一、⼀致性Hash算法
Hash
算法应⽤场景
Hash算法在很多分布式集群产品中都有应⽤,⽐如分布式集群架构Redis
、
Hadoop
、
ElasticSearch
,Mysql分库分表,
Nginx
负载均衡等
主要的应⽤场景归纳起来两个
① 请求的负载均衡(⽐如nginx的ip_hash
策略)
Nginx的IP_hash策略可以在客户端ip
不变的情况下,将其发出的请求始终路由到同⼀个⽬标服务 器上,实现会话粘滞,避免处理session
共享问题
如果没有IP_hash策略,那么如何实现会话粘滞?
可以维护⼀张映射表,存储客户端IP或者sessionid与具体⽬标服务器的映射关系 <ip,tomcat1>
缺点
1)那么,在客户端很多的情况下,映射表⾮常⼤,浪费内存空间
2)客户端上下线,⽬标服务器上下线,都会导致重新维护映射表,映射表维护成本很⼤如果使⽤哈希算法,事情就简单很多,我们可以对ip
地址或者
sessionid
进⾏计算哈希值,哈希值与服务器数量进⾏取模运算,得到的值就是当前请求应该被路由到的服务器编号,如此,同⼀个客户端ip
发送过来的请求就可以路由到同⼀个⽬标服务器,实现会话粘滞。
②分布式存储
以分布式内存数据库Redis为例,集群中有
redis1
,
redis2
,
redis3
三台
Redis
服务器 那么,
在进⾏数据存储时
,<key1,value1>
数据存储到哪个服务器当中呢?针对
key
进⾏
hash
处理
hash(key1)%3=index,
使⽤余数
index
锁定存储的具体服务器节点
普通
Hash
算法存在的问题
普通
Hash
算法存在⼀个问题,以
ip_hash
为例,假定下载⽤户
ip固定没有发⽣改变,现在有tomcat出现 了问题,宕
机了,服务器数量由
3
个变为了
2
个,之前所有的求模都需要重新计算。
如果在真实⽣产情况下,后台服务器很多台,客户端也有很多,那么影响是很⼤的,缩容和扩容都会存 在这样的问题,⼤量⽤户的请求会被路由到其他的⽬标服务器处理,⽤户在原来服务器中的会话都会丢失。
Nginx
配置⼀致性
Hash
负载均衡策略
ngx_http_upstream_consistent_hash 模块是⼀个负载均衡器,使⽤⼀个内部⼀致性hash
算法来选择 合适的后端节点。
该模块可以根据配置参数采取不同的⽅式将请求均匀映射到后端机器,
consistent_hash $remote_addr:可以根据客户端ip
映射
consistent_hash $request_uri:根据客户端请求的uri
映射
consistent_hash $args:根据客户端携带的参数进⾏映
二、集群时钟同步问题
时钟不同步导致的问题:数据混乱
集群时钟同步配置
集群时钟同步思路
分布式集群中各个服务器节点都可以连接互联⽹
操作⽅式
ntpdate -u ntp.api.bz
分布式集群中某⼀个服务器节点可以访问互联⽹或者所有节点都不能够访问互联⽹
操作⽅式:
1)选取集群中的⼀个服务器节点
A(172.17.0.17)
作为时间服务器(整个集群时间从这台服务
器同步,如果这台服务器能够访问互联⽹,可以让这台服务器和⽹络时间保持同步,如果不能就⼿动设置⼀个时间)
⾸先设置好A的时间
把A配置为时间服务器(修改/etc/ntp.conf⽂件)
集群中其他节点就可以从A服务器同步时间了
ntpdate 172.17.0.17
三、分布式ID
解决⽅案
为什么需要分布式
ID(
分布式集群环境下的全局唯⼀
ID)
① UUID
UUID 是指Universally Unique Identififier,翻译为中⽂是通⽤唯⼀识别码 产⽣重复 UUID 并造成错误的情况⾮常低,是故⼤可不必考虑此问题。 Java中得到⼀个UUID,可以使⽤java.util包提供的⽅法
②独⽴数据库的⾃增ID
MySQL:select LAST_INSERT_ID();
③SnowFlake 雪花算法
雪花算法是Twitter推出的⼀个⽤于⽣成分布式ID的策略。
④借助Redis的Incr命令获取全局唯⼀ID
Redis Incr 命令将 key
中储存的数字值增⼀。如果
key
不存在,那么
key
的值会先被初始化为
0 ,然后再执⾏ INCR
操作。
修改解压⽬录中的配置⽂件
redis.conf
,关掉保护模式
在src
⽬录下执⾏
./redis-server ../redis.conf
启动redis服务
Java代码中使⽤Jedis客户端调⽤Reids的incr命令获得⼀个全局的id
引⼊jedis客户端jar
Java代码(此处我们就是连接单节点,也不使⽤连接池)
四、分布式调度问题
定时任务的场景
定时任务形式:每隔⼀定时间/特定某⼀时刻执⾏
例如:
订单审核、出库
订单超时⾃动取消、⽀付退款
礼券同步、⽣成、发放作业
物流信息推送、抓取作业、退换货处理作业
数据积压监控、⽇志监控、服务可⽤性探测作业
定时备份数据
⾦融系统每天的定时结算
数据归档、清理作业
报表、离线数据分析作业
什么是分布式调度
1)运⾏在分布式集群环境下的调度任务(同⼀个定时任务程序部署多份,只应该有⼀个定时任务在执⾏)
2)分布式调度—>
定时任务的分布式
—>
定时任务的拆分(即为把⼀个⼤的作业任务拆分为多个⼩的作业任务,同时执⾏)
定时任务与消息队列的区别
共同点
异步处理
⽐如注册、下单事件
应⽤解耦
不管定时任务作业还是MQ都可以作为两个应⽤之间的⻮轮实现应⽤解耦,这个⻮轮可以中转 数据,当然单体服务不需要考虑这些,服务拆分的时候往往都会考虑
流量削峰
双⼗⼀的时候,任务作业和MQ都可以⽤来扛流量,后端系统根据服务能⼒定时处理订单或者 从MQ
抓取订单抓取到⼀个订单到来事件的话触发处理,对于前端⽤户来说看到的结果是已经 下单成功了,下单是不受任何影响的
本质不同
定时任务作业是时间驱动,⽽MQ是事件驱动;
时间驱动是不可代替的,⽐如⾦融系统每⽇的利息结算,不是说利息来⼀条(利息到来事件)就算⼀下,⽽往往是通过定时任务批量计算;所以,定时任务作业更倾向于批处理,MQ
倾向于逐条处理;
定时任务的实现⽅式
引⼊jar
定时任务作业主调度程序
定义⼀个job,需实现Job接⼝
分布式调度框架Elastic-Job
Elastic-Job是当当⽹开源的⼀个分布式调度解决⽅案,基于Quartz
⼆次开发的,由两个相互独⽴的⼦项⽬Elastic-Job-Lite
和
Elastic-Job-Cloud
组成。我们要学习的是
Elastic-Job-Lite
,它定位为轻量级⽆中⼼ 化解决⽅案,使⽤Jar
包的形式提供分布式任务的协调服务,⽽
Elastic-Job-Cloud
⼦项⽬需要结合
Mesos以及Docker
在云环境下使⽤。
Elastic-Job的
github
地址:
https://github.com/elasticjob
主要功能介绍
分布式调度协调
在分布式环境中,任务能够按指定的调度策略执⾏,并且能够避免同⼀任务多实例重复执⾏
丰富的调度策略 基于成熟的定时任务作业框架
Quartz cron
表达式执⾏定时任务
弹性扩容缩容 当集群中增加某⼀个实例,它应当也能够被选举并执⾏任务;当集群减少⼀个实例 时,它所执⾏的任务能被转移到别的实例来执⾏。
失效转移 某实例在任务执⾏失败后,会被转移到其他实例执⾏
错过执⾏作业重触发 若因某种原因导致作业错过执⾏,⾃动记录错过执⾏的作业,并在上次作业
完成后⾃动触发。
⽀持并⾏调度 ⽀持任务分⽚,任务分⽚是指将⼀个任务分为多个⼩任务项在多个实例同时执⾏。
作业分⽚⼀致性 当任务被分⽚后,保证同⼀分⽚在分布式环境中仅⼀个执⾏实例。
Elastic-Job-Lite
应⽤
jar
包(
API
)
+
安装
zk
软件
Elastic-Job依赖于Zookeeper
进⾏分布式协调,所以需要安装
Zookeeper
软件(
3.4.6
版本以上),关于 Zookeeper,此处我们不做详解,在阶段三会有深度学习,我们此处需要明⽩
Zookeeper
的本质功能: 存储+
通知。
Elastic-Job-Lite
轻量级去中⼼化的特点
任务分⽚
五、Session共享(⼀致性)问题
Session问题原因分析
场景:nginx默认轮询策略
Nginx的 IP_Hash 策略
同⼀个客户端IP的请求都会被路由到同⼀个⽬标服务器,也叫做会话粘滞
优点:配置简单,不⼊侵应⽤,不需要额外修改代码
缺点:服务器重启Session丢失,存在单点负载⾼的⻛险,单点故障问题
Session复制
也即,多个tomcat之间通过修改配置⽂件,达到Session之间的复制
优点:
不⼊侵应⽤
便于服务器⽔平扩展
能适应各种负载均衡策略
服务器重启或者宕机不会造成Session丢失
缺点:
性能低
内存消耗
不能存储太多数据,否则数据越多越影响性能
延迟性
Session共享,Session集中存储
Session的本质就是缓存,那Session数据为什么不交给专业的缓存中间件呢?⽐如Redis
优点:
能适应各种负载均衡策略
服务器重启或者宕机不会造成Session丢失
扩展能⼒强
适合⼤集群数量使⽤
缺点:
对应⽤有⼊侵,引⼊了和Redis的交互代码
使用方式
1)引⼊
Jar
2
)配置
redis
3
)添加注解
原理示意