一致性 Hash 算法
-
直接寻址法
优点:效率肯定是最高的
缺点:浪费空间,没办法处理重复数据
-
除留余数法
使用取模的方法,以一定的效率从而达到减少空间使用的目的
-
开放寻址法
-
拉链法
在 Java 当中最经典的实现就是 HashMap
Hash 算法应用场景
-
请求的负载均衡
Nginx 的 ip_hash 策略
-
分布式存储
分库分表,集群中的数据 ID
普通 Hash 算法存在的问题
在空间发生变化的时候,会导致大部分的 Hash 值重新计算。
一致性 Hash 算法
一致性 Hash 算法的范围是 0 - 2 ^ 32 -1 的圆。计算每个请求 Hash 值顺时针方向最近的服务器,需要注意转一圈的情况。
存在的问题:数据(请求倾斜问题)
解决方案:虚拟节点。添加一些虚拟节点,每个虚拟节点映射一个真实节点,相当于一层路由。
Nginx 配置一致性 Hash 负载均衡策略
upstream login {
consistent_hash $request_uri;
}
集群时钟同步问题
不同的场景使用不同的方案。
- 服务器全都可以连接互联网
- 部分服务器可以连接互联网或都不可以连接互联网
第一种情况,如果都可以连接互联网,那么所有的服务器都与同一个时间服务器同步即可。
# 使用 ntpdate 网络时间同步命令
ntpdate -u ntp.api.bz # 从一个时间服务器同步时间
可以使用定时任务,间隔一定时间,同步一次服务器时间。
第二种情况,如果部分服务器可以连接互联网,或者是全部都不能够连接互联网,那么,只需要选择一台服务器当作时间服务器即可,其他的服务器都与这台服务器进行时间同步。
配置为时间服务器(修改 /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
分布式 ID 解决方案
-
UUID
UUID 是指 Universally Unique Identifier,翻译为中⽂是通⽤唯⼀识别码 产⽣重复 UUID 并造成错误的情况⾮常低,是故⼤可不必考虑此问题。
-
独⽴数据库的⾃增 ID
使用一张表记录 ID,每一次先像表中添加一条记录,然后通过数据库
LAST_INSERT_ID()
方法获取添加记录的 ID -
雪花 ID
通过 SnowFlake 雪花算法生成 ID。
雪花算法是 Twitter 推出的⼀个⽤于⽣成分布式 ID 的策略。 雪花算法是⼀个算法,基于这个算法可以⽣成 ID,⽣成的 ID 是⼀个
long
型,那么在 Java 中⼀个long
型是8个字节,算下来是 64bit,如下是使⽤雪花算法⽣成的⼀个 ID 的⼆进制形式示意:
另外,⼀切互联⽹公司也基于上述的⽅案封装了⼀些分布式ID⽣成器,⽐如滴滴的 tinyid
(基于数 据库实现)、百度的 uidgenerator
(基于 SnowFlake)和美团的 leaf
(基于数据库和 SnowFlake) 等
- 借助 Redis 的
Incr
命令获取全局唯⼀ ID
分布式调度
在分布式环境下的定时任务调度。
Elastic-job 当当网开源的分布式调度框架。
Session 共享问题
因为在集群环境下,有可能存在同一个 Session(用户) 每一次请求访问不同的服务器,但是有些信息,又不希望反复操作。
- 通过相同 IP 每次访问相同服务器的方案(Nginx 的 IP_Hash 策略)
优点:配置简单,不入侵应用(不需要额外修改代码)
缺点:服务器重启 Session 丢失,存在单点负载高的风险,单点故障问题。 - 多服务器间进行 Session 同步
Tomcat 可以通过组播机制实现 Session 同步
优点:不入侵应用,便于服务器水平扩展,使用各种负载均衡策略,服务器重启或者宕机不会造成 Session 丢失。
缺点:性能低,内存消耗打,有延迟。 - Session 集中存储
使用缓存中间件对 Session 数据进行缓存。
优点:适应各种负载均衡策略,服务器重启或宕机不会造成Session 丢失,扩展能力强,适合大集群数量使用。
缺点:对应用又入侵,需要引入相关代码。