第五周总结
这周老师将了 缓存 消息队列 负载均衡 分布式数据库
缓存: 最常用 最有效的提升性能的手段
缓存命中率是缓存的主要指标,有 3 个影响因素:key 集合大小、内存大小、TTL 生存时间
CDN 内容分发网络也是一种常用手段
memcached 分布式缓存 客户端的一致性 hash 算法用于路由选择
redis cluster 集群用作分布式缓存
缓存穿透
在高并发下,查询一个不存在的值时,缓存不会被命中,导致大量请求直接落到数据库上,如活动系统里面查询一个不存在的活动。
缓存击穿
在高并发下,对一个特定的值进行查询,但是这个时候缓存正好过期了,缓存没有命中,导致大量请求直接落到数据库上,如活动系统里面查询活动信息,但是在活动进行过程中活动缓存突然过期了。
缓存雪崩
在高并发下,大量的缓存 key 在同一时间失效,导致大量的请求落到数据库上,如活动系统里面同时进行着非常多的活动,但是在某个时间点所有的活动缓存全部过期。
常见解决方案
直接缓存 NULL 值
限流
缓存预热
分级缓存
缓存永远不过期
消息队列
消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题
实现高性能,高可用,可伸缩和最终一致性架构
使用较多的消息队列有 ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ
kafka与Rocketmq的区别
淘宝内部的交易系统使用了淘宝自主研发的 Notify 消息中间件,使用 Mysql 作为消息存储媒介,可完全水平扩容,为了进一步降低成本,我们认为存储部分可以进一步优化,2011 年初,Linkin 开源了 Kafka 这个优秀的消息中间件,淘宝中间件团队在对 Kafka 做过充分 Review 之后,Kafka 无限消息堆积,高效的持久化速度吸引了我们,但是同时发现这个消息系统主要定位于日志传输,对于使用在淘宝交易、订单、充值等场景下还有诸多特性不满足,为此我们重新用 Java 语言编写了 RocketMQ,定位于非日志的可靠消息传输(日志场景也 OK),目前 RocketMQ 在阿里集团被广泛应用在订单,交易,充值,流计算,消息推送,日志流式处理,binglog 分发等场景。
数据可靠性
RocketMQ 支持异步实时刷盘,同步刷盘,同步 Replication,异步 Replication
Kafka 使用异步刷盘方式,异步 Replication
总结:RocketMQ 的同步刷盘在单机可靠性上比 Kafka 更高,不会因为操作系统 Crash,导致数据丢失。 同时同步 Replication 也比 Kafka 异步 Replication 更可靠,数据完全无单点。另外 Kafka 的 Replication 以 topic 为单位,支持主机宕机,备机自动切换,但是这里有个问题,由于是异步 Replication,那么切换后会有数据丢失,同时 Leader 如果重启后,会与已经存在的 Leader 产生数据冲突。开源版本的 RocketMQ 不支持 Master 宕机,Slave 自动切换为 Master,阿里云版本的RocketMQ支持自动切换特性。
性能对比
RocketMQ 单机写入 TPS 单实例约 7 万条/秒,单机部署 3 个 Broker,可以跑到最高 12 万条/秒,消息大小 10 个字节
总结:Kafka 的 TPS 跑到单机百万,主要是由于 Producer 端将多个小消息合并,批量发向 Broker。
RocketMQ 为什么没有这么做?
Producer 通常使用 Java 语言,缓存过多消息,GC 是个很严重的问题
Producer 调用发送消息接口,消息未发送到 Broker,向业务返回成功,此时 Producer 宕机,会导致消息丢失,业务出错
Producer 通常为分布式系统,且每台机器都是多线程发送,我们认为线上的系统单个 Producer 每秒产生的数据量有限,不可能上万。
缓存的功能完全可以由上层业务完成。
单机支持的队列数
Kafka 单机超过 64 个队列/分区,Load 会发生明显的飙高现象,队列越多,load 越高,发送消息响应时间变长
RocketMQ 单机支持最高 5 万个队列,Load 不会发生明显变化
队列多有什么好处?
单机可以创建更多 Topic,因为每个 Topic 都是由一批队列组成
Consumer 的集群规模和队列数成正比,队列越多,Consumer 集群可以越大
消息投递实时性
Kafka 使用短轮询方式,实时性取决于轮询间隔时间
RocketMQ 使用长轮询,同 Push 方式实时性一致,消息的投递延时通常在几个毫秒。
消费失败重试
Kafka 消费失败不支持重试
RocketMQ 消费失败支持定时重试,每次重试间隔时间顺延
总结:例如充值类应用,当前时刻调用运营商网关,充值失败,可能是对方压力过多,稍后在调用就会成功,如支付宝到银行扣款也是类似需求。
这里的重试需要可靠的重试,即失败重试的消息不因为 Consumer 宕机导致丢失。
严格的消息顺序
Kafka 支持消息顺序,但是一台 Broker 宕机后,就会产生消息乱序
RocketMQ 支持严格的消息顺序,在顺序消息场景下,一台 Broker 宕机后,发送消息会失败,但是不会乱序
Mysql Binlog 分发需要严格的消息顺序
定时消息
Kafka 不支持定时消息
RocketMQ 支持两类定时消息开源版本 RocketMQ 仅支持定时 Level 阿里云 ONS 支持定时 Level,以及指定的毫秒级别的延时时间
分布式事务消息
Kafka 不支持分布式事务消息
阿里云 ONS 支持分布式定时消息,未来开源版本的 RocketMQ 也有计划支持分布式事务消息
消息查询
Kafka 不支持消息查询
RocketMQ 支持根据 Message Id 查询消息,也支持根据消息内容查询消息(发送消息时指定一个 Message Key,任意字符串,例如指定为订单 Id)
总结:消息查询对于定位消息丢失问题非常有帮助,例如某个订单处理失败,是消息没收到还是收到处理出错了。
消息回溯
Kafka 理论上可以按照 Offset 来回溯消息
RocketMQ 支持按照时间来回溯消息,精度毫秒,例如从一天之前的某时某分某秒开始重新消费消息
总结:典型业务场景如 consumer 做订单分析,但是由于程序逻辑或者依赖的系统发生故障等原因,导致今天消费的消息全部无效,需要重新从昨天零点开始消费,那么以时间为起点的消息重放功能对于业务非常有帮助。
消费并行度
Kafka 的消费并行度依赖 Topic 配置的分区数,如分区数为 10,那么最多 10 台机器来并行消费(每台机器只能开启一个线程),或者一台机器消费(10 个线程并行消费)。即消费并行度和分区数一致。
RocketMQ 消费并行度分两种情况
消息轨迹
Kafka 不支持消息轨迹
阿里云 ONS 支持消息轨迹
开发语言友好性
Kafka 采用 Scala 编写
RocketMQ 采用 Java 语言编写
Broker 端消息过滤
Kafka 不支持 Broker 端的消息过滤
RocketMQ 支持两种 Broker 端消息过滤方式根据 Message Tag 来过滤,相当于子 topic 概念向服务器上传一段 Java 代码,可以对消息做任意形式的过滤,甚至可以做 Message Body 的过滤拆分。
消息堆积能力
理论上 Kafka 要比 RocketMQ 的堆积能力更强,不过 RocketMQ 单机也可以支持亿级的消息堆积能力,我们认为这个堆积能力已经完全可以满足业务需求。
开源社区活跃度
Kafka 社区更新较慢
商业支持
Kafka 原开发团队成立新公司,目前暂没有相关产品看到
RocketMQ在阿里云上已经开放公测近半年,目前以云服务形式免费供大家商用,并向用户承诺99.99%的可靠性,同时彻底解决了用户自己搭建MQ产品的运维复杂性问题
成熟度
Kafka 在日志领域比较成熟
RocketMQ 在阿里集团内部有大量的应用在使用,每天都产生海量的消息,并且顺利支持了多次天猫双十一海量消息考验,是数据削峰填谷的利器。
负载均衡
常用的有 nginx 和 lvs
nginx 和 LVS 作对比的结果:
nginx 工作在网络的第 7 层,可以作为网页静态服务器,支持 Rewrite 重写规则;支持 GZIP 压缩,节省带宽;可以做缓存;可以针对 http 应用本身来做分流策略,静态分离,针对域名、目录结构等
相比之下 LVS 并不具备这样的功能,所以 nginx 单凭这点可以利用的场合就远多于 LVS 了;但 nginx 有用的这些功能使其可调整度要高于 LVS,所以经常要去触碰,人为出现问题的几率也就大
nginx 对网络的依赖较小,理论上只要 ping 得通,网页访问正常,nginx 就能连得通,nginx 同时还能区分内外网,如果是同时拥有内外网的节点,就相当于单机拥有了备份线路;LVS 就比较依赖于网络环境,目前来看服务器在同一网段内并且 LVS 使用 direct 方式分流,效果较能得到保证。另外注意,LVS 需要向托管商至少申请多于一个 ip 来做 visual ip
nginx 安装和配置比较简单,测试起来也很方便,因为它基本能把错误用日志打印出来。LVS 的安装和配置、测试就要花比较长的时间,因为同上所述,LVS 对网络依赖性比较大,很多时候不能配置成功都是因为网络问题而不是配置问题,出了问题要解决也相应的会麻烦的多
nginx 也同样能承受很高负载且稳定,但负载度和稳定度差 LVS 还有几个等级:nginx 处理所有流量所以受限于机器 IO 和配置;本身的 bug 也还是难以避免的;nginx 没有现成的双机热备方案,所以跑在单机上还是风险比较大,单机上的事情全都很难说
nginx 可以检测到服务器内部的故障(健康检查),比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点。目前 LVS 中 ldirectd 也能支持针对服务器内部的情况来监控,但 LVS 的原理使其不能重发请求。比如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,nginx 会把上传切到另一台服务器重新处理,而 LVS 就直接断掉了
适用业务场景
网站建设初期(每日 PV 小于 100 万),可以选用 Nigix 作为反向代理负载均衡,因为其配置简单,性能也能满足一般的业务场景。如果考虑到负载均衡器是有单点问题,可以采用 Nginx + Keepalived 避免负载均衡器自身的单点问题
网站并发达到一定程度之后,为了提高稳定性和转发效率,可以使用 LVS、毕竟 LVS 比 Nginx 要更稳定,转发效率也更高。不过维护 LVS 对维护人员的要求也会更高,投入成本也更大
分布式数据库
mysql 高可用架构
MMM 与 MHA 以及 MGR,高可用架构都有如下的共同点:
对主从复制集群中的 Master 节点进行监控
自动的对 Master 进行迁移,通过 VIP。
重新配置集群中的其它 slave 对新的 Master 进行同步
MMM
需要两个 Master,同一时间只有一个 Master 对外提供服务,可以说是主备模式。
image-20190402160607794
需要基础资源:
资源数量说明主 DB2 用于主备模式的主主复制从 DB0~N 台可以根据需要配置 N 台从服务器 IP 地址 2n+1N 为 MySQL 服务器的数量监控用户 1 用户监控数据库状态的 MySQL 用户(replication)代理用户 1 用于 MMM 代理端改变 read_only 状态
故障转移步骤:
Slave 服务器上的操作完成原主上已经复制的日志恢复使用 Change Master 命令配置新主
主服务器上操作设置 read_only 关闭迁移 VIP 到新主服务器
优点:
提供了读写 VIP 的配置,试读写请求都可以达到高可用
工具包相对比较完善,不需要额外的开发脚本
完成故障转移之后可以对 MySQL 集群进行高可用监控
缺点:
故障简单粗暴,容易丢失事务,建议采用半同步复制方式,减少失败的概率
目前 MMM 社区已经缺少维护,不支持基于 GTID 的复制
适用场景:
读写都需要高可用的
基于日志点的复制方式
MHA
image-20190402162734119
需要资源:
资源数量说明主 DB2 用于主备模式的主主复制从 DB2~N 台可以根据需要配置 N 台从服务器 IP 地址 n+2N 为 MySQL 服务器的数量监控用户 1 用户监控数据库状态的 MySQL 用户(replication)复制用户 1 用于配置 MySQL 复制的用户
MHA 采用的是从 slave 中选出 Master,故障转移:
从服务器:选举具有最新更新的 slave 尝试从宕机的 master 中保存二进制日志应用差异的中继日志到其它的 slave 应用从 master 保存的二进制日志提升选举的 slave 为 master 配置其它的 slave 向新的 master 同步
优点:
MHA 除了支持日志点的复制还支持 GTID 的方式
同 MMM 相比,MHA 会尝试从旧的 Master 中恢复旧的二进制日志,只是未必每次都能成功。如果希望更少的数据丢失场景,建议使用 MHA 架构。
缺点:
MHA 需要自行开发 VIP 转移脚本。
MHA 只监控 Master 的状态,未监控 Slave 的状态
MGR
MGR 是基于现有的 MySQL 架构实现的复制插件,可以实现多个主对数据进行修改,使用 paxos 协议复制,不同于异步复制的多 Master 复制集群。
支持多主模式,但官方推荐单主模式:
多主模式下,客户端可以随机向 MySQL 节点写入数据
单主模式下,MGR 集群会选出 primary 节点负责写请求,primary 节点与其它节点都可以进行读请求处理.
优点:
基本无延迟,延迟比异步的小很多
支持多写模式,但是目前还不是很成熟
数据的强一致性,可以保证数据事务不丢失
缺点:
仅支持 innodb
只能用在 GTID 模式下,且日志格式为 row 格式
适用的业务场景:
对主从延迟比较敏感
希望对对写服务提供高可用,又不想安装第三方软件
数据强一致的场景
读写负载大问题
读负载大:
增加 slave
加中间层(MyCat,ProxySQL,Maxscale)
读写分离
关于写负载大:
分库分表
增加中间层
评论