分布式本地缓存

技术选型理由

Etcd

  1. Zookeeper 和Etcd 都是业界优秀的分布式协调系统,解决了分布式系统协调和元数据存储。etcd 参考了 ZooKeeper 的设计和实现经验,并从 Zookeeper 中汲取的经验教训用于优化自身架构,从而帮助其支持 Kubernetes 等大型系统。
  2. 解决服务发现,保证元数据变更后对集群中的每个实例的本地缓存进行更新
  3. 技术创新,使用业界认可的中间件,保持技术先进性。使用成熟后可覆盖其他业务场景。

Guava cache

    业界和本部门很多应用都比较常用,基于jvm的内存缓存,适用于以下场景:

  1. 愿意消耗一些内存空间来提升读性能
  2. 键值会多次被查询
  3. 内存适用总量不会超过jvm内容容量

对于分布式协调的应用场景没有用redis、ducc、jmq因为这些中间件的应用场景的优势不在于此。

 

 

改造一:业务数据本地缓存化,并通过分布式数据库解决元数据一致性

目的

  1. 当前数据查询先走redis缓存,为提高服务器利用率,遇突发流量时可以减少redis单分片的压力
  2. 两级缓存提高服务稳定性
  3. 解决数据在集群环境下的一致性,保证每个jvm内存中的数据一致

影响范围

    大促核心接口:

  1. xxx.checkSkuId,预估数据量10w条 (MaximumSize)10MB,最终按照压测情况调优。
  2. PopWareDetailService.PC/M 样式接口,但由于数据内容较大,如果要做缓存,数据量要线上实际去观测一下,建议只做热点。

业务流程

 

 

 

 

 

第一步:业务场景下,数据的新增与更新会触发入库(mysql/mongodb)和redis,本方案会新增写入etcd集群。写入规则是根节点(系统名)/子节点(业务名)/叶子节点(业务key)

第二步:每个应用客户端docker节点订阅etcd集群业务目录,业务目录下的key值变更都会监听到

第三步:监听到有变化的key会将数据同步到基于guava cache实现的本地缓存中

第四步:当业务代码被访问时先从本地缓存中获取数据,本地缓存是有数据的

第五步:如果本地缓存没有数据(或者应用被重启)通过第6步回源到redis获取数据并回写到本地缓存中。数据有变更时会通过1,2,3步骤完成本地缓存的更新

第七步:监控服务负责Etcd集群监控,另外再用mdc系统监控

第八步:开源应用,查看Etcd节点和叶子节点数据

 

 

使用 对内存的管理:

 

  1. 缓存淘汰策略:LRU,最近最少使用策略,无论是否过期,根据元素最后一次被使用的时间戳,清除最远使用时间戳的元素释放空间。策略算法主要比较元素最近一次被get使用时间。在热点数据场景下较适用,优先保证热点数据的有效性
  2. 提供统计接口:缓存命中率、缓存条数
  3. 清理缓存接口:key、keys、all

 

业务规则

  1. etcd集群,一主两从,预发环境2c4g,生产环境4c8g
  2. etcd集群监控,
    1. 现阶段通过mdc进行服务器性能监控(cpu、内存、磁盘、连通性等)
    2. 搭建新应用来对集群健康进行监控,通过etcd提供http接口来获取,结合ump进行监控,暂不进行监控数据的持久化
  3. 为XX.checkSkuId设置本地缓存优先读取,如果没查到回源到jimdb
  4. ducc参数与开关配置:
    1. 是否优先读取本地缓存开关
    2. guava cache初始化配置,包括:缓存条数
  5. 本地缓存运维查询接口:查询key,删除key/ALL,缓存命中率
  6. etcd SDK开发,包括功能put、get、del、watch

 

 

改造二:对缓存穿透、热key、异常量、限流 4种数据上报,通过服务端计算进行结果的同步

目的

  1. null key进行计算,达到阈值则同步到集群的各客户端jvm内存,解决缓存穿透
  2. 热key进行秒级的计算,达到阈值则同步到集群的各客户端jvm内存,防止redis单片过热
  3. 对调用的上游业务接口异常量进行计算,达到阈值则同步到集群的各客户端jvm内存,进行业务熔断

