• 【Nginx】Nginx双机热备



    目前所接触的项目还不涉及到分布式,都是单机模式。不过好在至今没出过什么大问题,基本能满足客户的需求。

    由于数据量不是很大,单机的性能已经可以满足,按理不应该做加法,毕竟部署的越复杂,维护起来就越麻烦。

    性能虽然可以满足,但有一个不得不提的痛点:项目无法随时更新。

    目前的解决方式是:白天改bug、测试,等到晚上客户不使用系统时才停机维护,效率相对较低。

    有没有可能让项目可以随时更新?
    答案肯定是有,相对简单的解决方案是:双机热备(应用双活) 。

    什么是双机热备?
    这里引用一下百度百科的解释。

    双机热备是应用于服务器的一种解决方案,其构造思想是主机和从机通过TCP/IP网络连接,正常情况下主机处于工作状态,从机处于监视状态,一旦从机发现主机异常,从机将会在很短的时间之内代替主机,完全实现主机的功能。

    就是同时部署两套系统,一主一备。主节点负责对外提供服务,备用节点默认不提供服务,只有在主节点出问题的情况下,备用节点才顶替主节点,继续对外提供服务。
    大哥不行了,二弟替一会儿。
    可以解决什么问题?
    利用这个思路,是否可以实现同时部署AB两套系统,当系统需要更新维护时,停用A服务,B服务顶替A工作。待A服务更新完毕后,A服务启动提供升级后的服务,B服务停用再更新。实现应用的热插拔?
    答案当然也是可以的。
    纸上得来终觉浅,绝知此事要躬行。
    本人写了个小demo亲测!
    实现思路
    搭建项目前先简单理一下思路。
    要做的分为以下几步:
    1、启动两套简单的Web服务
    2、服务内就两个简单的方法

    保存值到Session
    从Session取值

    3、Nginx配置负载均衡,PC01主,PC02备
    3、保存Session到PC01服务,然后停用PC01
    4、从PC02服务取值,看PC02能否正常工作并访问Session
    如果服务可以无缝切换,Session也都正常则表示成功。
    项目环境

    两套SpringBoot服务(双活)
    Redis(实现Session共享)
    Nginx(负载均衡-主备模式) (也可使用KeepAlived)

    为什么需要Redis?
    使用多套系统无法避开的一个问题就是Session,再也不能像以前单机模式下直接从request中getSession了,Session是保存在服务器的,多个服务器之间无法共享Session。关于共享Session有很多实现方案,这里采用的是Redis。
    搭建步骤

    1、先简单看一下前端

    由于只讲环境搭建,所以项目竟可能的简单。
    只有两个功能,保存值到Session和从Session中取值。
    javascript复制代码const PATH = ‘/backend/’;

    //保存到Session
    function saveSession() {
        const personName = $('#personName').val();
        if (personName.length <= 0) {
            alert('请输入再保存');
            return;
        }
        $.ajax({
            type:'post',
            url: PATH+"test/save",
            async:false,
            xhrFields: {
                withCredentials: true
            },
            crossDomain: true,
            data: {
                personName:personName
            },
            success: function(json) {
                $('#screen').text(json);
            }
        });
    }
    
    //查询Session
    function requestServer() {
        $.ajax({
            type:'post',
            url: PATH+"test/query",
            async:false,
            xhrFields: {
                withCredentials: true
            },
            crossDomain: true,
            success: function(json) {
                $('#screen').text(json);
            }
        });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    2、再看一下后端服务

    很简单的一个服务,就两个方法:保存值到session、从session中取值
    只从request中获取SessionId作为Key,数据作为Value保存到Redis。

    @RestController
    @RequestMapping("/test")
    public class TestController {
    	private static final String SERVER = "PC01";
    
    	@Autowired
    	private RedisUtil redisUtil;
    
    	@RequestMapping("/save")
    	public Object save(String personName, HttpServletRequest request, HttpServletResponse response) {
    		String sessionId = request.getRequestedSessionId();
    		if (redisUtil.set(sessionId, personName)) {
    			return SERVER+",Session保存成功";
    		}
    		return "Session保存失败";
    	}
    
    	@RequestMapping("/query")
    	public Object query(HttpServletRequest request) {
    		String sessionId = request.getRequestedSessionId();
    		Object personName = redisUtil.get(sessionId);
    		if (personName != null) {
    			return "Hello," + personName+",我是"+SERVER;
    		}
    		return "Session为空";
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    项目会编译两个jar包,同时部署。
    PC01对应8081端口,PC02对应8082端口。

    3、Nginx配置负载均衡

    #主备模式,backup只有在主节点故障时才提供服务
    upstream backend {  
       server 127.0.0.1:8081;  
       server 127.0.0.1:8082 backup;  
    }
    server {
        listen       81;
        server_name  localhost;
         location /{
    		#前端
            root www/back; 
         } 
         location /backend{
            #反向代理到80818082
            proxy_pass http://backend;
         } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    到这一步环境就算搭建完成了。

    4、测试

    现在虽然PC01和PC02都是启动的,但是只有PC01对外提供服务。
    我们将‘小潘’保存到Session,然后查询。

    可以看到,我们现在访问的是PC01服务,且Session也保存成功了。
    接下来,我们停用PC01服务。
    ruby复制代码[root@localhost test]# lsof -i:8081
    COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
    java 71972 root 13u IPv6 88606 0t0 TCP *:tproxy (LISTEN)
    [root@localhost test]# kill -9 71972

    强制杀掉进程,项目会不会因此而挂掉呢?
    再次请求查询Session

    可以看到,项目并没有挂掉。不仅如此,而且Session也能正常访问,PC02迅速顶替了PC01的位置,继续对外提供服务。
    接下来,就可以对PC01进行维护更新了,更新好了直接启用,PC02又会退居幕后,等待下一次复出。
    整个过程对于用户而言是无缝的。
    利用双机热备,不仅可以实现项目的随时更新,而且还实现了高可用。即使PC01意外宕机,PC02也会迅速接替,不至于整个项目瘫痪。
    至此,全部结束。

    尾巴

    白天写写代码,晚上有空研究研究技术,写写博客记录总结,三省吾身。不仅巩固知识点,而且也锻炼组织语言的能力。
    岁月无声无息地溜走,除了带走一些人的无聊时光,还能沉淀一个努力者的人生。
    一次美妙的旅程…

  • 相关阅读:
    从零手写实现 nginx-25-directive map 条件判断指令
    TienChin 渠道管理-渠道搜索
    基于Python实现相机标定正畸并生成鸟瞰图
    Flet教程之 09 NavigationRail 基础入门(教程含源码)
    Hive参数与性能调优-V2.0
    Leetcode—226.翻转二叉树【简单】
    string类型可以作为lock的锁对象吗
    C#语法基础
    IO多路转接 ——— select、poll、epoll
    【数据挖掘-思考】分类和聚类
  • 原文地址:https://blog.csdn.net/u011397981/article/details/133778247