负载均衡器 - 一致性哈希算法
单台服务器受限于硬件资源,其性能是有上限的,当单台服务器不能满足应用场景的并发需求量时,就需要考虑部署多个服务器共同处理客户端的并发请求,但是客户端怎么知道去连接具体哪台服务器呢?此时就需要一台负载均衡器,通过预设的负载算法,指导客户端连接服务器。
负载均衡器有基于客户端的负载均衡和服务器的负载均衡。
普通的基于哈希的负载算法,并不能满足负载均衡所要求的单调性和平衡性,但一致性哈希算法非常好的保持了这两种特性,所以经常用在需要设计负载算法的应用场景当中。
nginx配置tcp负载均衡
在服务器快速集群环境搭建中,都迫切需要一个能拿来即用的负载均衡器,nginx在1.9版本之前,只支持http协议web服务器的负载均衡,从1.9版本开始以后,nginx开始支持tcp的长连接负载均衡,但是nginx默认并没有编译tcp负载均衡模块,编写它时,需要加入–with-stream参数来激活这个模块。
nginx编译加入–with-stream参数激活tcp负载均衡模块
联系我获取 nginx-1.12.2.tar.gz
拖到linux上执行
tar -zxvf nginx-1.12.2.tar.gz
cd nginx-1.12.2
nginx编译安装需要先安装pcre、openssl、zlib等库,也可以直接编译执行下面的configure命令,根据错误提示信息,安装相应缺少的库。
sudo su进入root用户执行
./configure --with-stream
执行
make && make install
编译完成后,默认安装在了/usr/local/nginx目录
cd /usr/local/nginx/
可执行文件在sbin目录里面,配置文件在conf目录里面
nginx -s reload 重新加载配置文件启动
nginx -s stop 停止nginx服务
nginx配置tcp负载均衡
主要在conf目录里面配置nginx.conf文件,配置如下:
#nginx tcp loadbalance config
stream {
upstream MyServer{
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;
#proxy_timeout 3s;
listen 8000;
proxy_pass MyServer;
tcp_nodelay on;
}
}
配置完成后,./nginx -s reload平滑重启。
我们写在http的上面
listen 8000;这个是nginx会监听的一个端口号,也就是说,所有的客户端连接指定的8000端口就可以,所有客户端发过来的请求在配置文件中,人家就写好了,你都连8000,客户端发的请求如果都在8000端口上,nginx感应到,你要我完成反向代理的操作,也就是负载均衡的操作,nginx就按照既定的负载均衡算法把这些请求分发到不同的服务器上。
proxy pass MyServer 相当于一个标记。
所有连接到8000端口的请求都连接到这个MyServer的信息里面负载均衡。
MyServer的这个upstream就是负载均衡模块,包含了几台机器呢?
包含了2台:127.0.0.1:6000,127.0.0.1.6002,相当于起了2台服务器,一个运行在6000端口,一个运行在6002端口。
weight=1,就是权重,这2个服务器的权重都是1,就是说按照轮询算法,轮着往配置的服务器发,转着圈发送,
配置强的服务器,我们可以给它配置的权重大一些。
max_fails是在完成心跳机制,连续超过3次心跳失败,就认为服务器挂掉,fail_timeout,等心跳30秒。
如果要添加新的服务器,我们只需要在下面新增这台服务器的信息就可以了。
proxy_timeout 3s;是指nginx只和后端的chatserver连接3秒就断开,我们不加这个了。
proxy_connect_timeout的意思是nginx得连接后台的server服务器,第一次连接的时候发现超过1秒的时间还没有握手成功就判定连接失败了
tcp_nodelay on就是配置TCP的参数
listen 8000是让客户端都往8000端口发送数据,8000端口可以给你负载均衡,往MyServer负载均衡配置里面进行负载均衡
hash remote addr是另外一种基于哈希的负载算法,要单独安装插件
启动nginx
如果要停止nginx,不能发kill 进程ID号,因为nginx有进程容错机制,当提供服务的进程挂掉了,会自动重启,是kill不完的。执行s
-s stop关闭他。
打开客户端测试验证
我们先修改一下server的main.cpp
#include "chatserver.hpp"
#include "chatservice.hpp"
#include <iostream>
#include <signal.h>
using namespace std;
//处理服务器ctrl+c结束后,重置user的状态信息
void resetHandler(int)
{
ChatService::instance()->reset();
exit(0);
}
int main(int argc, char **argv)
{
if (argc < 3)
{
cerr << "command invalid! example: ./ChatServer 127.0.0.1 6000" << endl;
exit(-1);
}
//解析通过命令行参数传递的ip和port
char *ip = argv[1];
uint16_t port = atoi(argv[2]);
signal(SIGINT, resetHandler);
EventLoop loop;
InetAddress addr(ip, port);
ChatServer server(&loop, addr, "ChatServer");
server.start();
loop.loop();
return 0;
}
编译成功
我们启动两台服务器
我们启动1台客户端
我们启动第二台客户端
我们客户端的请求先发的nginx,nginx根据配置既定的负载均衡算法,把第一个请求转到第一台服务器,根据权重相等,轮询,下一个客户端连接到第二台服务器。