当前位置: 首页 > 科技观察

学一学微服务的架构模式:一个服务一个数据库模式

时间:2023-03-14 20:45:09 科技观察

不管你喜不喜欢微服务,微服务无疑是现在程序员绕不开的话题。无论你是想把现在的架构改成微服务,还是想出去面试更高级的职位,都需要对微服务有深刻的理解。说到微服务,很多程序员又爱又恨。如果他们想学习微服务,他们不知道如何开始。学了一点,就找不到修炼的地方了。总之,感觉微服务遥不可及,难以掌控。首先要明白微服务是有套路的,这些套路基本上解决了微服务架构面临的几乎所有重要问题。这些套路就是微服务本身的架构模式。如果我们能够深刻理解这些模式的来龙去脉,我们就能理解微服务的大部分内容。上手快,实用价值高。一、微服务最基本的模式本文先讲第一种也是最基本的模式。这个模式我估计要三篇文章才能讲透。这是第一部分。打算中间部分写练习,下部分写题。我希望你能轻松学习。微服务最基本的模式是:一个服务,一个数据库上图是最简单的微服务模式。一服一库模式是微服务架构中最基础、最核心的模式。看似简单,但这个模式包含了微服务最基本的思想。搞清楚一个服务一个数据库的模式,首先要问我们为什么要搞微服务。2.传统系统存在的问题说到微服务,微服务对应的概念叫做单体应用。简单的说,微服务是为了解决单体系统的问题而衍生出来的。单体系统结构如下图所示:那么现在大家都要开放微服务的这种单体结构有什么问题呢?3、单体系统过大最重要的原因是应用系统过大。但是,由于应用系统过于庞大,如果只是单一的系统,会造成各种问题,体现在以下三个方面:3.1.系统本身的业务是复杂的,随着时间的推移会发展出很多模块的系统。需求在增加。为了满足这些需求,导致整个系统的模块越来越多。随着系统模块越来越多,能看懂整个系统的人越来越少,直到最后没人能看懂整个系统。3.2.该系统的代码库非常庞大。代码量也会随着系统的增加而增加。庞大的代码量影响了整个开发过程,会导致整个开发成本变得非常高。首先,代码量大,依赖关系复杂,对于新开发人员来说,配置开发环境是非常费力的。其次,代码量大,加载这些代码和相应的依赖需要更多的内存,所以开发者的IDE运行起来会很慢,编辑代码会很麻烦。再次,代码量大。如果要编译打包整个代码,需要大量的内存,所以功能开发完成后,系统构建会很慢,导致整个构建的时间很长。而且代码量大,几乎没有人能够对整体代码有更深入的理解。即使其中一个要改变的功能可能过于复杂,开发人员也不会深入理解它。而这些深入的理解会阻碍开发者使用最好的方式来开发功能,从而导致隐藏的bug。3.3.技术团队变得非常庞大随着功能模块越来越多,需要越来越多的开发人员来开发和维护这个系统。然而,这些开发人员都面临着同一套代码库。虽然他们可以分支,但每个人都做自己的事情。但是一旦代码需要合并并发布到网上,那就是一场噩梦。上网时可能会出现各种代码冲突和代码丢失。不仅如此,出于对代码丢失和冲突的担忧,上线前需要进行充分的测试,而这些测试需要付出巨大的时间成本。但是现在讲敏捷开发,很有可能后续的业务需求在上线前就接踵而至,这简直是致命的。4、业务需求的个性化搞微服务的另一个重要原因是业务需求的个性化和颗粒化。随着业务的发展,无论是市场竞争还是自身发展的需要,都需要深挖自身的业务模式,提升用户使用系统的各种体验。基于这些,有必要深入了解系统的各个功能模块。这会导致几个新的问题:4.1.系统功能模块可能会变得越来越复杂。系统功能模块可以不断拆分成更小的模块,从而可以打碎成粒子。并且由于功能变得更加碎片化和细化,产品经理将更容易提出一些非常详细的业务需求。这些非常详细的需求很可能会造成频繁的功能修改和上线需求。而这些没完没了的快速需求,与整体庞大的系统在线和开发者的疲惫形成了最激烈的冲突。4.2.功能模块与系统技术需求冲突,如不同的功能模块、订单模块、支付模块等。订单模块希望系统尽可能同时处理大量的订单,甚至有一定的容错能力。如果出现问题,只需取消订单即可。但是支付模块不同。支付模块希望系统能够尽可能的稳定,必须对精度要求极高,几乎没有容错的余地。同样,在同一个支付模块中(取决于系统模块的划分),可能同时存在本地账户转账和第三方渠道支付,而本地账户转账可能需要即时,对响应时间要求极高。但是对于第三方支付,有一定的响应时间容忍度。如果系统本身是一个单体系统,势必需要开发者对整个系统做出一定的妥协,对相互冲突的技术需求做出一定的取舍。而这种权衡很可能会影响系统的整体体验。4.3.服务器的系统模块要求存在冲突。由于功能的精耕细作,必然会出现对性能的不同要求。例如,在系统的订单模块中,个别订单可能会被频繁访问。这时候就需要更多的系统集群来处理这些大规模的访问。但是,在同一个功能模块中,可能还会存在一些企业团购需求。他们没有那么大的访问量,所以不需要那么多的服务器集群。再比如,用户评论的截图可能需要大量的数据存储。然而,类似地,为用户提供个性化推荐可能需要大规模的密集计算。除了上述之外,还有一些由庞大的系统引起的附属问题:4.4.故障的连锁反应。从技术上讲,单个系统的每个模块都是耦合在一起的。在实际运行中,很可能一个故障就会导致整个系统崩溃。比如一个不常用的XX函数,出现内存泄漏,导致整个系统不可用。4.5.系统的技术锁死问题坦率地说,你不得不承认,在编程中,没有一种语言是完美的,也没有一种数据库是万能的。例如,Java在科学计算方面不如Python方便高效。例如,当我们需要存储非常复杂的对象关系时,MySQL和Oracle都不如任何图数据库。因此,系统越复杂,需要不同技术的可能性就越高。但由于系统的复杂性,引入新技术的风险较大。因此,新技术的使用难度很大。同时,在系统庞大之后,如果需要对某些组件甚至语言SDK本身进行升级,是一件麻烦且风险大的事情,因此技术版本的升级难度很大。综上所述,对于传统的单体应用来说,庞大的系统带来的技术问题,业务发展带来的需求冲突……不是单靠单体系统的架构就能解决的。那为什么SOA不能解决这些问题呢?5.SOA问题我们先来看看SOA的结构。我们可以看到SOA架构中有一个ESB(EnterpriseServiceBus)。这个ESB专门用于SOA服务以及服务之间的交互,是SOA必备的基础技术设施。正因为SOA有服务总线的思想,就注定了SOA切分的服务不能太细,因为出现的服务越多,服务总线最终会成为整个系统的瓶颈。SOA的服务切分规模本身是有限制的,这种限制会带来以下问题:切分不够细——正如我们所说,我们的主要问题根源是系统太大,堆起来了。如果我们的切分不够细,可能的结果就是一个大系统被分成了几个大系统,最后没有解决问题,也有可能是系统变得不一样了。分布式服务,也引入了新的分布式系统本身带来的问题。ESB本身可能会成为一个巨大的系统怪兽——作为SOA的基础设施,ESB本身已经足够复杂,很可能由于业务的发展,它本身也成为了一个可怕的系统怪兽。这样一来,开发者不仅需要维护原有的系统,还可能需要操心如何维护和修改ESB本身。由此可见,SOA的思维方式和架构实现不足以解决单体系统庞大带来的问题。6.我们为什么需要服务?回到我们微服务的话题。现在我们知道了问题的根源,我们需要开始修复它们。首先,既然问题是由庞大复杂的系统引起的,那么我们可以参考软件中常见的解决思路:分而治之。不管系统有多大,如果我们把它拆解得足够小,就可以把一个复杂的大系统拆分成很多小系统,然后通过对外提供服务的方式,让拆解后的小系统重新聚合起来,形成一个大而完整的系统在结果上等同于原来的复杂大系统。而这就是微服务最简单的思想。因此,微服务有两个核心思想:将系统拆分成不同的部分。可以把问题简单化,不用担心系统变复杂。只要拆分的服务足够小,无论是开发、部署还是运维,都可以获得无数因为庞大的系统而得不到的好处:修改代码可能会变得更容易,更容易测试运行…………拆分后的服务可以独立开发,互不制约。当原有系统为单体系统时,由于模块间的技术耦合,无法自由选择最适合当前功能模块的技术,无法根据当前功能模块的负载灵活安排服务器模块。故障自然隔离。我们把系统划分成服务,每个服务都有自己的进程或者服务器,这样就把故障从物理层面隔离开来,从而避免一个不重要的功能故障导致整个系统的崩溃。我们只需要让核心功能足够健壮,即使非核心功能出现问题,也不会造成太大的损失。因此,一个庞大的系统,由于其臃肿和复杂性,可能不得不自行分裂。而这些拆分,按照一些指导原则,拆得足够小,足够简单,那么拆解带来的收益是相当可观的。7、为什么要拆库?服务已经拆了,就已经有了这么大的好处。“可是为什么数据库一定要拆?”-这其实是很多使用微服务的同学最困惑的问题。是否拆分数据库本质上是数据共享的问题。为图书馆服务本身的理念其实就是尽可能避免数据共享。数据共享会带来以下问题:7.1.技术实现上可能还是耦合的,因为数据库没有拆分,所以很有可能本来应该独立的一个服务模块必须依赖另外一个服务模块,这和我们拆分服务的初衷似乎是在冲突。例如,订单服务和个性化推荐服务都可能需要访问与订单相关的数据。此时,如果不拆除数据库,很可能会因为订单业务需求修改订单表的结构,迫使个性化推荐服务做相应的修改。7.2.底层数据的过度暴露仍然是上述订单服务和个性化推荐服务的例子。个性化推荐可能只需要一些用户ID、订单类别等,但是由于数据库是共享的,很可能订单是公开表中的所有数据,而这些数据很多都属于敏感数据,应该隐藏起来,现已曝光。7.3.不必要的数据访问竞争由于是同一个数据库,这必然会导致共享数据的竞争访问,而这些竞争访问会极大地影响业务模块的灵活部署。比如订单模块,由于一些个性化推荐的定时批量查询,很可能会受到其所能承载的并发数据量的影响。所以,可以看出,分库是微服务整个架构中必须要考虑的。8、最后留个尾巴。每个服务对应一个数据库。这种模式是微服务中最核心、最基础的模式。它体现了微服务的核心思想:拆分和解耦。一般来说,微服务在大的时候,我们会尽量采用一服务一数据库的模式。这里只讲为什么要用一个服务一个数据库,以及如何划分服务和数据库。他们是否还有一些实际的妥协,将在下一篇文章中仔细分析。本文转载自微信公众号“思源外”,可通过以下二维码关注。转载本文请联系思源外公众号。