简洁架构下的高性能读服务
尽量靠近数据
读服务要尽量和数据靠近,尽量减少网络传输。
减少服务之间的调用、架构之间尽量不要分层。
- 不宜
- 宜
代码尽可能简单
- 尽量减少引入框架,
-
- 例如beanUtil.copyProperites 使用了反射进行字段copy。效率低。
- 按需读取
-
- mysql不要使用select *,redis 尽量使用map进行读取。
- 减少日志打印
-
- 在qps较高的情况下,不要进行参数的日志打印。
存储的选型和架构
读服务最依赖的中间件是存储,往往读服务的瓶颈在存储上,因此可以选用基于内存的存储来提升性能。
存在的问题
- 缓存击穿
- 缓存雪崩
- 双写一致性问题,如何保障db与cache中的数据一致
- 代码复杂度增加,每次在更新db时都需要更新cache
全量缓存的高性能读服务
基于binlog 的全量缓存架构
- 优势
-
- mysql与缓存之间的数据同步时间在毫秒级
- 减少了代码的侵入性。无需在每个修改db的时候侵入修改缓存的代码
- 解决了双写一致性问题。始终能保证最终一致性。
- 劣势
-
- 缓存资源成本的增高
- 系统整体复杂度增高,引入了中间件
- 提升点
-
- 存储在cache中的数据需要进行筛选
- 数据压缩
-
-
- json中可以使用替代标识
- redis hash中的Filed字段也可用短标识替代
- json中可以使用替代标识
-
-
- 如需多次查询不同的缓存,可采用异步的方式进行。
- 如需多次查询不同的缓存,可采用异步的方式进行。
存在的问题
如何做binlog格式解析?
binlog不同数据格式
- statment 存储了主节点执行的完成sql ,发送至从节点 由从节点进行重放
- row 存储了该行记录修改前与修改后的数据,并记录了对应的修改字段
- mixed 为以上两种模式的动态结合
binlog同步时的延迟高、吞吐低的问题
由于binlog是串行执行的,业务逻辑过长则会导致性能较低,耗时较长,此时可引入mq作为中间件。接收到binlog对应的消息后直接放入队列,并进行ack。从而提高吞吐量,减少耗时。具体架构如图。
如何保证数据不丢失或错误?
如何设计缓存的数据格式?
使用hash 而不要使用string
如何应对热点数据的查询
具体场景
微博热瓜导致百万用户访问某一个固定的缓存
解决方案
采用缓存的主从复制
二级缓存(前置缓存)
存在的问题
缓存上限
由于前置缓存是基于应用内存中的,因此如果不加限制可能会影响其他引用或导致引用内存爆满。因此前置缓存必须增加缓存过期时间及缓存淘汰策略。
数据更新后的延迟问题
- 定时刷新 定时去redis中拉取数据刷新
- 主动刷新 采用binlog的方式主动刷新
逃逸流量应对
由于热点数据只是小部分数据。因此如果访问非热点数据则需要先到缓存中查询数据并写入前置缓存中,此时会存在一部分延时。此时可以采用热点数据发现即可。
热点数据发现
单独启动个服务进行计数,判断是否为热点数据,然后写入前置缓存中
CDN
整体思路就是减少网络io,让数据离用户更近。
nginx 前置缓存
兜底:降级
需要评估当前机器的qps,然后设置兜底降级策略。