集群聊天服务器项目(三)——负载均衡模块与跨服务器聊天

news2024/11/15 11:56:18

负载均衡模块

为什么要加入负载均衡模块

原因是:单台服务器并发量最多两三万,不够大。

负载均衡器 Nginx的用处或意义**(面试题)**

  • 把client请求按负载算法分发到具体业务服务器Chatserver
  • 能和ChatServer保持心跳机制,检测ChatServer保持心跳机制,检测ChatServer故障
  • 能发现新添加的ChatServer设备方便服务器扩展数量

客户端和某台服务器可建立IP隧道

想要更大并发量可以对负载均衡器再做集群

负载均衡模块在整个程序中的位置如下图

在这里插入图片描述

如何配置nginx的TCP负载均衡模块

首先解压nginx的安装包 (tar zxvf);

进入nginx安装包中编译加入--with-stream参数激活tcp负载均衡模块

~/package/nginx-1.12.2# ./configure --with-stream
~/package/nginx-1.12.2# make && make install

编译完成后,默认安装在 /usr/local/nginx

$ cd /usr/local/nginx/
/usr/local/nginx$ ls

可执行文件在sbin目录里面,配置文件在conf目录里面。

nginx -s reload #重新加载配置文件启动
nginx -s stop #停止nginx服务

nginx.conf的补充内容如下

events {
    worker_connections  1024; #最大连接数1024,默认为512
}
#-------------------------------添加的内容------------------------

stream {
      upstream MyServer {
          # max_fails最大失败次数,若超过则判断连接失败
          # fail_timeout,发出心跳包超过改时间没收到回包就算一次失败
          server 127.0.0.1:6000 weight=1 max_fails=3 fail_timeout=30s;
          server 127.0.0.1:6002 weight=1 max_fails=3 fail_timeout=30s;
      }
  
      server {      
          proxy_connect_timeout 1s;
          listen 8000;
          proxy_pass MyServer; # 所有连接到8000端口的请求都往MyServer指定的主机里负载均衡
          tcp_nodelay on;
      }
  }
#---------------------------------------------------------------

其中 weight表示权重

上面配置也就是说,客户端连接服务器时端口号填8000就是连接到负载均衡器上,它会帮助我们把请求分发到 127.0.0.1:6000127.0.0.1:6002端口上.

配置修改后可用 ./nginx -s reload平滑重启。

注意:这么修改了之后,客户端连接服务端的地址都要为127.0.0.1:8000,也就是连接到负载均衡器上而不是确定的服务器端口上。

sudo netstat -anp查看nginx进程是否启动在80端口监听

在这里插入图片描述

服务器通过负载均衡器按权重分别接收一个连接

在这里插入图片描述

redis发布订阅消息队列

背景

当客户端登录到不同的服务器时,应该如何解决跨服务器通信问题?

假如采用两两服务器之间建立连接

在这里插入图片描述

上图设计相当于在服务器网络之间进行广播。这样的设计使得各个服务器之间耦合度太高,不利于系统扩展,并且会占用系统大量的socket资源,各服务器之间的带宽压力很大,不能够节省资源给更多的客户端提供服务,因此绝对不是一个好的设计。
集群部署的服务器之间进行通信,最好的方式就是引入中间件消息队列解耦各个服务器,使整个系统松耦合,提高服务器的响应能力,节省服务器的带宽资源,如下图所示:

在这里插入图片描述

集群分布式环境中,经常使用的中间件消息队列ActiveMQRabbitMQKafka等,都是应用场景广泛并且性能很好的消息队列,供集群服务器之间,分布式服务之间进行消息通信。

发布订阅是观察者模式的使用场景。

消息队列是长连接跨服务器聊天通用方法,工作流程大致如下

客户端c1在某个服务器上连接后,要把该连接在redis队列上订阅一个通道ch1

别的客户端c2在不同的服务器上登录要给c1发消息,会直接发到redis队列上的通道ch1,客户端c1可接受到信息发布到通道ch1

