三分钟深入TT猫之故障转移

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
简介:

结束了一周繁忙的工作,趁着周末,小编手中的键盘早已饥渴难耐了,想知道上期省略号中发生了什么有趣的故事么?且听小编娓娓道来,结尾有彩蛋。

1

风月前场

春风再续,书接上回,春香园的老鸨妈妈,给这位血气方刚的骚年挑选了一位佳人A,于是乎骚年兴致勃勃的进入了闺房,宜言饮酒,与子同欢,琴瑟在御,莫不静好,谁知佳人A突然来月事了(这个事先老鸨是不知道的)

我了个擦,春宵一刻值千金啊,赶召唤系老鸨儿,老鸨先是把A从侍客名单中剔除,随后赶紧给这位骚年换了一位佳人B,歌管楼台声细细,秋千院落夜沉沉,哈哈哈,又是一个难忘的夜晚......

2

梦回现实

哎,少年,醒醒,别做梦了,快起来搬砖了

3

其实在实际生产中,我们的负载均衡器可能要更加温柔体贴智能,不能让用户有一丝感觉到服务器也来大姨妈。

  • 还记得我们的TT猫,下单失败的场景么?被强行跳转到登陆页。
  • 还记得双十一妹子那幽怨的小眼神么?可能你已在偷偷乐了。
  • 还记得程序员小明瞎白活了一顿原理么?其实可能他自己都没搞明白。

模拟老鸨

在讲如何体贴之前,先给大家传授几种老鸨经常使用的分配手法,为了让大家更加形象直观的了解老鸨的内心,小编决定带大家扒开来看,当然了鸨妈的内心也是一坨代码而已。

4

首先我们定义一个OldBird,接着安排四个smallBirds值班。

/**
 * 老鸨
 * 创建时间 2017年9月16日
 */
public class OldBird {
    // Key代表风尘X子,Value代表该风尘X子的受欢迎程度
    public static Map<String, Integer> smallBirds = new ConcurrentHashMap<String, Integer>();

    static {
        smallBirds.put("野鸡", 1);
        smallBirds.put("幺二", 2);
        smallBirds.put("长三", 3);
        smallBirds.put("书寓", 4);
    }
}

开张了,开张了,显然第一位客人并没有入的了鸨儿的法眼,随机了一个后继续嗑她的瓜子。

/**
 * 随机 
 * 创建时间 2017年9月16日
 */
public class Random {
    public static String getServer() {
        // 获取值班名单
        Set<String> keySet = ServerMap.servers.keySet();
        ArrayList<String> keyList = new ArrayList<String>();
        keyList.addAll(keySet);
        // 老鸨看人办事 精打细算了一下、随即了一个
        java.util.Random random = new java.util.Random();
        int randomPos = random.nextInt(keyList.size());
        // 程序员小明获取了一个smallBird
        return keyList.get(randomPos);
    }
}

可能是鸨妈的随机有点看心情,导致后院有些人有点不高兴了,于是乎赶紧采取了另一种策略。

/**
 * 轮询 
 * 创建时间 2017年9月16日
 */
public class RoundRobin {
    private static Integer pos = 0;

    public static String getServer() {
        //获取今日值班名单
        Set<String> keySet = ServerMap.servers.keySet();
        ArrayList<String> keyList = new ArrayList<String>();
        keyList.addAll(keySet);
        //有些人 活太少 可能会不高兴 还是排号来吧
        String server = null;
        synchronized (pos) {
            if (pos >= keySet.size())
                pos = 0;
            server = keyList.get(pos);
            pos++;
        }
        // 程序员小明获取了一个smallBird
        return server;
    }
}

这时候大茶壶急急忙忙的赶到老鸨身边,哎,别嗑了,韦爷点名要书寓,赶紧给安排安排,老鸨一想常客啊,不行,我得好好编排一下,省的老被打扰。

/**
 * 源地址哈希
 * 创建时间    2017年9月16日
 */
public class Hash {
    public static String getServer()      
    {      
        //获取今日值班名单
        Set<String> keySet = ServerMap.servers.keySet();      
        ArrayList<String> keyList = new ArrayList<String>();      
        keyList.addAll(keySet);  
        //韦爷 悠哉的进来的 点名要书寓
        String remoteGuest = "韦爷";      
        //老鸨给韦爷 设置固定编号
        int hashCode = remoteGuest.hashCode();
        int serverListSize = keyList.size();
        int serverPos = hashCode % serverListSize;
        //韦爷获取到了指定服务
        return keyList.get(serverPos);      
    }      
}

