写点什么

“一学就会”微服务的架构模式,一名毕业三年的女程序媛面试头条经验

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:3534 字

    阅读完需:约 12 分钟

一个服务一个数据库



上图就是一个最简单的微服务模式了。


一个服务一个数据库这种模式,是微服务体系结构中的最基础也是最核心的模式。看着简单,但是,这个模式蕴含着微服务的最基本的思想。


要弄清楚一个服务一个数据库这种模式,首先我们就需要问一下,为什么我们要搞微服务。


2. 传统系统的问题


==============================================================================


在谈及微服务的时候,和微服务对应的概念叫做单体系统( Monolithic application )。简单说,微服务是为了解决单体系统的问题才衍生出来的。单体系统结构如下图:



那么这种单体结构出现了什么问题,导致现在大家必须开口闭口微服务了呢?


3. 单体系统太大了


==============================================================================


最首要的一个原因就是应用系统太大。而由于应用系统的过于庞大,如果仅是单体系统的话,就引发了各种各样的问题,体现在以下三个方面:


3.1. 系统本身业务复杂,模块众多




系统随着时间的发展,业务需求越来越多。而为了满足这些需求,就导致整个系统的模块越来越多。而系统模块越来越多,就导致能理解整套系统的人变得越来越少,直到最后没有人可以理解整套系统。


3.2. 系统的代码库非常庞大




代码量也会随着系统的增大而增大,代码量的庞大影响了整个开发流程,会导致整个开发成本变得很高。


  • 首先,代码量大,依赖关系复杂,所以对新接手的开发人员来说,配置开发环境非常耗费精力。

  • 其次,代码量大,加载这些代码和对应的依赖需要的内存就多,所以就会导致开发人员的 IDE 运行非常缓慢,导致编辑代码都很麻烦。

  • 再次,代码量大,如果要把整个代码编译打包,需要的内存也很多,所以也会导致功能开发完成后,对系统的构建会非常缓慢,导致整个构建的时间非常漫长。

  • 再有,代码量大,几乎没人能对整体代码有比较深入的了解,哪怕可能其中一个要改动的功能,都会因为过于复杂导致开发人员理解不深入。而这些不深入的理解又会让开发人员不能使用最佳的方式去做功能开发,从而导致隐藏的 bug。


3.3. 技术团队变得非常庞大




由于功能模块越来越多,这就需要越来越多的开发人员去开发和维护这套系统。但是,这些开发人员都是面对的同一套代码库,虽然可以搞分支,大家各搞各的。可是一旦需要合代码,发布上线,就是场噩梦。


各种代码冲突,代码丢失,都可能在上线的时候发生。


不仅如此,由于顾虑代码丢失和冲突,就需要在上线前,进行足量的测试,而这些测试又需要投入巨大的时间成本。


但是,现在都讲敏捷开发,很可能在还没上线的时候,后续的业务需求又接踵而至,简直要命。


4. 业务需求的个性化


===============================================================================


搞微服务,还有一个很重要的原因是业务需求的个性化和颗粒化。


随着业务的发展,不管是由于市场竞争还是本身发展的需要,势必需要对本身业务模型的深度挖掘以及提高用户使用系统的各种体验。而基于此类种种,就势必要把系统的各个功能模块做深做透。


这又会引发几个新的问题:


4.1. 系统功能模块可能变得更多更杂




系统功能模块可能被不断拆分成了更细碎的模


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


块,以致可能碎成了颗粒。而由于功能变得更碎更颗粒了,就会让产品经理们更容易的提出一些非常细致的业务需求。


这些非常细致的需求,很可能会造成频繁的功能修改和上线要求。而这些无穷尽的快速需求相对整体庞大的系统上线和开发人员的疲于奔命形成了最激烈的冲突。


4.2. 功能模块对系统的技术要求出现了冲突




比如,不同的功能模块,订单模块和支付模块。订单模块就希望系统能尽可能的能同时处理大量的订单,甚至可以有一定的容错性,出问题了砍单就可以了。


但是支付模块则不一样,支付模块希望系统能尽量的稳定,并且必须对准确度要求极高,几乎没有容错的空间。


同样的,在同样的支付模块中(根据系统模块划分而定),可能同时存在本地账户转账和三方渠道支付,本地账户转账可能需要即时,要求极高的响应时间。但是对于第三方支付,则可以有一定的响应时间容忍度。


如果系统本身是个单体系统,就势必要求开发人员对整套系统做一定的妥协,对冲突的技术需求做出一定的权衡。而这种权衡很可能影响的就是系统整体的体验度。


4.3. 系统模块对服务器的要求出现了冲突




由于功能的深耕细作,则势必会出现性能上的不同需求。