要开一个单独线程进行监听通道上的事件,有消息给业务层上报。

当服务器发现发送的对象id没有在自己的_userConnMap上,就要往消息队列上publish,消息队列就会把消息发布给订阅者。

redis服务器后台运行输入如下指令

redis-server --daemonize yes

发布订阅功能要开两条redis连接即两个redisContext *,一条用于订阅和接收消息,一条用于发布消息,这么做的原因是因为订阅 SUBSCRIBE时会进入阻塞状态,代码如下

// 向redis指定通道channel发布消息
bool Redis::publish(int channel, string message)
{
    redisReply *reply = (redisReply *)redisCommand(_publish_context, "PUBLISH %d %s", channel, message);
    if (nullptr == reply)
    {
        cerr << "publish command failed!" << endl;
        return false;
    }
    freeReplyObject(reply);
    return true;
}

// 向redis指定通道subscribe订阅消息
bool Redis::subscribe(int channel)
{
    // SUBSCRIBE命令本身会造成线程阻塞等待通道里发生消息,这里只做订阅通道,不接受通道消息
    // 通道消息接收专门在 observer_channel_message 函数中的独立线程中进行
    // 只负责发送命令,不阻塞接收redis server响应消息,否则和notifyMsg线程抢占响应资源
    if (REDIS_ERR == redisAppendCommand(this->_subscribe_context, "SUBSCRIBE %d", channel))
    {
        cerr << "subscribe command failed!" << endl;
        return false;
    }
    // redisBufferWrite可循环发送缓冲区累积的命令,知道缓冲区数据发送完毕(done被置1)
    int done = 0;
    while (!done)
    {
        if (REDIS_ERR == redisBufferWrite(this->_subscribe_context, &done))
        {
            cerr << "subscribe command failed!" << endl;
            return false;
        }
    }
    return true;
}

本项目使用hiredis进行redis编程,加入redis的发布订阅消息队列后,业务层的改动大致如下:

  • chatservice构造中连接redis即调用connect,并设置上报消息的回调,connect中会开启一条新线程调用 observer_channel_message函数进行循环接收订阅通道上的消息,有消息到来给业务层上报。
  • 登录时订阅subscribe channel
  • 聊天时遇到用户在别的服务器上登录(userid不在map中,但状态为online)就publish
  • 注销就取消订阅 unsubscribe channel

杂项

  • 若不满意Nginx负载均衡效果前面可加LVS(Linux Virtual Server)

  • 负载均衡器 - 一致性哈希算法学有余力可了解

  • IP隧道

    IP隧道(IP Tunnel)是一种虚拟的网络连接方式,它允许将一个IP数据包传输到另一个IP网络中,同时保留原始数据包的源和目的地址。它通常用于将两个不同的IP网络连接起来,使它们看起来像一个单一的网络。IP隧道的主要目的是为了解决网络互联问题,特别是当两个不兼容的网络需要进行通信时。

    在IP隧道中,数据包被封装在另一个IP数据包中,以便在一个网络上传输到另一个网络。这个封装过程称为“隧道ing”,隧道的两端点被称为“入口”和“出口”。入口点将原始IP数据包封装在另一个IP数据包中,将其发送到出口点。出口点接收到封装后的数据包,然后解封装出原始的IP数据包,并将其传送到目的地。

    IP隧道的优点是它可以让不同的网络连接起来,同时保持原有的网络拓扑结构和地址分配。但是,它也会带来一些缺点,例如会增加网络延迟和降低网络性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/440659.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习实战5-天气预测系列:利用数据集可视化分析数据,并预测某个城市的天气情况

大家好&#xff0c;我是微学AI&#xff0c;最近天气真的是多变啊&#xff0c;忽冷忽热&#xff0c;今天再次给大家带来天气的话题&#xff0c;机器学习实战5-天气预测系列&#xff0c;我们将探讨一个城市的气象数据集&#xff0c;并利用机器学习来预测该城市的天气状况。该数据…