读到最后,小伙伴们可能要问了,那个Map中的Value并没有起作用啊,让老鸨吃了么?其实,只是感觉用在这里不妥而已,有些事,你懂我懂大家都懂。

具体到生产架构中,应该是这个样子的

/**
 * 服务器负载均衡集群组 
 * 创建时间 2017年9月16日
 */
public class ServerMap {
    // Key代表服务器,Value代表该服务的权重
    public static Map<String, Integer> servers = new ConcurrentHashMap<String, Integer>();
    static {
        //这里有四个服务 权重分别是1234
        servers.put("1核1G-服务器", 1);
        servers.put("2核2G-服务器", 2);
        servers.put("3核3G-服务器", 3);
        servers.put("4核4G-服务器", 4);
    }
}

能者多劳,权重视服务器的性能而定,下面的算法,服务器4每次有百分之四十的几率被获取到。

/**
 * 加权轮询
 * 创建时间    2017年9月16日
 */
public class WeightRoundRobin {
    private static Integer pos = 0;   

    public static String getServer()   
    {   
        //取得服务器List   
        Set<String> keySet = ServerMap.servers.keySet();   
        Iterator<String> iterator = keySet.iterator();   
        //计算权重总数 累加 比如 4核4G-服务器  权重为4 上述10个服务器中存在4个4核4G-服务器服务  增加随机或者轮询几率
        List<String> serverList = new ArrayList<String>();   
        while (iterator.hasNext())   
        {   
            String server = iterator.next();   
            int weight = ServerMap.servers.get(server);   
            for (int i = 0; i < weight; i++)   
                serverList.add(server);   
        }   

        String server = null;   
        synchronized (pos)   
        {   
            if (pos >= keySet.size())   
                pos = 0;   
            server = serverList.get(pos);   
            pos ++;   
        }   

        return server;   
    }  
}

说了这么多,以上只是几种简单的负载均衡算法,在 记一次JavaWeb网站技术架构总结 中有提到十种负载均衡策略以及其优缺点,有兴趣的同学可以一看。

会话机制

各位看官莫急,要想弄明白故障转移是怎么回事,必须要弄明白客户端-服务端的会话认证机制。

由于HTTP协议本身是无状态的,这与HTTP协议本来的目的是相符的,那么小马哥是怎么知道那些用户买了那些东西的呢?

以Tomcat为例,大家都知道session是在服务器端创建并存储到容器的JVM内存中的,浏览器初次访问服务器会生成一个叫JSESSIONID的cookie,浏览器的每次请求都会附带这个cookie,服务端通过JSESSIONID会找到内存中对应的状态信息。

程序员小明,打开TT猫,输入自己的账号密码,附带cookie信息请求到了后台,TT猫后台校验成功以后,会把用户信息保存到JSESSIONID对应的内存中,这样小明和TT猫就可以无障碍的深入交流了。

这个过程也可以用以下示意图来描述:

5

如果你觉得会话机制如此简单,那可就有点高看小编了,篇幅有限,对会话机制感兴趣的同学只能自行查阅资料了。

故障转移

老鸨之所以能快速安抚骚年使其顺利度过这缠绵之夜,有没有感受到老鸨强大的人工智能气息?

6

其实我们的负载均衡器Nginx,也是做的相当智能的,如果后端节点服务器宕掉的话,Nginx通过自带的模块可以把这台坏掉的服务踢出upstream负载集群组,然后自动切换到健康节点来提供访问。

有过开发经验的小伙伴,都知道服务分有状态和无状态。

  • 无状态服务(Stateless Service):游客浏览商品、搜索商品等等这种不需要鉴权的操作。
  • 有状态服务(Stateful Service): 添加购物车,下单,支付等等需要用户认证的操作。

对于这种无状态的服务请求,不管集群组使用任何负载均衡算法(随机、轮询、hash),只要有一个存活,小马哥的TT猫就可以提供正常服务。

但是对于支付这种需要用户认证的操作,不得不说,我们要选择合适的负载均衡算法。

服务独自存储用户状态

  • 随机、轮询算法,小明可能一辈子都无法登陆TT猫
  • hash算法,单一服务宕掉的话会导致用户状态丢失

服务统一存储用户状态

架构设计之Spring-Session分布式集群会话管理

总结

7

秋名山上行人稀,常有框架较高低,如今原理依旧在,不见当年老框架。

