架构实战案例解析_10_09_可复用架构案例二如何对现有系统做微服务改造
你好,我是王庆友。
在上一讲中呢,我以订单服务为例,和你一起讨论了如何从头开始设计一个共享服务。
那么今天我们再来聊一聊如何对现有系统做微服务化改造。
很多早期的互联网公司都有巨大的单体应造。
那底层的数据库表呢是集中放在一个数据库里,这一表加起来肯定有几百张。
对这样的应用系统和数据库,我们往往需要对他们进行拆分,通过微服务化改造,保证系统能够不断的扩展和复用。
那相比从头开始落地服务,对现有系统做微服务化改造,这会面临更多的挑战。
首先呢应用和数据表紧密耦合在一起。
那代码模块和表是多对多的依赖关系。
一个模块可能会访问多张表啊,多个模块也可能会对同一张表进行访问。
而且由于表在一个数据库里,开发人员往往会随意对这些表做关联。
有的时候呢甚至将用五六张表以上。
这样子呢代码模块和表之间的关系啊是剪不断理还乱。
我们很难清晰的划分代码和数据表的边界,这样也就很难把它们分装成独立的微服务。
还有一个问题,系统现在已经在运行了,那我们的改造不能影响业务的稳定性。
微服务落地后,现有的系统要怎么对接?微服务数据要怎么迁移才能保证系统的平滑过渡呢?所以要想应对这些挑战,一方面呢我们要保证比较合理的服务设计,这样才能达到优化系统架构的目的。
那另外一方面呢,我们要做到整个过程中啊,对现有系统影响比较小,才能达到系统改造顺利落地的目的。
那接下来我就以药店库存服务化改造为例,让你深入的理解我们是如何把库存相关的功能和数据表从现有系统里剥离出来,最终构建独立的库存服务,并实现和业务系统平滑对接的那我们先来看一下这次架构改造的背景和目标。
那药店作为一个网上超市,它售卖的商品种类啊很多有数十万个。
那包括药店自营的和第三方商家的商品。
那由于历史的原因,所有商品相关的表都存在产品库里面。
这里面呢包含产品相关的表,商品SKU相关的表,商家和供应商的表,还有库存和价格的表,这些表加起来呢数量超过了上百张。
那我们知道商品是电商业务的核心,那几乎所有的前后台系统都需要访问这个产品库。
而这些系统的开发人员在早期的时候只关心如何实现业务功能,对这些表的访问呢是怎么方便怎么来。
有些c口语句会对大量的表做交易关联。
所以说虽然系统是类似分布式的,但数据库呢是集中式的。
这里呢我放了一张图,你可以到文稿中看一下。
那这样的方式就给系统的维护带来一系列的问题。
那么我们从应用方面来说,各系统功能重复建设,比如很多系统都会直接访问库存相关的表类似的库存逻辑散布在很多地方。
还有呢如果我们修改了库存表的某个字段,那这些系统呢会同时受影响,正是为迁一发而动全身。
那从数据库方面来说,数据库的可用性是比较差的。
如果某个系统有慢查询,它就很可能拖垮整个产品库,导致它不可用。
还有这么多系统同时访问产品库数据库的叠加数呢也经常不够用。
所以我们这次架格改造的目标,首先是对这个大数据库按照业务维度进行垂直拆分。
比如说分成产品数据库、库存数据库、价格、数据库等等。
然后基于这些拆分后的库,构建微服务,以结构的方式来支持数据库表的访问。
最后呢把各个业务系统统一接入这些微服务,最终完成整个商品体系的微服务化改造。
那这里呢你可以看到涉及了很多的微服务,如果同时进行服务化改造的话,牵扯会很大,这样呢很难落地。
于是呢我们就选择从库存微服务开始,为什么呢?一方面是因为库存的业务很重要,库存的规则也比较复杂。
如果我们能够实现对库存逻辑进行优化,这会带来明显的业务价值。
另外一方面呢,电商的库存概念相对独立,涉及的表也比较少。
我们可以相对容易的把它从现有体系中剥离出来。
那整个改造过程从确定库存相关的表开始,到最后把库存表从产品库迁移出来,落到单独的库存数据库为止,一共分为两个阶段。
那每个阶段呢又包含了三个步骤,这里呢有一张图,你可以到文本中看一下。
第一个阶段是准备阶段,这个阶段为微服务改造,做好前期的准备工作。
那具体步骤包括圈表收集CQ语句以及CQ语句的拆分。
第二个阶段呢是实施的阶段。
这个阶段我们实际落地微服务。
那具体步骤呢包括微服务的开发,微服务的接入和数据库的独立。
那通过这些良好定义的步骤,我们就很好的保证了整个库存微服务改造的有序和可控。
接下来呢我就具体说明一下,改造的各个步骤,包括都是哪些人负责,哪些阶情,具体的挑战在什么地方。
这样子呢你就可以深入理解整个改造过程。
先说一下准备阶段,准备阶段第一步呢就是圈表,产品数据库有一百多张表。
那圈表呢就是用来确定库存微服务具体包含哪些表,也就是确定服务的数据模型。
在确定了表以后,库存微服务就负责这些表的访问。
当然库存微服务也不会访问其他的表。
而业务系统呢后续将通过库存微服务的接口实现对这些表的访问。
缺表呢是整个微服务改造过程中比较有挑战性的地方。
它实际上对应了服务的边界划分,是针对老系统做浮法改造的时候呢,我们更多的从数据库表的角度考虑划分,这样呢更加好落地。
那针对库存微服务来说,我们要求确定的表一方面能够满足所有库存访问的场景,而且这些表之间的关系比较紧密,和其他表的关联不大。
另外一方面呢,这些表的数量不能太多,一般不超过十几张这样子我们既容易拆分数据库,又能控制库存微服务的力度,保证它的功能聚焦。
在这个例子中呢,由于库存的概念比较独立,圈表相对比较容易,一共呢有十五张表和库存直接相关。
这里呢包括自营库存表,自营库表,它是分表的,所以实际上是十二张。
那还有商家虚拟库存表活动库存表和库存共享表。
这些表之间呢他们是紧密相关的,他们一起决定了前台用户能看到的可用库存数量。
这些库存相关的表都有商品ID字段和商品的基本信息表关联。
那我们知道库存数量计算它不依赖于商品的具体信息。
所以这些库存表和其他表的关系呢是比较弱的。
这样我们就可以比较清晰的实现库存表和其他表的切分,可以简化库存服务的落地。
我这里呢也放了一张图,你可以到文稿中看一下,可以很清晰的表明这些表和其他表的相互关系。
在微服务改造中确定哪些表属于这个服务,而直接影响后续的所有改造工作。
这个呢需要有经验的业务架构师和数据架构师穿与进来,通过深入的分析,现有的业务场景和表的关系,才能对库表进行合理的划分。
所以啊你可以发现对现有系统做改造服务的边界划分呢主要是从圈表入手的,而不是从一个服务应该有哪些功能入手的这一点呢和新服务设计是有所不同的这具体呢有两方面的原因。
一方面呢如果我们确定了服务包含哪些表,其实也就大致确定了这个服务呢有哪些功能。
而表呢它是现成的,它比业务功能更加直观。
所以从表入手比较高效。
另外一方面呢,如果我们从表入手,那我们构造的服务呢和表是对应的服务,它包含的是完整的表,不会说产生一个表的一部分字段属于库存服务。
而另一部分字段属于别的服务。
这种情况避免表字段的拆分带来额外的复杂性。
那这里值得注意的是呢,因为这个是对现有系统的改造。
我们为了避免一下子引入太多变化,我们先不对库存的表结构进行调整表结构的优化呢,我们可以放在服务的升级版里做,这样对业务系统的影响也最小。
那第二步呢,就是收集sql语句。
在确定了哪些表属于库存服务后,我们会收集所有业务系统访问这些表的sql语句,包括它的业务场景说明,访问的频率等等。
那库存微服务后续就针对这些sql语句进行封装,提供相应的接口给业务系统使用。
那这里呢服务开发团队会负责提供这些sq收集的excel模板。
那各个业务系统开发团队负责收集具体的sql语句。
第三步呢是对c口语进行拆分,对收集过类税口语句啊,有些c口不仅仅访问圈定的这几张库存表,它还会和产名库中的其他表进行关联。
那比如说商品详情页,它需要展示商品的详情信息,它会发起sql查询商品的基本信息表和库存表一次性的获取商品的基本信息和库存数量。
那那后对这工作呢,我们就需要把查询语句拆分为两条c口,先查询商品表,获取商品的基本信息,然后再查询库存表获取库存数量。
那对于这样的c口语句,我们就要求各个业务团队先进行拆分,保证最后提供给服务开发团队的sq l那那在访问库存的相关表。
那通这c口口拆分们就切断断库库存和其他他的的直接数量。
那后面微服务落地后呢,业务系统就可以通过接入微服务,完成现有c口的替替换。
这个c口口分会涉及一定的业务系统改造,这部分工作呢主要由各个研发团队负责。
一般情况下性能可能会受些影响,但问题不是很大。
那我们完成了圈表sql收集和拆分以后,接下来我们就进入了服务实际落地阶段。
那第四步呢就是构建库存微服务。
这里面呢包含了接口的设计,代码的开发、功能的测试等步骤。
那服务开发团队会对业务方提供的sql进行梳理,然后对接口做一定的通用化设计,避免为每个sql定制一个单独的接口,这样呢也保证了服务的复用能力。
那这部分工作呢由微服务开发团队负责。
第一版的服务主要是做好接口设计,聚焦业务功能,以保证服务能够落地业务系统,能够顺利对接为目标。
那将来呢服务可以持续迭代,内部做各种技术性的优化。
那只要我们服务的接口保持不变,就不会影响业务系统。
那将步是接入库存为目标。
那我们的库存服务经过功能和性能的验证以后呢,会有各个业业务开发团队逐步接入替换原来的c口语句。
这部分工作呢主要由业务研发团队负责,难度也不大,但需要耗费比较多的时间。
最后一步呢是数据库的独立的服务。
接入完成后,所有的c口语句都被替换了。
那业务系统已经不会直接访问这些库存的表。
这个时候呢,我们就可以把库存相关的表从原来的产品库中迁移出来,部署成为一个物理上独立的数据库业务系统,只通过服务来访问数据库的。
因此,这个数据库迁移对业务系统来说是透明的业务团队,甚至不用关心这些表的新位置。
通过把库存表独立成库,我们可以从物理层面切断业务团队对这些表的依赖,同时呢也可以大幅度降低产品库的压力。
特别在大促的时候,库存读写压力是非常大的那数据库独立也为库存服务,后续的技术优化打下了基础。
这部分工作呢主要有微服务开发团队和DBA一起配合完成,主要是避免业务系统还有遗漏的CQ语句。
他们还在直接访问库存的表,这个呢我们可以在清库前通过代码扫描做相应的检查工作。
这里呢我放了一张图,显示改造完成后的库存微服务架构。
这个呢你可以到文稿中看一下。
那库存微服务一共包含了十五张表,对外有三十多个接口,有几十个业务系统接入库存服务。
在平时的时候,库存服务会部署五十个实例。
大促的时候,我们会部署更多。
我们也很容易通过加期的方式实现库存服务的水平扩展到这里。
我们的库存微服务就改造完成了。
整个改造呢大概持续了三个月的时间,主要是对接的工作比较耗时。
那从前面介绍的步骤中呢,你可以看到除了做好库存服务本身的设计开发工作,相关团队之间的配合啊也是非常的重要。
在整个改造过程中有很多团队之间的沟通和确认的环节。
比如说服务开发团队圈定表以后,需要和业务开发团队一起确认,保证圈表的合理性。
那在业务团队拆分sql的过程中,服务开发团队需要介入进去,帮助解决拆分时带来的性能和一致性问题。
那在服务接口设计和接入的过程中,服务的接口呢可能也需要不断的调整,也可能有新的sql进来。
这个呢需要双方及时沟通,相互配合,这些都是纯技术层面的问题。
那值得注意的是,系统改造它不会产生直接的业务价值。
那对于业务线开发团队来说,他们往往还需要承担大量新需求的开发工作。
所以从项目推进的角度来看,这种核心服务的改造,很多时候都是技术一把手工程。
在库存微服务改造过程中呢,我们也是老板高度重视大家事先定好时间计划,每周会过进度,协调各个团队工作的优先级,确保改造顺利落地。
以上呢是库存微服务改造的例子。
那一号键的系统呢,它从零八年就开始建设了。
由于历史的原因形成了几个典型的大库,比如说产品库、用户库等等。
那我们通过类似的微服务改造,逐渐把这些大库拆分开,构建了一系列的技术服务。
比如说订单服务、用户服务、产品服务、库存、服务价格服务等等。
通过这些微服务化改造,我们同时提升了业务的复用性和系统的稳定性。
最后呢我在这里放了一张一号店的总体系统架构图,那非常建议你到文稿中看一下。
通过这张图,你可以看到一个历史包袱很重的系统,它是如何经过服务化改造,最终变成一个那个高度复用和扩展的平台的。
好了,下面我总结一下今天所讲的内容。
那基于现有的系统进行改造和全新的服务设计是有所不同的。
我们不能追求理想化和一步到位,而是要考虑到系统的平滑过渡,先实现微服务的顺利落地,后续再考虑各种优化。
那今天呢我通过一药店库存微服务改造例子给你提供一种可行的微服务落地套路。
那你可以顺利的完成老系统的架构升级。
相信通过今天的分享,你对现有系统如何进行微孵化改造,有了更深入的理解,希望你在实践中也能灵活运用,最后给你留一道思考题。
你在做现有系统服务化改造的过程中,具体碰到了哪些挑战,你又是如何克服的呢?我是王庆友,欢迎在留言区和大家分享你的思考,我们一起讨论。
如果你觉得有收获,也欢迎你把这篇文章分享给你的朋友,感谢收听,我们下一期再见。