迈入Java,一文告诉你学习Java的原因

前言 Java是一种流行的编程语言&#xff0c;由Sun Microsystems于1995年首次发布。自那时以来&#xff0c;Java已成为全球最广泛使用的编程语言之一。Java具有许多优点&#xff0c;包括跨平台、面向对象和安全性等&#xff0c;使其成为开发企业软件、Web应用程序和移动应用程序…

Consul TTL健康检查方式

consul比较常用的健康检查方式为http健康检查方式&#xff0c;也还有使用TTL方式来进行健康检查的&#xff0c;下面从spring-cloud-consul-discovery这个SDK来着手分析。 构建ConsulAutoRegistration&#xff0c;这里的工作是组成服务注册的报文&#xff0c;有一个setCheck方法…

【应急响应】战中溯源反制对抗上线CSGoby蚁剑Sqlmap等安全工具

文章目录 溯源反制-Webshell工具-Antsword正常情况下&#xff0c;PHP后门上线发现PHP后门&#xff0c;修改webshell进行反制 溯源反制-SQL注入工具-SQLMAP溯源反制-漏洞扫描工具-Goby&Awvs溯源反制-远程控制工具-CobaltStrike1、伪造流量批量上线&#xff08;欺骗防御&…

(IPC)进程间通信的常用的两种方式——管道、共享内存

前言&#xff1a; 众所周知&#xff0c;不同的进程之间&#xff0c;在正常情况下&#xff0c;由于其拥有独立的PCB、上下文等原因&#xff0c;每个进程都是独立且互不干扰&#xff0c;这不仅保证了进程的安全&#xff0c;也降低了OS对于进程的管理成本。 但是通常情况下&…

第04讲:实战掌握 Byte Buddy,体验代码生成的顺畅

为什么需要运行时代码生成 我们知道&#xff0c;Java 是一种强类型的编程语言&#xff0c;即要求所有变量和对象都有一个确定的类型&#xff0c;如果在赋值操作中出现类型不兼容的情况&#xff0c;就会抛出异常。强类型检查在大多数情况下是可行的&#xff0c;然而在某些特殊场…

猴子分桃与反转部分单链表

目录 一、编程题 1.猴子分桃 2.反转部分单向链表 二、选择题 1.如果希望监听 TCO 端口 9000&#xff0c;服务器端应该怎样创建 socket&#xff1f; 2. jre 判断程序是否执行结束的标准是&#xff08; &#xff09; 一、编程题 1.猴子分桃 链接&#xff1a;猴子分桃__…

C# 平台调用过程

