查看原文
其他

路遥知马力,聊聊好买财富的分布式缓存中间件

2017-07-15 王晔倞 吃草的罗汉

本文将会重点介绍好买财富的中间件服务之分布式缓存(以下简称缓存服务)相关的发展历程。目前为好买财富的零售、高端及机构三条业务线提供服务,承载线上业务数百个,Redis节点超过100个,日均线上请求超过6亿次,业务覆盖程度达到95%以上。

写在前面

跟绝大多数系统一样,“为什么开始使用缓存服务?”“因为数据库扛不住了。。。”


好吧,我们上个缓存挡一挡吧~


和许多传统金融公司一样,在使用缓存服务之前,所有业务数据都是运行在Oracle之上,基本所有的业务系统都处于“1个war包打天下”的状态,强耦合,频发布,人肉化回归测试,这对服务接入的透明度、侵入性提出了很高的要求。


从‘Oracle’转向‘分布式存储服务’的过程中,除去重构这种方式之外,我觉得应该站在以下3个视角进行思考:

  • 设计视角:多半不会考虑数据垂直分片问题(用个Oracle partition也能扛着)

  • 成本视角:无自动化回归测试体系,避免技术风险(如事务、数据一致性等)

  • 效率视角:无法试错,不能“ 憋大招”,马上上,马上用

快速解决当务之急

如外界所述,‘IOE’的架构依托于‘堆机器,拼设备’,当这套理论在某些场景失效,且又无法在短时间替换或重构时,我们只能采取‘分部瓦解,核心击破’的方式开展工作,直接将部分的数据在Oracle DML成功后,将数据同步至缓存中,通过异构读写分离的方式分流Oracle的压力,这样不但不需要承担额外的事务问题,而且应用修改成本还较小,只不过感觉上有些简单粗暴。


简单粗暴的架构设计(2015)

缓存服务在短短1周时间就匆匆上线主要用于存放交易场景中查询频率高、变更频率低的数据,其中架构设计只是‘jredis封装+1M/1S+1WEB’的结构,如图所示。

应用拆分,中间件升级

如外界所述,‘IOE’的架构依托于‘堆机器,拼设备’,当这套理论在某些场景失效,且又无法在短时间替换或重构时,我们只能采取‘分部瓦解,核心击破’的方式开展工作,直接将部分的数据在Oracle DML成功后,将数据同步至缓存中,通过异构读写分离的方式分流Oracle的压力,这样不但不需要承担额外的事务问题,而且应用修改成本还较小,只不过感觉上有些简单粗暴。


混合复用的架构设计(2016)

系统逐渐拆分、垂直化、RPC改造,将核心交易的部分数据优先切换至由Sentinel保障高可用的架构,同样用于存放那些‘查询频率高、变更频率低的数据,其余业务系统还停留在“拆一个系统,搭建一套缓存,使用一个控制台”的架构,如图所示。

无论是‘简单粗暴’,还是‘混合杂乱’,由于缓存的出现,研发手上又多了一把武器,杀敌时可以左右开弓了......



下面大致介绍下各组件(自研部分):

  • howbuy-cache-client:

Read-wirte separation:主从模式:用从服务读,主服务写。

Cache-route:根据业务划分不同的redis集群下,根据业务key,路由到指定redis集群下。

Sentinel-scalable:考虑sentinel的高可用,客户端需要通过接受sentinel的通知消息。自动增加Master节点。

Distributed locks:基于redis中的setnx、get、getandset、del指令特性。实现高效的分布式锁。满足分布式环境下业务同步问题。

Jedis+:jedis客户端在编程实施方面存在如下不足:

  1. connection管理缺乏自动化,connection-pool的设计缺少必要的容器支持;

  2. 数据操作需要关注“序列化”/“反序列化”,因为jedis的客户端API接受的数据类型为string和byte,对结构化数据(json,xml,pojo等)操作需要额外的支持;

  3. 事务操作纯粹为硬编码;

  4. pub/sub功能,缺乏必要的设计模式支持,对于开发者而言需要关注的太多。提供封装处理Native cache:为缓存性能更加优化处理。采用本地缓存处理。减少网络损耗。对于本地缓存变更基于redis pub/sub方式处理;


  • howbuy-cache-web:


好了,研发视角的话说完了,假如你是运维,假如你是测试,应该没有心思去理解后面的技术细节,因为通过上面两张图,内心应该是“我擦。先别说出了异常怎么排查了,那么多套环境,怎么维护啊?”


就像你看到的,每个版本的上线无法做到“一刀切换”,而是采取的“逐个替换”,在这个过程中无论是对测试&生产环境的维护、发布、部署都是挑战,就算你一晚上就能做出一个牛X的自动化系统,也无法在一夜之间将他覆盖至核心业务

透明化接入,技术松耦合

随着时间的推移,系统越拆越多,在第二代缓存服务开始显得 “后经不足”,所以我们开始琢磨第三代缓存服务的演进


为什么要做第三代缓存

做任何事情都是有目的的,先来说说 “为什么”:

  • SDK太重,每次升级对应用流程都是风险、负担

  • 无法透明化访问/接入

  • 对Redis紧耦合,对扩展、迁移及可用性带来麻烦

  • 对多环境无法支持,比如测试环境的特殊需求


上面提到的这些,在「把越来越多的服务治理好才是当务之急,服务微不微可以慢慢来」文章中我也提到过,有兴趣的小伙伴可以浏览此文


先来看看 “第三代缓存的系统架构” 图长啥样:


第三代缓存的版本特性:

  1. 多环境支持 

  2. 反向代理

  3. 服务注册与发现

  4. Proxy无状态化

  5. 轻客户端、 私有协议

  6. 横向扩展、 路由规则


当前的系统拓扑&性能报告


‘第三代’ 与 ‘第二代’ 的性能对比:

  • 技术维度:


  • 带业务场景:


  • 结论:

除去硬件&环境的客观因素,单从性能视角,在增加了proxy层之后,性能并无明显差异


遗留的缺陷与瓶颈

有个道理相信大家都认可,任何方案或版本都是为了解决技术或业务的痛点而诞生的


通过一个时期或一个时代后,再好的方案和版本,都将逐渐地出现 “缺陷或瓶颈”,毕竟业务规模与团队能力在上涨嘛


  • 以下是整理出来待解决的4个缺陷与瓶颈:

结束语

其实,所谓的第三代缓存,就是通过增加Proxy解决如下3个问题:

  1. 透明接入

  2. 技术解耦

  3. 统一管理


在技术圈内,“中间层方案” 与 “非中间层方案” 一直是大家争论与探讨的热点,我觉得各有各的优势,选择哪一种方案应该看以下几点:

  1. 业务规模,如多条业务线,还是单一业务线

  2. 组织结构,如F-Team还是横向工种分类

  3. 技术选型,如平台化


最后,通过最近在互联网上阅读 “当当网架构” 的一篇文章后,整理的几个截图结束本篇文章





最近技术类文章:

你是如何看待“过度设计”这件事的?

架构的纵坐标与横坐标,你权衡好了吗?

把越来越多的服务治理好才是当务之急,服务微不微可以慢慢来



扫描二维码或手动搜索微信公众号【吃草的罗汉】

欢迎转载,带上以下二维码即可

点击“阅读原文”,所有【吃草的罗汉】近期的文章汇总

↓↓↓

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存