比如,系统的订单模块,个人下单可能会被频频访问,此时,就需要系统的集群多一些,去处理这些大规模的访问。但是,同样的功能模块里,可能还存在一些企业团购需求,他们没有那么大的访问量,就不需要那么多的服务器集群。


又比如,用户评论截图,可能需要大量的数据存储。但是,同样的,针对用户的个性化推荐就可能需要大规模的密集运算。


除了上面说的,系统庞大引发的问题带来的一些附属问题:


4.4. 故障的连锁反应问题




单体系统从技术上,各个模块是耦合在一起的。在实际运行里,很可能就会出现一处故障导致整个系统崩盘的现象。


比如,不常用的一个 XX 功能出现了内存泄露,导致整个系统全部不可用了。


4.5. 系统的技术锁死问题




坦白来说,你得承认在编程里,没有一种语言是完美的,也没有一个数据库是万能的。


比如,Java 做科学计算就没有 Python 那么方便高效。比如,我们需要存储很复杂的对象关系的时候,MySQL、Oracle 就不如任何一种图形数据库。


所以,系统越复杂,需要不同技术的概率就越高。但是又由于系统的复杂,引入新技术的风险也就越大。所以,新技术的使用非常困难。


同时,系统庞大后,如果一些组件,甚至语言 SDK 本身的问题如果需要升级,也是一件既繁琐,又充满风险的事情,所以,技术版本升级也非常困难。


综上,对于传统的单体应用来讲,系统庞大引发的技术问题,业务发展引发的需求冲突问题……都是无法单凭单体系统的架构思想就可以解决的。


那为什么 SOA 也不能解决这些问题呢?


5. SOA 的问题


==============================================================================


咱们先来看看 SOA 的结构



可以看到 SOA 架构中有个 ESB(企业服务总线)。这个 ESB 就是专门用于 SOA 的服务和服务之间的互动,是 SOA 必备的基础技术设施。


正因为 SOA 有了服务总线的思想,就注定 SOA 切分的服务不可能太细,因为服务出现的越多,这个服务总线就最终会变成一个整体系统的瓶颈。


SOA 的服务切分规模本身就受到了限制,这个限制就会带来以下的问题:


  1. 切分不够细——我们说过,我们的主要问题根源是系统过于庞大,并且还堆在了一起。如果我们切分不够细,那么可能的结果就会变为,从一个很大的系统被切分为了寥寥几个也很大的系统,最终没有解决问题不说,还可能因为系统变成了不同的分布式服务,又引入了新的分布式系统本身所带来的问题。

  2. ESB 本身就可能成为一个庞大无比的系统怪兽——ESB 作为 SOA 的基础设施,它本身就已经足够复杂,很可能由于业务的发展,它自己也变成了一个恐怖的系统怪物。从而让开发人员不仅需要维护原来的系统,很可能还需要为如何维护和修改 ESB 本身而伤透脑筋。


所以,可以看出来,SOA 这种思维方式和架构实现本身不足以解决庞大单体系统带来的问题。


6. 为什么需要服务


==============================================================================


回到我们的微服务的话题。我们知道了问题的根源,我们就需要着手解决这些问题。


首先,既然问题是由于系统的庞大复杂引起的,那么我们就可以参考软件里很普遍的解决思想:分而克之。


无论一个系统有多大,如果我们将其拆的足够小,就可以把一个复杂的大系统拆分成许多个小系统,再让这分解出来的小系统通过对外提供服务的手段,将他们再聚合成一套大的完整体系,从结果上,就等价为了原来的复杂的大系统了。而这,就是微服务的最朴实的思想。


所以,微服务思想核心有两个:


  • 把系统拆分成不同的部分

  • 这些部分要足够小


微服务这样做带来了几个好处:


  1. 无论多大多复杂的系统,我只要能拆,会拆,就能把问题简化,从而不用惧怕系统变得复杂。

  2. 拆分出来的服务只要足够小,那么无论开发、部署、运维上,都能得到无数原来因为系统庞大而无法获得的好处:修改代码可能变得简单了,测试和运行也变得容易了……

  3. 拆分出来的服务能各自独立发展,不会互相制约。原来系统是单体系统的时候,模块之间由于技术上的耦合,导致无法自由自在的选用最适合当前功能模块的技术,也不能随心所欲的根据当前功能模块的负载情况去弹性的安排服务器。

  4. 故障天然被隔离开了。我们把系统切分成了服务,每个服务都有自己的进程或者服务器,这样故障从物理层面就被隔离开了,从而避免了一处不重要的功能故障导致整个系统崩盘。我们只需要把核心的功能弄的足够健壮,即使非核心功能有了问题,也不会造成太大的损失。

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
“一学就会”微服务的架构模式,一名毕业三年的女程序媛面试头条经验