(1&#xff09;调用LoadLibrary加载非托管DLL到内存中,并调用GetProcAddress 获得内存中非托管函数的指针。 (2) 为包含非托管函数地址的托管签名生成一个DllImport存根&#xff08;stub)。 (3) 压入被调用方保存的寄存器。 (4&#xff09;创建一个DllImport帧&#xff08;fr…

Node.js—http模块

目录 1、HTTP 协议1.1 概念1.2 请求报文的组成1.3 HTTP 的请求行1.4 HTTP 请求头1.5 HTTP 的请求体1.6 响应报文的组成 2、创建 HTTP 服务2.1 操作步骤2.2 测试2.3 注意事项 3、获取 HTTP 请求报文3.1 请求方法 request.method3.2 请求版本 request.httpVersion3.3 请求路径 re…

shell 初级

判断当前磁盘剩余空间是否有20G&#xff0c;如果小于20G&#xff0c;则将报警邮件发送给管理员&#xff0c;每天检查一次磁盘剩余空间。 [rootlocalhost ~]# bash c.sh c.sh: line 7: echo剩余内存:1GB,小于20GB 判断web服务是否运行&#xff08;1、查看进程的方式判断该程序是…

ctfshow_愚人杯WEB之easy_flask

1、easy_flask 百度了下什么是flask&#xff0c;flask是一款非常流行的python web框架。 2、尝试步骤 &#xff08;1&#xff09;、搜索博文&#xff0c;查看该题是如何破解的 先注册账号&#xff0c;登录自己注册的账号&#xff0c;查看可访问内容&#xff08;可以查看到部…

深入探讨Linux驱动开发:字符设备驱动开发与测试

文章目录 一、字符设备驱动介绍1.设备驱动介绍 二、设备号1.设备号介绍2.分配与释放设备编号①dev_t类型②静态分配设备号③动态分配设备号④释放主次设备号⑤手动创建设备节点⑥自动创建设备节点⑦删除设备节点 三、字符设备注册1.cdev结构体2.注册cdev到内核 三、字符设备驱动…

黑马点评实战篇问题总结

缓存穿透 用户查询的数据在缓存和数据库中都不存在 这样的请求每次都会打到数据库上 解决方案&#xff1a; 1.缓存空字符串&#xff08;额外的内存消耗&#xff0c;可能造成短期的不一致&#xff09; 2.布隆过滤&#xff08;内存占用少&#xff0c;没有多余key&#xff0c;实现…

访问若依vue版后端api接口

访问若依vue版后端api接口 如何使用Talend API Tester进行访问若依vue-前后端分离版的后端api接口&#xff1f; 方法一&#xff1a; 写好一个后台api接口&#xff0c;启动项目 直接使用Talend API Tester进行访问后台api出现如下错误&#xff0c;原因是因为若依系统有jwt认证…

2023软件测试工程师涨薪攻略,3年如何达到30K?

1.软件测试如何实现涨薪 首先涨薪并不是从8000涨到9000这种涨薪&#xff0c;而是从8000涨到15K加到25K的涨薪。基本上三年之内就可以实现。 如果我们只是普通的有应届毕业生或者是普通本科那我们就只能从小公司开始慢慢往上走。 有些同学想去做测试&#xff0c;是希望能够日…

数据可视化的web工具 apache-superset

文章目录 简介安装window10Ubuntu1804CentOS8 配置连接数据库创建仪表板创建图表图表加入仪表板时间序列折线图 简介 Superset是一款由Airbnb开源的、目前由Apache孵化的&#xff0c;基于Flask-appbuilder搭建的“现代化的企业级BI&#xff08;商业智能&#xff09;Web应用程序…

很合适新手入门使用的Python游戏开发包pygame实例教程-02[如何控制飞行]

前面一篇博文&#xff0c;我们让飞机动起来了&#xff0c;但不是那么完美&#xff0c;我们继续来完善我们的游戏代码&#xff0c;本篇博文主要介绍获取按键的方式已经飞行的控制。 文章目录 一、获取按键的三种方式1、通过event.get配合pygame.key枚举2、通过event.get配合ord…

C++入门教程||C++ 文件和流||C++ 异常处理

C 文件和流 C 文件和流 到目前为止&#xff0c;我们已经使用了 iostream 标准库&#xff0c;它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。 本教程介绍如何从文件读取流和向文件写入流。这就需要用到 C 中另一个标准库 fstream&#xff0c;它定义…

《我的第一本算法书》读书笔记

《我的第一本算法书》读书笔记 作者&#xff1a;宫崎修一 石田保辉 ◆ 1-3 数组 在链表和数组中&#xff0c;数据都是线性地排成一列。在链表中访问数据较为复杂&#xff0c;添加和删除数据较为简单&#xff1b;而在数组中访问数据比较简单&#xff0c;添加和删除数据却比较复…

转行IT,怎么选专业?

转行IT&#xff0c;怎么选专业&#xff1f; 知己知彼&#xff0c;百战不殆 先清楚你自身的基础情况&#xff1a;学历、年龄、是否有基础、学习能力如何、自律性、时间管理能力、有没有生活压力、有没有家要养、车贷、房贷…… 思考的问题越现实&#xff0c;对你的帮助越大 选…