中间件阅读笔记
推拉模式的选择
使用长连接拉模式,在消息的实时性方面丝毫不逊推送模式
低延时探索
- 考量性能从吞吐量和延迟两方面考虑
- 依赖系统自身的page cache,全链路延时不可控
- 延时变高导致该时间系统内处理的请求数增多,会导致某些节点不可用并扩散,导致雪崩
锁相关
非公平锁:加锁时不考虑排队问题,直接尝试获取锁,若失败则自动进行排队。
非公平锁导致线程等待时间过长,延迟变高。
锁同步会引起上下文切换,会带来一定开销。上下文切换一般为微妙级,当线程数过多,竞争压力大时,会产生数十毫秒级别的开销。
为避免锁带来的延迟,可利用CAS原语将核心链路无锁化。
内存没那么快
受限于linux的内存管理机制,应用程序访问内存时有时候会产生高延迟。
linux会尽可能用内存来做缓存,大多时候服务器可用内存比较少。当可用内存少时,应用程序申请或者访问新内存页会发生内存回收,当后台内存回收速度不及分配内存的速度时,会进入直接回收(direct reclaim),应用程序会自旋等待内存回收完毕,产生巨大延迟。
通过vm.extra_free_kbytes和vm.swappiness调优来避免。
page cache——利与弊
page cache作为文件缓存能加速数据的读写,但遇到os进行脏页回收/内存回收/内存换入换出等情形时,会产生较大的读写延迟,即偶发的高延迟。
通过内存预分配/文件预热/mlock系统调用/读写分离来消除延迟,同时能利用page cache的优点。
容量保障
降级限流熔断三大措施来保障核心服务的资源,暂停边缘服务。
限流
消息对列中对于慢请求(排队等待时间以及服务时间超过某个阈值的请求)进行容错处理。
对于离线应用场景,利用滑动窗口机制,缓慢缩小窗口以减缓从服务端拉取的频率,降低对服务端的影响。
对于高频交易/数据复制的场景,则采取了快速失败的策略,既能预防应用程序连锁的资源耗尽而引发应用雪崩,又能降低服务端压力,为端到端低延迟带来可靠保障。
降级
通过服务的QOS定义设置,提前约定划分等级,在洪峰期间进行丢车保帅的策略执行。
熔断
Netflix公司开源了他们的熔断解决方案hystrix。
高可用
高可用架构中的技术与权衡
type | Backups | Master/Slave | Master/Master | 2PC | Paxos |
---|---|---|---|---|---|
Consistency | Weak | Eventual | Eventual | Strong | Strong |
Transactions | No | Full | Local | Full | Full |
Latency | Low | Low | Low | High | High |
Throughout | High | High | High | Low | Medium |
Data Loss | Lots | Some | Some | None | None |
Failover | Down | Read-Only | RW | RW | RW |
不同的解决方案对各项指标的支持程度各有侧重。基于 CAP 原则,很难设计出一种高可用方案能同时够满足所有指标的优值。
以 Master/Slave为例,一般满足如下几个特性:
- Slave是Master的备份,可以根据数据的重要程度设置Slave的个数。数据写请求命中Master,读请求可命中Master或者Slave。
- 写请求命中 Master 之后,数据可通过同步或者异步的方式从 Master复制到Slave上;其中同步复制模式需要保证Master和Slave均写成功后才反 馈给客户端成功;异步复制模式只需要保证Master写成功即可反馈给客户端成功。
- 数据通过同步或者异步方式从Master复制到Slave上,因此Master/Slave 结构至少能保证数据的终一致性;
异步复制模式下,数据在Master写成功后即可反馈给客户端成功,因此系统拥有较低的延迟和较高的吞吐量,但同时会带来Master故障丢数据的可能性;如期望异步复制模式下Master故障时数据仍不丢,Slave只能以Read-Only的方式等待Master的恢复,即延长了系统的故障恢复时间。相反,Master/Slave结构中的同步复制模式会以增大数据写入延迟、降低系统吞吐量的代价来保证机器故障时数据不丢,同时降低系统故障恢复时间。
消息服务介绍
路由系统
路由系统,各个处理模块管道化,扩展性强。系统监听主站的交易、商品、 物流等变更事件,针对不同业务进行消息过滤、鉴权、转换、存储、日志打点等。 系统运行过程记录各个消息的处理状况,通过日志采集器输出给JStorm分析集 群处理并记录消息轨迹,做到每条消息有迹可循。
存储系统
存储系统,主要用于削峰填谷,基于 BitCask 存储结构和内存映射文件,磁 盘完全顺序写入,速度极佳。数据读取基于 FileRegion 零拷贝技术,减少内存 拷贝消耗,数据读取速度极快。存储系统部署在多个机房,有一定容灾能力。
推送系统
推送系统,基于Disputor构建事件驱动模型,使用Netty作为网络层框架, 构建海量连接模型,根据连接吞吐量智能控制流量,降低慢连接对系统的压力; 使用WebSocket构建 长连接通道,延时更低;使用对象池技术,有效降低 系统GC频率;从消息的触发,到拉取,到发送,到确认,整个过程完全异步, 性能极佳。
架构
面向公网的应用,消息密度低,随机性强,使用服务端推送的消息消费模式。
快速确认消息
公网环境大部分消息一次就会消费成功,少数需要多次尝试。即99%的数据会在几秒内读写各一次,两次操作完成这条数据就失去了意义。
将待消费的数据存到内存,则少数一直未被消费的数据会丢失(内存队列用完)。数据都存到磁盘则磁盘压力大,性能差,为了少数数据而将全部数据都写磁盘不值得。通过多级缓存的思路来处理这类问题效果比较好,即针对这种场景,系统在存储子系统使用HeapMemory、 DirectMemory、FileSystem三级存储结构。
为了保护存储系统内存使用情况,HeapMemory存储近10秒发送记录,其余的数据会异步写入内存映射文件中,并写入磁盘。HeapMemory基于时间维度划分成三个HashMap,随着时钟滴答可无锁切换,DirectMemory基于消息队列和时间维度划分成多个链表,形成链表环,新数据写入指针头链表,末端指针指向的是已经超时的事务所在链表。
这里,基于消息队列维护,可以有效隔离各个队列之间的影响;基于时间分片不仅能控制链表长度,也便于扫描超时的事务。在这种模式下,95%的消息事务会在HeapMemory内完成,5%的消息会 在 DirectMemory完成,极少的消息会涉及磁盘读写,绝大部分消息事务均在内存完成,节省大量服务器资源。