----------------------------------总结-------------------------------------------
1. 分布式基础知识点:
(1)一致性哈希和哈希取模算法的区别:
哈希取模算法:即hash(服务器A的IP地址) % 服务器的数量,常用在nginx的IP哈希取模算法,数据库的分库分表策略里;
一致性哈希:即hash(服务器A的IP地址) % 2^32,可以想象成一个圆了,常用在服务层dubbo负载均衡算法、缓存分片算法
注:http://www.zsythink.net/archives/1182
(2)一致性哈希:jedis采用一致性哈希算法路由redis服务器的流程是
a. 求出redis服务器的哈希值,将其配置到0-2^32的圆上;
b. 采用相同方法求出待存储的Key的哈希值,并映射到相同的圆上;
c. 从数据映射到的位置开始顺时针查找,找到的第一台服务器就是数据保存的位置;
d. 如果顺时针寻找过程中超过2^32仍然找不到节点,则保存到最开始的第一台服务器上;
(4)架构演进过程:
单体应用架构SSH -> 垂直应用架构(RESTful) -> SOA(Dubbo) -> 微服务(SpringCloud)
RPC:即让调用远程服务和调用本地服务一样,底层是基于socket进行通信;
(5)区别:双机热备(一主一备)、双机互备(互为主备)、双机双工(集群)
双机热备:主+备=一套业务跑在两套机器上(配置最好一样),两机用心跳线相连,备机监控主机,当主机出现问题,备机接管业务。主机成为备机。优点:总有一套机器备用,保证系统运行。缺点:浪费一套机器。
双机互备:主(备)+备(主),主备机上都跑应用,应用不通互为备份,出问题时,所有应用转在一套机器上。优点:双机皆跑应用,不浪费机器。缺点:双机压力可能互不相同,当全转到一套机器上时,该机的承受能力很是问题。如配置过高又造成浪费。
双机双工:主+备,跑的业务相同,系统前端进行业务负载均衡,通过平均分配把业务分散到多台机器上,而机器配置相应不至较高。当出现问题时可由前端负载均衡调整业务处理流量。
详见:https://blog.csdn.net/herry2008/article/details/1916258
(6)服务化好处:
解耦后进行分而治之提高安全性和并发性、提高代码复用性、屏蔽底层复杂度、调用方便
1. 路由策略:
应用层:nginx-轮询、加权轮询、IP值哈希等
服务层:dubbo-轮询、随机、一致性哈希、leastactive等
消息队列:kafka-生产者按照指定分区策略、默认的随机均衡策略等发送消息到分区;
缓存客户端:redic-哈希取模策略,jedis-一致性哈希
数据层:常用的有取模策略、分区策略等;
注:如果后端有缓存,则最好应用层选ip哈希、服务层一致性哈希、缓存哈希策略都可;
2. 存储或持久方式:??
zookeeper:分层文件系统目录树结构,事务日志和快照文件;
redis: RDB和AOF
kafka:文件结构,所以存储量很大;
3. 服务降级场景和分类:
http://jinnianshilongnian.iteye.com/blog/2306477 --- 开涛 聊聊高并发系统之降级特技
4. 分布式锁:可通过zookeeper、redis或数据库等方式实现:详见《可伸缩服务架构-李艳鹏》6.2.3
a. 数据库:
利用数据库的唯一索引来实现,插入数据成功表示获得锁;
b. Redis:
利用setnx命令和expire命令设key的超时时间;
失效时间我设置多长时间为好?如何设置的失效时间太短,方法没等执行完,锁就自动释放了,那么就会产生并发问题。如果设置的时间太长,其他获取锁的线程就可能要平白的多等一段时间。对于这个问题目前主流的做法是每获得一个锁时,只设置一个很短的超时时间,同时起一个线程在每次快要到超时时间时去刷新锁的超时时间。在释放锁的同时结束这个线程。如redis官方的分布式锁组件redisson,就是用的这种方案。
优点:性能好;
缺点是:存在锁无法释放问题、单点问题,另外不可重入问题、非阻塞问题、非公平问题都需要引入专门机制处理,实现较复杂;
c. Zookeeper:
排它锁:通过createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的distribute_lock 节点就释放出锁。
共享锁:即不同事务可同时读,而更新操作必须在当前没有任何事务进行读写操作情况下进行;/distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序节点(/shared_lock/host1-R/W-序号),获取/shared_lock子节点列表,判断当前是否是写请求,如果是读请求,则判断当前目录下有没有比自己序号小的写节点,如果没有则获得锁,如果有则监听改写节点;如果当前是写请求,判断是否序号最小和监听比自己小的节点来实现;
公平锁:在lock目录下,A要获取锁则建立临时顺序节点,然后判断是否是最小节点,如是则获取成功,退出后自动删除;B要获取锁同样流程,如果不是最小节点,则设置监听比自己值小的节点;
优点:有效的解决锁无法释放的问题、不可重入问题、非公平问题、单点问题、非阻塞问题;
缺点:性能较缓存低,每次在创建锁和释放锁的过程中,需要动态创建、销毁临时节点来实现锁功能。ZK中创建和删除节点只能通过Leader服务器来执行,然后将数据同不到所有的Follower机器上。
d. 分布式锁应用场景:
分布式定时任务(保证同一时刻只有一个集群定时任务在执行)、分布式缓存中修改变量;
其他:
https://blog.csdn.net/u010963948/article/details/79006572 分布式锁的几种使用方式(redis、zookeeper、数据库) 好!!!
https://blog.csdn.net/xlgen157387/article/details/79036337 分布式锁简单入门以及三种实现方式介绍
https://www.zhihu.com/question/62598701 redis和zookeeper有什么联系吗?
5. 分布式ID
(0)要求:
a. 全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。
b. 粗略有序:如果在分布式环境中做到完全有序,需要用到锁等,考虑到性能,采用粗略有序,具体分为秒级有序和毫秒级有序;
c. 可反解:即生成ID服务提供反解方法,这样在存储时就能以十进制存储,省下传统timestamp类字段的占用空间了;
d. 可伸缩:中心发布模式时可进行集群部署,这样在生成ID里就必须包含机器ID;
(b. 趋势递增:在MySQL InnoDB引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。
(c. 单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求)
d. 信息安全:如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,会需要ID无规则、不规则。
上述123对应三类不同的场景,3和4需求还是互斥的,无法使用同一个方案满足。
(1) 方案总结:
生成全局唯一ID方案:引入全局ID生成服务、通过时间戳、依靠特定算法生成UUID等3种方案;
(2) 方案一:UUID:
简介:共128位,3部分生成:当前日期和时间+时钟序列+全局唯一机器识别号如网卡MAC地址;UUID标准型式包含32个16进制数字,分为五段,形式为8-4-4-4-12的36个字符,示例:550e8400-e29b-41d4-a716-446655440000,到目前为止业界一共有5种方式生成UUID;
优点:性能非常高,本地生成,没有网络消耗;
缺点:--太长不易于存储,32字符16个字节128位; --不具备有序性,会导致在写入B+树索引的时候有过多的随机操作(连续的ID会产生部分顺序写),另外,由于在写入时不能产生有顺讯的append操作,而需要进行insert操作,将读取整个B+数节点到内存,在插入记录完成后将整个节点写回磁盘,这种操作在记录占用空间比较大的情况下性能下降明显;
参考:https://blog.csdn.net/xinghuo0007/article/details/72868799 -- UUID生成方法
(3) 方案二:基于数据库实现
简介:设置不同初始值和相同增长步长来实现,即4个数据库,初始值为,0,1,2,3,步长为4;
缺点:--水平扩展较难;--对数据库压力较大,每获取一次都会读写一次数据库; --只有趋势递增,没有单调递增;
(4) 方案三:类snowflake方案---好!!
简介:共64位,3部分组成:0位不用+41位时间戳+10位workerID+12位自增序列;其中:10位机器ID,可手动配置,或通过zookeeper创建持久顺序节点后取回顺序号当做自己的workerId; 41位时间戳:以某一时间为基准,当前时间减去该时间生成,40位毫秒级可支撑34年,41位可支撑68年) ,最后生成的是十进制数,如3279458774233907200
优点:--不依赖第三方,性能都很高; --可以根据自身特性分配bit位,非常灵活;--毫秒为在高位,自增序列低位,整个ID是趋势递增;
缺点:强依赖时钟,如果机器时钟回拨,会导致发号重复;每毫秒自增序列归0问题;
改进方案:leaf-snowflake方案:即对snowflake强依赖的时钟问题,进行了处理;通过间隔3秒上报时钟到zookeeper,并判断是否小于上次上报的时间来判断是否有过大幅回拨,如果是新加入节点,则访问其他节点时间并计算平均值进行对比;失败则抛异常并不提供服务或报警;
参见:https://tech.meituan.com/MT_Leaf.html 美团点评分布式ID生成系统 -- 好!!
参见:《可伸缩服务架构:框架与中间件》李彦鹏----设计一款永不重复的高性能ID发号器 --- 好!!!
(9) Mycat提供的全局主键方式如下:
1. 本地文件方式:使用服务器本地磁盘文件的方式;2. 数据库方式:使用数据库的方式;3. 本地时间戳方式:使用时间戳方式;4. 分布式zookeeper生成ID
详见:https://www.linuxba.com/archives/8002#22 Mycat全局主键
问题 |
可行性 |
|
基于redis |
单点问题,redis重启问题等 |
较高,公司有项目使用 |
给予DB(每次生成多个使用时去取出来) |
单点问题,并发量问题 |
低并发,数据量较小的可以使用 |
UUID |
暂用存储空间比较大,非可排序的,体现不出增长的趋势 |
较高 |
twitter snowflake |
Xx年以后可能存在重复问题,需要配置生产参数 |
高,分布式的没单点故障问题,时间上是递增的。推荐 |
基于DB步长的方式 |
不是所有数据库都支持 |
低 |
6.服务发布方式:
(1)嵌入式发布模式:即提供一个本地Jar包;
(2)中心服务器发布模式:客户端调用服务器;
(3)REST发布模式:中心服务器通过RestfulAPI导出服务,供非java客户端调用;
7. 分布式session一致性
session同步法:多台web-server相互同步数据
客户端存储法:一个用户只存储自己的数据
反向代理hash一致性:四层hash和七层hash都可以做,保证一个用户的请求落在一台web-server上
后端统一存储:web-server重启和扩容,session也不会丢失
8. 大量定时任务如何高效触发?
https://mp.weixin.qq.com/s/mvFwjgxliwx808Hn_9ruEA 10w定时任务,如何高效触发超时 好!!!
http://blog.51cto.com/wenshengzhu/2106623 环形队列高效触发大量超时任务的算法实现