林靖JAVA技术专家,货拉拉技术中心核心基础设施部Java技术专家,对数据库中间件研发有深刻的理解和丰富的实践经验。曾在摩托罗拉子公司UniqueSoft担任Java专家,领导自动逆向工程系统中Java的研发;曾任阿里巴巴本地生活中间件技术专家,负责DAL中间件的研发,同时负责多活系统中全局控制中心和数据层的建设。今天的分享主要包括以下几个方面:长期以来,有这样一种观点,认为随着云时代的到来,基础设施将被云接管。基础设施没有了,自然也就不用建中间档了。我的观点正好相反。正是云时代的到来,我们需要更多的自建中间件。你为什么这么说?主要有两个原因:一是技术适配,我们原生环境和云环境不能完全一致,要上云必须要通过中间件来顺畅适配业务;一个更重要的原因是保持供应商的中立性。各个云厂商的服务没有统一的标准。一旦企业习惯了某些独特的服务,企业将失去自由选择云平台的能力。因此,自建中间件是云时代的必由之路。而自建数据库中间件是其中不可或缺的一部分——《适配混合云,数据库中间件建设之路》,这就是我这次要和大家探讨的话题!一、背景业务量的不断增长遇到了单一数据库的瓶颈;业务条线数量持续增加,数据库总量不断扩大;多语言异构,技术基础不断演进,新旧服务过多;多云和混合云部署。和大多数处于上升期的公司一样,随着业务的蓬勃发展,技术底盘也面临着自身的挑战。从量变到质变,很多原本想当然的解决方案都变得不那么完美了。DB就是一个典型的例子。单个数据库没有压力的好日子已经一去不复返了。在高并发和海量数据的压力下,DB开始遇到吞吐和存储的瓶颈。而当DB处于高水位时,也是最容易出现故障的。随着业务的不断丰富和多样化,原来的单体架构也在向微服务架构演进,基于PHP的技术栈也出于各种考虑,也在向Java技术栈过渡。在DB层面表现出来的就是大量的拆库、搬迁、建库。熟悉这方面的同学都知道,“拆迁”是一项耗时、耗力、高风险的作业。混合云背景增加了问题的复杂性。混合云是指我们的架构设计必须具有跨云的特性,需要能够适应不同的云环境,不依赖于特定云厂商的独特产品。从业务研发的角度来看,是一个统一的解决方案,不需要重复开发代码来适应底层环境。2、混合云下的问题与挑战各个云厂商的RDS存在各种差异;现有线性扩容方案无法跨云;DB频繁拆分合并,风险大,容易影响业务;DB层产品变更成本高,无法及时享受新技术红利。刚刚介绍了背景,我们再回顾一下内容。RDS一般在一个云平台上有多种选择,在多云的情况下,可能有点淘宝购物的感觉。总的来说,协议是兼容mysql的,但是涉及到具体的SQL语法、主从部署方案等细节,会有各种细微的差别。比如我们想限制所有的SQL删除数据都有where条件。有的产品不支持该功能,有的产品可能支持动态修改,有的产品只能重启修改。刚才我们提到了单机瓶颈,云厂商已经给出了自己的解决方案。早期的云厂商会提供自己的数据库中间件,比如阿里云的DRDS,支持分库分表的水平扩展数据库。经过一段时间的沉淀和演进,现在云厂商已经推出了几款分布式数据库新产品,提供了更好的运维能力。我们无需关心部署细节,直接享受其线性扩展能力。这些新产品是非常适合单一云环境下的解决方案,但问题是这些解决方案无法跨云,而且这些解决方案依赖于每个云厂商的独特产品。另一个问题是变化。我们以拆解数据库为例。两个企业共享一个数据库,现在需要拆分。那么如何安排具体的执行顺序呢?①同步数据到新数据库;②业务中断;③使用新字符串重启业务服务;④业务恢复。在这个过程中,我们依赖于业务的自我中断能力。此外,我们将长时间中断业务。我们需要判断每个业务节点是否已经重启,否则就是数据不一致的灾难。万一出现问题需要回滚,这个冗长的步骤就得重新做一遍。这时候我们就会想,要是能灵活控制连接字符串,动态设置它指向的DB就好了。可以一下子彻底断掉,有问题可以立马切回来,不需要重启中间业务服务。最后,让我们再看看成本。由于强大的技术背景和市场竞争的压力,云厂商总是推陈出新,不断推出性价比更高的新产品来替代旧产品。我们对低价很感兴趣,但改变的风险让我们不敢轻举妄动。3、混合云下数据库中间件建设如何解决上述问题?核心是解耦和适配。你怎么理解的?我们遇到的问题大多是底层RDS与业务服务的高耦合。这种情况在过去其实是一种非常合理的架构模式,但是到了云时代,已经不能满足我们对可操作性和高可用的要求了。因此,我们需要通过自建数据库中间件,将业务服务和数据层解耦,同时利用数据库中间件适配DB层,为业务服务提供统一一致的体验。从这张图我们可以看出,通过数据库中间件,实现了业务层和DB层的解耦。在这样的架构下,DB层变得更加灵活和安全。我们可以在DB层灵活选择产品,甚至进行跨云设计。回到刚才的DB拆分问题,在新架构下,我们可以这样处理:业务服务用新字符串(指向旧数据库)重启;数据同步到新数据库;数据库流量中断;流量指向新数据库;业务服务只需要修改链接字符串,不需要做任何其他操作。中断时间变得很短,只要增量数据同步完成就可以恢复对数据库的访问。同时回滚操作也由DBA团队闭环。原本需要多方合作的变更,变成了DBA团队内部的闭环动作,大大降低了复杂度。效率和安全性都得到了极大的提升。.1.核心功能和特性前面提到,解耦是靠自建数据库中间件带来的架构灵活性来解决的,那么适配是怎么做的呢?适配主要体现在数据库中间件的具体功能上,这是我们在设计和实现数据库中间件的功能时需要考虑的。下面详细说说这几个功能点:1)基于模板的分库分表,读写分离分库分表可以说是目前性价比最高的数据库线性扩展方案,主流的分布式数据库中间件采用的就是这样的方案。提供给业务研发的视角是使用视角。从业务研发的角度来看,这是一个可扩展的新型mysql数据库,DB容量可以随着业务的发展按需扩展。提供给DBA的视角是运维视角。这是一个分库分表组成的集群,分库分表的数量根据实际DB压力调整。我们可以发现无论是业务研发视角还是DBA视角都比较直观,不会介绍特别抽象的概念。一条SQL的实际执行其实是非常复杂的,包括语法分析、分库分表规则映射、新SQL的生成、新SQL下发到分库执行、结果聚合等等。这些复杂的过程虽然很重要,但是从用户的角度来看,它们不是价值而是负担,所以我们把所有的细节都交给数据库中间件来隐藏。我们交付给业务研发同学的是和普通DB一样的连接串。我们为DBA同学提供的是新建逻辑库的API。参数为分库分表个数,具体哈希函数选择、分表分布等均提供默认模板。这是企业自建数据库中间件的特点。我们不会考虑做一个大而全的产品,需要用户自己调整参数,而是直接提供一个直观的产品,迎合自己业务的特点和最佳实践。这样的设计非常灵活。在不久的将来,将会出现一种被公认为性价比高且稳定的新型数据库。我们完全可以替换掉逻辑库的实现,不用重启就可以直接享受业务服务。2)支持多租户,资源利用更高效多租户是云时代中间件的必备能力。多租户的核心在于资源池化和按需共享,可以有效提高资源利用率,简单来说就是节省资金。多租户的特性可以帮助数据库中间件适应各种使用场景。比如在DEV环境中,我们可以使用一个数据库中间件节点来代理所有的测试DB,这样业务开发在测试开发阶段就可以保持和生产一样的体验,完全不用担心资源浪费。在多租户的设计和实现中,需要考虑两个方面的隔离:一是配置隔离,不同逻辑库的动态配置变化不能相互影响;二是资源隔离,不同逻辑库的SQL执行不应竞争资源。.3)SQL链接跟踪和SQL治理SQL链接跟踪是企业级环境中非常实用和重要的功能。抓到问题SQL后,可以快速定位到具体源头,大大提高在线排查效率。加速故障恢复,减少损失。显然,这种能力无法通过单一的中间件来实现,需要结合成熟的技术底盘。这里需要说明的是,与所有中间件一样,数据库中间件产品只有成为企业技术体系的一部分,才能发挥其全部价值,获得包括监控、配置中心、注册中心等支持,以及支持整个技术体系。提供DB层埋点数据和治理能力。如果成为数据孤岛,在功能和运维上肯定会存在短板,甚至会成为企业技术系统的黑洞。SQL治理能力包括:紧急故障保护能力、紧急故障处理能力;故障保护能力包括:削峰填谷、连接管理、SQL拦截审计等;紧急故障处理能力包括:指定SQL限流拦截、SQLIndexhint注入、主库强制绑定等;完善的SQL治理工具,适配各种云环境,有效保障DB的健康稳定。2.核心技术指标这里列出了一些关键指标。简单解释一下:线性扩展极限——单机容量*1024多租户极限——单集群理论极限最大10K。这两个指标主要考虑这样一个问题:我们现在的架构方案能否满足企业未来2-3年的发展,假设未来3年我们的体量增长10倍,我们的架构是否能够满足顺利应对。从数据层的角度来看,答案是肯定的。基于自建数据库中间件的数据库层架构,可稳定支撑未来百倍业务增长。DBMigrationImpact——二级中断DBMigrationImpact这个指标代表了我们迁移能力的成熟度。也可以说它代表了我们能够在不损失业务的情况下迁移的自由。秒级中断能力可以帮助我们实现业务淡季的无损迁移。最理想的情况一定是全天可操作,这也是我们努力的方向。低时延——99.999%时延小于10ms低时延指标其实包括两个维度的考虑:RT平均值小,RT抖动小。作为数据库中间件,稳定性肯定是第一位的。我们一般选择RT抖动作为衡量稳定性的核心指标。技术上,我们选择了NettyNIO和Java16ZGC的复用框架来实现这个维度指标的提升。HighAvailability——99.999%服务可用性高可用性的量化指标一般用X9s表示,X9s表示系统正常使用时间占系统使用1年期间总时间(1年)的比例.一般企业级软件要求是4个9,即全年允许挂50分钟,如果有5个9,则全年只能挂5分钟,而我们的数据库中间件上线16个月,一直保持零故障,这也算是我们做的。比较满意的部分。成本低——成本占RDS的不到5%。所谓低成本,就是自己做的蛋糕肯定比买的便宜。当然,这只是个玩笑,绝不能这样考虑。这里涉及到三个成本,软硬件成本+运维成本+研发成本。前两个相信大家都不陌生。我主要分享一下我对第三个成本的看法:与过去什么都想自己开发相反,现在我们倾向于夸大自主开发的投入成本,直接放弃自主开发的选择。在中间件领域开源环境比较强的环境下,我们其实比以前更容易培养中间件人才,更有信心利用社区资源解决相关问题,所以研发的成本会不要太高。而且我们还可以在研发实践后回馈社区,形成良性循环,是双赢的选择。3、可操作性和技术设计可操作性是衡量一个中间件产品设计是否“好用”的重要维度。虽然是针对产品上线后的生命周期,但在设计阶段就已经决定了。可操作性的内容比较丰富。在对我们产品的施工过程进行总结和反思后,总结出以下四点。1)面向故障设计非核心依赖可降级核心依赖做好冗余构建系统“自证清白”能力最后一道防线ManualSOP面向故障设计应该是大家耳熟能详的概念。尤其是体积增大之后,故障就变得不可避免了。当只有一台机器的时候,我们说今天可能坏了,但是当我们有一万台机器的时候,我们肯定会说今天坏一台。特别值得一提的是,有时我们把云环境的稳定性神化,认为上云后就不会出现故障。云环境的稳定并不是说没有故障,而是有完善的故障恢复机制,是一种抗脆弱的设计。而有些故障,尤其是硬件故障,并没有快速恢复的方法。例如,如果一个开关坏了,要找到问题需要很长时间,更不用说恢复了。所以无论环境如何,我们都要设计一个失败的预案。在数据库中间件场景中,可降级依赖一般是指影响旁路、动态修改配置、监控等功能,不能降级的部分包括关键数据、硬件设备等,一定要做好数据的备份工作.从另一个角度来看,硬件问题更有可能是单节点故障。集群是一个非常合适的解决方案。当一个大系统发生故障时,往往是到处冒烟,却没有真正的问题。这时候,“自证清白”就很重要了。如果所有部件都能快速确定其状态,则故障点清晰可见。当然,“自证清白”并不那么容易。真实情况往往是市场出现故障。大家想不通是不是自己的模块有问题,然后查看日志,查看监控。但即使做出了这样的努力,仍然很难下结论。“自证清白”是一项重要且极具挑战性的能力,需要对领域有非常深刻的理解,同时需要监控、报警等基础能力的配合。对于数据库中间件,我们主要关注内部工作线程负载、外部性能RT、网络丢包这三个关键数据。手动SOP是一种掩盖方法。例如,数据库中间件保留了启动本地文件的能力。2)产品标准化针对不同的使用特性,分层组隔离使用统一的软硬件标准,尽可能复用已有的企业标准接入标准化功能。简单正交标准化是一种追求全局优化的设计理念。一是功能设计的标准化。作为基础中间件,我们的功能一定要简单正交,这样才能在实现功能的时候更加专注于保证质量,同时为进一步的编排留有余地。比如我们提供了限制指定SQLpqs的功能,也提供了异常SQL的上报能力(类似于SQL过长)。这时候如果上层控制面有能力自动限制异常SQL,就会很顺利,也就是很容易实现,也很容易灰度回滚。但是,如果一开始就把数据库中间件的大动作憋住,就很难做到自如了。相反,很可能功能之间会相互影响,复杂度太高,引入bug会破坏迭代节奏。另一个是外部依赖的标准化。比如尽量使用公司统一的ECS模型,最大程度的避免机器缺货的问题。使用公司统一的基础组件,可以消除额外的维护成本,提高产品开发效率和稳定性。最后是用户使用的规范化。我们应该避免给用户提供太多的不确定性,而只给出标准答案。我们应该统一一套最佳实践,并在此基础上做好支撑优化工作。通过这种方式,用户可以轻松访问并轻松将此过程复制给其他人。在提高效率的同时,也避免了因使用姿势不合理可能导致的故障。3)故障处理智能服务监控、系统监控、外部依赖监控、链路跟踪、自动告警监控非常重要。我们需要从一开始就把监控点纳入到开发计划中,而不是在某个失败之后,才开始增加各种监控指标。监控埋点的要点是能够全面覆盖产品的主要流程,包括数据流和控制流,正常流程和异常流程。这时容易进入的误区是过早地处理埋点数据。比如里面有一个工作队列,直接显示队列的长度比根据某个阈值检查队列是否繁忙更合适,这样我们就可以用图表来显示队列的变化队列繁忙度,还可以灵活设置告警。告警可以是值为0的idle异常告警,也可以是值为100的busy异常告警。无论是告警、链路还是监控,都需要服务于故障排除,所以我们需要设计验收这些指标从方便故障排除的角度来看。当我们怀疑某处打点是否有必要时,可以看看是否对在线排查有帮助。我们谈论“智能”在线故障排除,但我们真正想要实现的是“傻瓜式”故障排除方案。可以在故障发生第一时间收到告警,然后通过链路跟踪工具直接找到根源,最后通过预案一步步处理。4)管理自动化最终会“淘汰”人工流程,用户自助服务自动化可以提高效率,这是我们的共识。自动化可以帮助我们将我们从大量的重复性劳动中解放出来,提高工作效率。那么体积没那么大,零件没那么重复怎么办?是否还需要自动化,比如审计等动作。我觉得很有必要。当我们发现某个部分不能自动化,想手动“忽悠”它时,往往是我们没有考虑清楚。如果我们不彻底解决这个问题,这个问题就会像狗皮膏药一样继续拖累我们的用户。我们之前遇到过这样的情况:新的逻辑库可能会影响旧的逻辑库。我们怕用户填错信息导致异常,所以我们设置了几次人工审核审核。事实上,人工审核并没有解决问题,反而阻碍了整体的自动化。最后,我们重新设计了逻辑库的配置隔离和回滚能力,自动化不再是问题。“淘汰”人工流程很大程度上是在清理我们产品潜在的问题,这些是我们假装没有看到的地方。用户自助类似。能够自助的系统是什么意思?这意味着我们的系统是健壮和稳定的,我们有很好的隔离设计和很强的容错能力。将自助作为目标是构建更好产品的良好动力。一般来说,可操作性影响软件后期投入的“隐性成本”,是一项高回报的长期投资。4.解决的问题及收益下面总结一下自建数据库中间件带来的收益。提高研发效率;提高运维效率;提高系统稳定性;保持供应商中立,实现“云自由”。
