路遥知马力,聊聊好买财富的分布式缓存中间件
本文将会重点介绍好买财富的中间件服务之分布式缓存(以下简称缓存服务)相关的发展历程。目前为好买财富的零售、高端及机构三条业务线提供服务,承载线上业务数百个,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客户端在编程实施方面存在如下不足:
connection管理缺乏自动化,connection-pool的设计缺少必要的容器支持;
数据操作需要关注“序列化”/“反序列化”,因为jedis的客户端API接受的数据类型为string和byte,对结构化数据(json,xml,pojo等)操作需要额外的支持;
事务操作纯粹为硬编码;
pub/sub功能,缺乏必要的设计模式支持,对于开发者而言需要关注的太多。提供封装处理Native cache:为缓存性能更加优化处理。采用本地缓存处理。减少网络损耗。对于本地缓存变更基于redis pub/sub方式处理;
howbuy-cache-web:
好了,研发视角的话说完了,假如你是运维,假如你是测试,应该没有心思去理解后面的技术细节,因为通过上面两张图,内心应该是“我擦。先别说出了异常怎么排查了,那么多套环境,怎么维护啊?”
就像你看到的,每个版本的上线无法做到“一刀切换”,而是采取的“逐个替换”,在这个过程中无论是对测试&生产环境的维护、发布、部署都是挑战,就算你一晚上就能做出一个牛X的自动化系统,也无法在一夜之间将他覆盖至核心业务
透明化接入,技术松耦合
随着时间的推移,系统越拆越多,在第二代缓存服务开始显得 “后经不足”,所以我们开始琢磨第三代缓存服务的演进
为什么要做第三代缓存
做任何事情都是有目的的,先来说说 “为什么”:
SDK太重,每次升级对应用流程都是风险、负担
无法透明化访问/接入
对Redis紧耦合,对扩展、迁移及可用性带来麻烦
对多环境无法支持,比如测试环境的特殊需求
上面提到的这些,在「把越来越多的服务治理好才是当务之急,服务微不微可以慢慢来」文章中我也提到过,有兴趣的小伙伴可以浏览此文
先来看看 “第三代缓存的系统架构” 图长啥样:
第三代缓存的版本特性:
多环境支持
反向代理
服务注册与发现
Proxy无状态化
轻客户端、 私有协议
横向扩展、 路由规则
当前的系统拓扑&性能报告
‘第三代’ 与 ‘第二代’ 的性能对比:
技术维度:
带业务场景:
结论:
除去硬件&环境的客观因素,单从性能视角,在增加了proxy层之后,性能并无明显差异
遗留的缺陷与瓶颈
有个道理相信大家都认可,任何方案或版本都是为了解决技术或业务的痛点而诞生的
通过一个时期或一个时代后,再好的方案和版本,都将逐渐地出现 “缺陷或瓶颈”,毕竟业务规模与团队能力在上涨嘛
以下是整理出来待解决的4个缺陷与瓶颈:
结束语
其实,所谓的第三代缓存,就是通过增加Proxy解决如下3个问题:
透明接入
技术解耦
统一管理
在技术圈内,“中间层方案” 与 “非中间层方案” 一直是大家争论与探讨的热点,我觉得各有各的优势,选择哪一种方案应该看以下几点:
业务规模,如多条业务线,还是单一业务线
组织结构,如F-Team还是横向工种分类
技术选型,如平台化
最后,通过最近在互联网上阅读 “当当网架构” 的一篇文章后,整理的几个截图结束本篇文章
最近技术类文章:
扫描二维码或手动搜索微信公众号【吃草的罗汉】
欢迎转载,带上以下二维码即可
点击“阅读原文”,所有【吃草的罗汉】近期的文章汇总
↓↓↓