• HTTP请求回调IM系统LB,确保服务定向调用


    1. 背景介绍

    基于websocket的及时通信中,客户端与服务端建立ws连接后,服务端将业务继续传递到下一级业务服务系统Business server后,下一级服务系统处理完毕后,要将结果反馈给客户端,而此时的客户端ws服务器存在多个实例时,处理方式上存在几种策略:

    1) 比较常见的是基于ip哈希;

    2)基于参数的hash;

    这些,一般情况下可以满足业务需求,但是呢,在ws服务动态增减的时候,可能就会出现消息丢失。例如:当前有3台websocket的tomcat服务器,有一个ws连接建立在tomcat1上面,基于轮询的模式下,且websocket前端采用了心跳机制时,客户端的重连机制会让这个客户端连接转而连接到其他两个tomcat当中之一,例如tomcat2,而客户是无感知的, 请参照websocket连接的后台反向代理问题。若这个时候Business server回调及时通信系统IM后(HTTP),不做特别处理,在轮询的方式下(或者hash方式),会出现消息去往的websocket的tomcat服务器不是这个回复消息该去往的tomcat服务器。导致回复消息无法到达该客户的websocket连接通道上,从而出现消息丢失的问题。

    如上图所示:客户请求如红色线条,起初,经过LB-》nginx1-》websocket server1-》other business server. 但是处理过程中,websocket server1宕机了,或者其他什么原因,不能对外服务了,客户端的心跳机制,使得websocket重连,连到了websocket server2上了。此时,other business server处理完了客户的请求,回调IM系统,投递客户请求的答案,有可能出现上图绿色的箭头所示,这个时候,该客户的消息是没有办法投递出去的,因为websocket的长连接是在客户端和websocket server2.

    即使还有一种,就是基于redis的订阅发布,进行消息回传给ws服务器,这种做法,要增加redis服务器的压力,且可能存在多次发布操作,性能不好,放弃。

    这里要介绍的是,基于http的接口调用,通过url后面带上query信息,指定ws所在的服务器的ip和port信息。然后在nginx上做特殊配置,实现消息回传时,指定调用ws服务器集群中的服务器,因为这个服务器上存在websocket的连接实例。

    nginx的配置如下:

    upstream ims_svr {
         server 10.130.215.143:8080;
         server 10.130.215.144:8080;
    }
    
    #用于BI回调IMS系统定位消息具体去往那个tomcat服务,涉及websocket的连接要原路来还要原路回去
    upstream 10.130.215.1438080 {
         server 10.130.215.143:8080;
    }
    upstream 10.130.215.1448080 {
         server 10.130.215.144:8080;
    }
    
    server {
        listen       80;
        server_name  localhost;
    
        #charset koi8-r;
    
        #access_log  logs/host.access.log  main;
        default_type text/html;
    
        location / {
            root   html;
            index  index.html index.htm;
        }
    
        location /IMS {
            proxy_pass http://ims_svr;
            proxy_set_header Host $host:$server_port;
            proxy_set_header Remote_Addr $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    
        location ~ /IMS/(replyMessage|callback) {
            proxy_pass http://$arg_ip$arg_port;
            proxy_set_header Host $host:$server_port;
            proxy_set_header Remote_Addr $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

    上面的配置中,技巧就在于获取query中的ip字段和port字段的值,拼接在一起构成upstream的block名称。在proxy_pass的代理下,就可以去往特定服务器,即连接有websocket连接的那个tomcat上。

    注意这里你可能会说,websocket server同样会出现宕机啊,在other Business server回调的时候,对的。我们可以在other Business server和websocket server之间搭建redis服务器,作为信息中心节点,通过visistorId+sessionid作为redis的key,ip_port值作为这个key对应的键值,当other Business server回调IM前,获取一下这个visistorId在当前sessionid下的websocket建立在那个websocket server上,即获取IP和Port信息。在回调的HTTP接口的URL部分附着query信息,例如?ip=1.1.1.1&port=8080.

    如上图所示的案例,客户请求经过LB-》nginx1-》websocket server1-》other business server-》LB-》nginx2-》websocket server1-》resp去往客户端(基于websocket长连接),因为HTTP请求,在LB上是基于轮询的,所以,HTTP回调的response信息,也可能是经过nginx1的,这个时候,基于我们的nginx配置规则,依然会使得resp反馈去往websocket server1上,保障resp响应一定是在websocket连接建立的通道上回复给客户端,确保resp消息不会丢失。

    测试案例截图:

    到此,整个方案介绍完毕,是不是觉得nginx很厉害?的确,nginx现在的web应用领域占有率非常高。

    另外,这里要注意一个小细节:就是nginx获取query部分的变量时,$arg_<xxx>这里的xxx部分,不要出现下划线“_”了,否则会导致query部分的变量获取不到,我经历过这个血的教训

    例如我开始的配置如下:

    upstream ims_svr {
         server 10.130.215.143:8080;
         server 10.130.215.144:8080;
    }
    
    #用于BI回调IMS系统定位消息具体去往那个tomcat服务,涉及websocket的连接要原路来还要原路回去
    upstream 10.130.215.143_8080 {
         server 10.130.215.143:8080;
    }
    upstream 10.130.215.144_8080 {
         server 10.130.215.144:8080;
    }
    
    server {
        listen       80;
        server_name  localhost;
    
        #charset koi8-r;
    
        #access_log  logs/host.access.log  main;
        default_type text/html;
    
        location / {
            root   html;
            index  index.html index.htm;
        }
    
        location /IMS {
            proxy_pass http://ims_svr;
            proxy_set_header Host $host:$server_port;
            proxy_set_header Remote_Addr $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    
        location ~ /IMS/(replyMessage|callback) {
            proxy_pass http://$arg_ip_$arg_port;
            proxy_set_header Host $host:$server_port;
            proxy_set_header Remote_Addr $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

    测试过程中,nginx后台报错如下:

    access.log

    10.130.207.217 - - [23/Mar/2018:13:03:28 +0800] "POST /IMS/replyMessage?ip=10.130.215.143&port=8080 HTTP/1.1" 502 541 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"

    error.log

    2018/03/23 13:03:28 [error] 2358#0: *253758 no resolver defined to resolve 8080, client: 10.130.207.217, server: localhost, request: "POST /IMS/replyMessage?ip=10.130.215.143&port=8080 HTTP/1.1", host: "10.130.207.217"

    这里显然是$arg_ip_$arg_port值没有计算对。根本原因是$arg_ip_搞错了

    切记,切记nginx的query的arg取值规则。

  • 相关阅读:
    rm
    Linux下解包/打包,压缩/解压命令
    虚拟机安装---vm12+ubuntukylin16.04
    mysql-5.6.41-winx64安装
    tensorflow学习笔记一------下载安装,配置环境(基于ubuntu16.04 pycharm)
    大一上学期C语言学习心得总结
    常见HTTP状态码
    Java语言基础及java核心
    linux下安装JMeter(小白教程)
    Linux下安装JDK(小白教程)
  • 原文地址:https://www.cnblogs.com/shihuc/p/8633246.html
Copyright © 2020-2023  润新知