底层原理可能你这辈子都不过时,解决问题的能力永远都不过时,积极向上的求知欲永远是你的强大后盾。

既定目标,做个有追求的程序员,如果你连算法数据结构都能搞得明白,网络传输都可以手到擒来,怎学不会简单的API调用?

塞内加在《论生命之短暂》中说过“如果一个人出海遇到狂风暴雨,被变换肆虐的风吹得团团转,你可能会觉得他航行了很远。其实航行得并不远,只是浮沉动荡的时间长而已”,没错如今的知识就像出海时遇到的狂风暴雨,我们只是被吹的原地团团转而已,并没有在知识的海洋航行很远。

https://blog.52itstyle.com/usr/uploads/2017/09/3701848136.gif) no-repeat 6px 50%;">最后,愿大家都不会被吹昏头脑,据说留言的程序员都找到女朋友了...
相关实践学习
小试牛刀,一键部署电商商城
SAE 仅需一键,极速部署一个微服务电商商城,体验 Serverless 带给您的全托管体验,一起来部署吧!
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
5天前
|
数据采集 自然语言处理 搜索推荐
基于Qwen3的Embedding和Rerank模型系列,开源!
近年来,随着大规模预训练语言模型(LLM)的飞速发展,文本嵌入(Embedding)和重排序(Reranking)技术在搜索引擎、问答系统、推荐系统等多个领域的重要性愈发凸显。
692 65
|
4天前
|
安全 JavaScript 前端开发
Typora免费下载,不需要激活,Typora早期版本,Markdown编辑器
Typora是一款支持实时预览的Markdown编辑器,跨平台兼容Windows、macOS和Linux,适合写作、笔记和技术文档。本文提供合法安全的Typora早期免费版安装方案及常见问题解决方法,助你快速上手。同时详细介绍了Markdown基础用法,包括标题、加粗、斜体、列表、链接、图片、引用、代码块和表格等常用语法,帮助用户高效编写结构化内容。
929 13
|
4天前
|
云安全 人工智能 安全
|
4天前
|
人工智能 前端开发 Devops
通义灵码带你玩转开发者常用的MCP(合辑,持续更新中)
今天我们精选了与开发者息息相关和比较热门的MCP 服务,总结了这些技术服务在实际开发的最佳实践,涵盖了从前端开发、后端开发、DevOps、测试、运维等关键环节,及非研发领域中的热度较高的MCP服务。我们通过直播、图文等形式带你了解和学习!
589 3
|
6天前
|
存储 前端开发 JavaScript
2025 最新前端 100 道经典面试题及详细答案汇总整理
本文整理了100道前端常见面试题及其详细答案,涵盖HTML、CSS、JavaScript等多个领域,助你系统复习前端知识。内容包括HTML5新特性、CSS盒模型、Flex与Grid布局区别、选择器优先级等核心知识点,以及伪类和伪元素的区别等细节。适合准备面试或巩固基础的开发者学习。资源可从文末链接下载。
461 1
|
15天前
|
人工智能 API 开发者
一文带你 "看见" MCP 的过程,彻底理解 MCP 的概念
本文介绍了模型上下文协议(MCP)的基本概念、工作原理及其应用过程。MCP 是一种连接 AI 助手与数据系统的开放标准,旨在帮助大模型生成更高质量的响应。文章从 RAG 和 Function Calling 的理论基础出发,详细解析了 MCP 的核心组件(主机、客户端、服务器)及优势,并通过 ModelScope 和 Cherry Studio 实例展示其操作流程。同时,文中指出了 MCP 存在的手动配置复杂、工具稳定性不足等问题,但也强调其作为过渡协议的重要性,为未来智能体间的协同和工具使用提供了方向。
1583 56
一文带你 "看见" MCP 的过程,彻底理解 MCP 的概念
|
8天前
|
人工智能 Java 决策智能
Spring AI Alibaba Graph:多智能体框架实践
Spring AI Alibaba 是一个面向 Java 开发者的开源人工智能框架,旨在简化 AI 应用开发。本文重点介绍其 Graph 组件,用于解决工作流与多智能体协作问题。Graph 组件通过声明式编程接口,提供统一的上下文管理、消息记忆、人工确认节点等功能,支持复杂 AI 应用的构建。
|
8天前
|
人工智能 安全 测试技术
信条:阿里云AI攻防安全启示录
解读AI时代下的安全攻防新态势
1109 11