影响范围

  1.     PopWareDetailService.PC/M 样式接口(nullkey、热key)
  2.     工作台保存业务中的多个上游接口(熔断)

业务流程

 

 

第一步,请求进入客户端,从本地缓存读取业务key数据进行业务流程判断,是否空值,是否被限流、是否被降级

第二步,客户端根据业务需求调用上报SDK模块,进行null key的上报、调用上报、接口调用异常上报

第三步,计算集群上报心跳到etcd集群,SDK模块从etcd获取计算服务IP集合,实现服务发现

第四步,将业务key进行hash取模,再将上报请求固定在一台计算服务机器上进行计算。基于netty建立长链接,提高TPS

第五步,将符合阈值(ducc)的计算结果put到etcd集群的业务目录/业务key。Sentinel、Resilience4j

第六步,客户端对业务目录/业务key进行订阅,监听程序进行数据同步,并更新到每个客户端jvm内存

 

业务规则

  1. 先完成方案一的技术搭建
  2. 上报模块SDK开发(空key、异常量、热key),数据上报通信模块客户端开发
  3. 计算服务端开发(计算模块),数据上报通信模块服务端开发
  4. ducc参数与开关配置:
    1. 上报数据计算阈值配置
    2. 上报开关配置
    3. 是否优先读取本地缓存配置

 

 

改造三:商品介绍数据Etcd兜底(探讨,结论:不适合)

目的

  1. 为商品介绍数据寻找一个兜底数据库,并且能100%负载大促流量和性能指标的数据库

影响范围

    大促核心接口:SkuDecCheckService.checkWareIdDecInfo、PopWareDetailService.获取样式接口

业务流程

 

 

 

 

原有架构,核心接口中读数据由jimdb硬抗。改造后

第一步,业务模块会进行三写,jimdb+etcd+mongodb。

第二步,数据请求先访问本地缓存

第三步,本地缓存没有查询jimdb

第四步,jimdb没有数据回源查询mongodb

第五步,jimdb异常从etcd查询

第六步,ducc作为查询jimdb还是etcd的手动开关

目前jimdb资源占用内存130G,8分片,峰值操作6.7w次。建议Etcd集群指标 QPS 8w、硬盘300G。

以下是官方的性能参考:

 

 

 

 

 

集群部署策略:

 

 

  1. 集群磁盘容量不足,分片存储
  2. 提高QPS
  3. 数据分摊,单点故障也能提供有损服务

 

兜底数据可以考虑使用es。oss

 

Etcd运维

  1. etcd搭建(集群) etcd + (nginx/HAProxy) 高可用部署方案
  2. etcd服务监控(集群健康情况监控告警、新增节点、移除节点、单点故障与恢复)
  3. etcd方案权限控制(保证开发环境与生产环境的隔离)
  4. etcd重启与数据恢复
  5. etcd磁盘打满解决方案

 

 

 

其他

发布过的sku数量:27874618(未去重)

不进行全量数据的本地缓存(虽然全量数据不多),因为历史数据可能就没有访问量,存入本地缓存浪费资源。

对非热点数据不进行本地缓存数据一致性处理,比如场景:容器A接收到请求写入本地缓存key1后,不将key1同步到容器B、C。

压缩样式内容字符串,提高缓存数量

其他:当前业务没有限流的需求,但基于这样的架构限流也能做

 

待确认

1、etcd的集群申请

2、实时计算服务的选型可以考虑kafka,kafka性能:单个Consumer每秒可消费三百万条消息,单个Producer每秒可成功发送一百多万条消息

3、灾备建议使用jimdb成本较低

4、watch的延时问题,需要通过测试来验证

 

1、愿意消耗一些内存空间来提升读性能
2、键值会多次被查询
3、内存适用总量不会超过jvm内容容量

posted @ 2021-02-05 17:04  姚春辉  阅读(1730)  评论(0编辑  收藏  举报