分布式和集群
文章目录
分布式:
- 把一个系统拆分为多个子系统,每个子系统负责各自的那部分功能,独立部署,各司其职
集群:
- 多个实例共同工作,最简单/最常见的集群是把一个应用复制多份部署
区别:- 分布式一定是集群,但集群不一定是分布式
- 因为集群就是多个实例一起工作,分布式将一个系统拆分之后,那就是多个实例;
- 集群并不一定是分布式,因为复制型的集群不是拆分而是复制
1. 一致性算法
Hash算法,比如在安全加密领域MD5、SHA等加密算法,在数据存储和查找方面有Hash表等,都用到了Hash算法
Hash算法应用场景:
- 请求负载均衡(比如nginx的ip_hash策略)
- 分布式存储
- MySQL分库分表
普通Hash算法的问题
- 以ip_hash为例,假定用户的ip固定没有改变,服务端的tomcat集群,有一台机器出现了问题,服务器数量减少,之前的hash算法结果会有所影响。而且可能影响的面非常大(可能多半的客户端都需要重新计算,也就是重新登录)
- 因此,在集群缩容和扩容的时候,会造成大量的用户会话丢失。
- 我们虽然不能完全处理这种情况,但是我们可以通过一致性hash算法将受影响的客户端数量减到最少
一致性Hash算法
- 将客户端和服务器端节点都映射到上图所示的hash环中,每个服务器端只处理其右侧的客户端请求。这样在缩容和扩容的时候受影响的节点数量将大大减少。
- 如果出现了,服务器数量少,请求倾斜的情况,可以使用虚拟节点机制,给实际的服务器多虚拟出来几个节点,虚拟出来的节点越多,这种情况越能得到充分解决。
在nginx中使用一致性Hash负载均衡策略
ngx_http_upstream_consistent_hash 模块是⼀个负载均衡器,使⽤⼀个内部⼀致性hash算法来选择合适的后端节点。
- 该模块可以根据配置参数采取不同的⽅式将请求均匀映射到后端机器,
- consistent_hash $remote_addr:可以根据客户端ip映射
- consistent_hash $request_uri:根据客户端请求的uri映射
- consistent_hash $args:根据客户端携带的参数进⾏映
- ngx_http_upstream_consistent_hash 模块是⼀个第三⽅模块,需要我们下载安装后使⽤
- github下载nginx⼀致性hash负载均衡模块 https://github.com/replay/ngx_http_consistent_hash
- 将下载的压缩包上传到nginx服务器,并解压
- 我们已经编译安装过nginx,此时进⼊当时nginx的源码⽬录,执⾏如下命令
./configure —add-module=/root/ngx_http_consistent_hash-master make make install
- Nginx就可以使⽤啦,在nginx.conf⽂件中配置
upstream lagouServer{ consistent_hash $request_uri; server 127.0.0.1:8080; server 127.0.0.1:8082; }
2. 集群时钟同步问题
集群是一个共同工作的系统,需要各个服务器的时间都是一致的。每个服务器的时间都需要是一样的。
否则,会造成数据混乱,如:a系统比b系统时间快,会造成实际上同时下单但是系统保存的下单时间不同的情况。
- 集群时钟同步思路
- 集群中各个节点都可以连接互联网
#使⽤ ntpdate ⽹络时间同步命令 ntpdate -u ntp.api.bz #从⼀个时间服务器同步时间
Linux也有定时任务, crond,可以使⽤linux的定时任务,每隔10分钟执⾏⼀次ntpdate命令
- 【集群中某一个服务器节点可以访问互联网】或【集群中所有的服务器都不可以访问互联网】
- 选择一台服务器
A
节点作为时间服务器,尽量选择能够联网的机器作为时间服务器 - 把
A
配置成时间服务器(修改/etc/ntp.conf文件)1、如果有 restrict default ignore,注释掉它 2、添加如下⼏⾏内容 restrict 172.17.0.0 mask 255.255.255.0 nomodify notrap # 放开局域⽹同步功能,172.17.0.0是你的局域⽹⽹段 server 127.127.1.0 # local clock fudge 127.127.1.0 stratum 10 3、重启⽣效并配置ntpd服务开机⾃启动 service ntpd restart chkconfig ntpd on
- 集群中其他节点就可以从
A
服务器同步时间了ntpdate 172.17.0.17
- 选择一台服务器
3. 分布式ID解决方案
UUID
- UUID(Universally Unique Identifier),翻译中文为:通用唯一识别码
- 缺点:生成的编码无规律,不好识别
独立数据库的自增ID
- 在一个独立的数据库上创建一个表,使用程序给这个表插入数据后,使用
select LAST_INSERT_ID();
查询自增id- 缺点:独立数据库的自增ID能够使用的前提是,独立数据库的性能没有问题。
SnowFlake雪花算法
- 雪花算法是Twiter推出的一个用于生成分布式ID的策略,这个算法可以生成一个long型的ID,
借助Redis的Incr命令获取全局唯一ID
- Redis Incr命令将key中存储的数字值增加,如果没有那么key的值会被初始化为0,再执行INCR操作。
Jedis jedis = new Jedis("127.0.0.1",6379); try { long id = jedis.incr("id"); System.out.println("从redis中获取的分布式id为: " + id); } finally { if (null != jedis) { jedis.close(); } }
4. 分布式调度问题
定时任务与消息队列的区别
共同点
- 异步处理:注册和下单分步骤处理
- 应用解耦:通过定时任务或消息队列可以把单体应用拆分成多个应用
- 流量削峰:使用任务作业和MQ都可以抗流量
本质不同
- 定时任务是事件驱动,MQ是事件驱动,时间驱动时不可代替的,比如金融系统的利息结算。
- 定时任务作业更倾向于批处理,MQ倾向于逐条处理。
分布式调度框架Elastic-job(当当开源的基于Qrartz二次开发的框架)
Elastic-Job的github地址: https://github.com/elasticjob
主要功能:
分布式调度协调,基于Quartz cron表达式执行调度,弹性扩容缩容,失效移交,错过执行作业重触发,支持任务分片调度
- jar包(API)+安装zk软件
任务分片:
5. Session共享问题解决方案
Nginx的IP_Hash策略
同一个客户端IP的请求都会被路由到同一个目标服务器,也叫会话粘滞
优点:
- 配置简单,不⼊侵应⽤,不需要额外修改代码
缺点:
- 服务器重启Session丢失
- 存在单点负载⾼的⻛险
- 单点故障问题
Session 复制
多个tomcat之间通过修改配置⽂件,达到Session之间的复制
优点:
- 不⼊侵应⽤
- 便于服务器⽔平扩展
- 能适应各种负载均衡策略
- 服务器重启或者宕机不会造成Session丢失
缺点:- 性能低
- 内存消耗
- 不能存储太多数据,否则数据越多越影响性能延迟性
Session共享, Session集中存储
Session的本质就是缓存,那Session数据为什么不交给专业的缓存中间件呢?⽐如Redis
优点:
- 能适应各种负载均衡策略
- 服务器重启或者宕机不会造成Session丢失
- 扩展能⼒强
- 适合⼤集群数量使⽤
缺点:- 对应⽤有⼊侵,引⼊了和Redis的交互代码