微服务架构学习与思考(12):从单体架构到微服务架构的演进历程
<blockquote><p>微服务架构系列文章集合:https://www.cnblogs.com/jiujuan/p/17307285.html</p>
</blockquote>
<p>从单体架构到微服务架构的演进历程</p>
<h2 id="一单体架构">一、单体架构</h2>
<h3 id="11-什么时候用单体架构">1.1 什么时候用单体架构</h3>
<p>在创业初期或项目开始时,项目整体功能比较少,开发人员也少,且项目需要用最少时间开发出来,用 MVP 方式快速进行市场验证是否可行,这时候就可以用单体架构进行快速开发。</p>
<h3 id="12-单体架构设计举例-电商应用">1.2 单体架构设计举例-电商应用</h3>
<h4 id="功能分析">功能分析:</h4>
<p>拿淘宝网来举例,现代电商网站功能是很复杂的,有多少功能呢?可以看看我前面的文章《电商产品设计全攻略》读书笔记(https://www.cnblogs.com/jiujuan/p/14452748.html#1574269892) 里的电商管理系统和电商平台产品结构 2 小节。</p>
<p>拿淘宝网举例的话,当然是最早期的淘宝网 - -!,它最简单的 3 个功能:商品展示,用户下单,订单中心。这三个功能构成一个最简单的电商业务流程。</p>
<p>展示给用户看的商品页面以及用户购买商品的操作功能。那我们需要对用户和订单进行管理,怎么办?</p>
<p>就需要一个管理后台来对用户订单进行管理。如此简单分析过后,就知道了电商网站应用功能。</p>
<h4 id="应用功能架构图">应用功能架构图:</h4>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138264-1922362190.png" alt="image-20230124022153045" loading="lazy"></p>
<h4 id="程序架构设计">程序架构设计:</h4>
<p>这时候我们开发的单体应用程序,部署在应用服务器上。程序架构可能采用 MVC 这种程序架构模式。</p>
<blockquote>
<p>当然也有可能什么架构都不用,直接撸代码了,所有的程序都混合在一起,这就是所谓的“大泥球”单体,这是一种糟糕的开发方式。</p>
</blockquote>
<p>java 里最常用的 MVC 框架,比如 SpringMVC 框架。</p>
<ol>
<li>划分模块</li>
</ol>
<p>比如根据上面电商功能架构图,在程序里可以把电商功能划分为相对应的模块,如用户模块,订单模块,商品模块。</p>
<p>这时程序里不管是前台功能,后台功能都有这些模块。</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138206-1754121769.png" alt="image-20230124110006299" loading="lazy"></p>
<p> (应用程序模块)</p>
<p>这时候应用程序模块都在一个大的单体项目里,前台功能和管理后台共用一套代码。</p>
<ol start="2">
<li>模块里的功能</li>
</ol>
<p>比如前台商品模块,就有商品列表,商品详情页等页面功能。</p>
<ol start="3">
<li>程序开发</li>
</ol>
<p>编写程序时可能应用 MVC 这种程序设计模式来进行程序代码开发。</p>
<h4 id="程序部署架构图">程序部署架构图:</h4>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138232-951146321.png" alt="image-20230124122806802" loading="lazy"></p>
<p>编写的程序代码部署到应用服务器上,用户的所有数据存储到 MySQL 数据库里。</p>
<p>程序和 MySQL 都部署在同一台服务器上。</p>
<h2 id="二单体架构程序演进">二、单体架构程序演进</h2>
<h3 id="21-mysql-性能瓶颈-缓存">2.1 MySQL 性能瓶颈-缓存</h3>
<p>随着项目上线,公司对项目加大力度推广和运营,用户数越来越多。</p>
<p>有一天,用户投诉说,商品详情页面浏览好慢。如是你一番操作猛如虎,发现详情页显示慢,性能瓶颈出现在数据库 MySQL 上,</p>
<p>MySQL 在用户访问高峰时,扛不住那么大的访问量。这时你想到的解决方法,可以用缓存来缓存一部分数据,不必每次都到 MySQL 取数据,</p>
<p>可以用 Redis 来缓存部分商品信息数据。如是,增加一个 Redis 缓存,架构图如下:</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138194-1969961667.png" alt="image-20230124122020910" loading="lazy"></p>
<h3 id="22-mysql-读写分离">2.2 MySQL 读写分离</h3>
<p>这时候,你也可能想到另外的一种方法:数据的读写分离,减轻对 MySQL 访问压力。</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138221-235316130.png" alt="image-20230124122113934" loading="lazy"></p>
<p>经过上面 2 种措施改进后,商品详情页访问速度开始变快,访问正常了。</p>
<p>但是这种舒服日子没过几个月,又有用户开始反馈页面访问比较慢。</p>
<p>你又一番埋头辛苦分析,发现是单台服务器负载高,单台服务器的性能已经到了极限,它已经承载不了那么多用户的访问。</p>
<p>如是你想,把数据存储和应用程序部署到 2 台服务器上,减轻服务器的负载压力。</p>
<h3 id="23数据存储和应用程序服务器分离">2.3:数据存储和应用程序服务器分离</h3>
<p>于是你申请买了一台服务器,把 MySQL 和 Redis 都部署在这台新买的服务器上,让原来那台服务器负载得到缓解。</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138243-938554941.png" alt="image-20230124122240609" loading="lazy"></p>
<p>新的架构部署成功后,用户访问页面又恢复正常。</p>
<p>但是随着业务发展越来越好,新增用户越来越多,应用服务器的负载又居高不下了。</p>
<p>这时候要增加新的应用服务器了,这样做是最简单的。多台应用服务器形成集群,那怎么访问这些应用服务器?才能使每台服务器负载保持平衡,或者性能好的多接受一些用户访问?这时候就要用到负载均衡了。</p>
<h3 id="24-集群-分布式">2.4 集群-分布式</h3>
<h4 id="集群-负载均衡多台应用服务器">集群-负载均衡(多台应用服务器)</h4>
<p>部署多台应用服务器形成一个应用服务器集群,前面用户通过负载均衡器来进行服务的访问。</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138745-541706211.png" alt="image-20230124124859989" loading="lazy"></p>
<p>比较常用的负载均衡软件有 Nginx、LVS、KeepAlived 等等。</p>
<p>还有硬件负载均衡,比如 F5 等。</p>
<p>部署后,页面访问又恢复了正常。</p>
<p>过了几个月,数据服务器也出现负载过高情况,这时候可以把 Redis 缓存和 MySQL 分离,部署到不同服务器上。</p>
<p>随着数据量增加,把 Redis 部署为分布式缓存。</p>
<h4 id="数据库分离和-redis-分布式缓存">数据库分离和 Redis 分布式缓存</h4>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138692-209459449.png" alt="image-20230124130955865" loading="lazy"></p>
<p>把 MySQL 和缓存 Redis 部署到不同的服务器上。</p>
<p>随着缓存数据的增多,Redis 也部署为主从模式,然后到 Redis Cluster 集群模式,也就是 Redis 的分布式缓存。</p>
<p>此时数据存储服务器负载得到缓解,访问恢复正常。</p>
<p>由于业务发展太快,用户变得更多,数据库又出现了性能瓶颈,这时可以对数据库进行分库分表</p>
<h4 id="分库分表">分库分表</h4>
<p>为了进一步的降低数据库由于数据量太多,访问太大而造成的瓶颈,可以对数据库进行分库分表,减轻数据库的访问压力。</p>
<h4 id="搜索分离">搜索分离</h4>
<p>把搜索独立出来,用 Elasticsearch 进行全局搜索处理。</p>
<h4 id="分布式文件存储">分布式文件存储</h4>
<p>使用 HDFS 进行分布式文件存储。<br>
对象存储、块存储、文件存储 Ceph。</p>
<h2 id="三应用程序发展演进">三、应用程序发展演进</h2>
<h3 id="31-应用程序功能变化-硬件发展">3.1 应用程序功能变化-硬件发展</h3>
<p>上面画的架构图都是后端技术部分,服务端架构从单体到集群再到分布式的演进。</p>
<p>那么前面给用户使用的应用程序呢?也是在变化之中。</p>
<p>比如在《淘宝技术这十年》里的淘宝网的发展变化,刚开始时是一个很简单的 PC 端页面,到后来随着手机普及,移动互联网发展起来,</p>
<p>手机应用就出现了。淘宝 APP 也随之出现。随着国民应用微信逐渐发展壮大,小程序也成为第三种互联网程序应用形式。当然,还有其它终端,比如平板 ipad,自动售货机等等各种终端。</p>
<p>上面是不同硬件出现,程序应用承载出现不同形式。</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138711-21976372.png" alt="image-20230124185223955" loading="lazy"></p>
<p> (多终端用户出现后的架构图)</p>
<p>那么淘宝网的功能呢?当然增加了很多。</p>
<p>还孵化出了多种不同的业务应用,比如天猫,1688,支付宝,聚划算,淘宝旺旺等等很多应用。</p>
<p>在今年 2013.1 再去打开淘宝 APP 看看,里面的功能多到眼花缭乱。</p>
<p>现在的电商系统有哪些子系统,系统里都有啥功能,可以看看我之前发布的这篇文章。</p>
<h3 id="32-多端程序单体架构">3.2 多端程序单体架构</h3>
<p>多种终端的出现,当然不是一下子就出来的,都有一个发展过程,只不过到写这篇文章为止,出现了上面说的PC,手机 APP、小程序,平板等多个终端,最常用的还是前面 3 种。</p>
<p>最开始开发程序时,应用程序要适应多个终端,最简单的方式就是拷贝 PC 端的代码到多个终端程序里。按照上面 1.2 小节的电商最简单业务功能模块实现,多终端应用程序功能架构如下:</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138647-122201280.png" alt="image-20230124193811484" loading="lazy"></p>
<p> (后端功能模块架构图)</p>
<p>上面的三种终端程序应用,还是使用同一个 MySQL 数据库,也及是说订单数据、用户数据等都存储在一个库中。</p>
<p>可能会问,怎么区分订单来自哪一个终端?</p>
<p>可以给订单数据一个类型标识来进行区分,订单是从哪一个终端过来的。</p>
<p>那管理后台呢?</p>
<p>多终端程序可以共用一个管理后台。</p>
<blockquote>
<p>多终端的后台功能模块都搞起来了,但是这种程序模块架构有什么弊端缺点呢?</p>
<ol>
<li>代码重复</li>
<li>增加/修改功能复杂:比如说要修改一个订单模块的功能,需要修改 3 个终端的后台代码</li>
<li>代码维护复杂:每次维护代码都需要动 3 个后端的代码</li>
</ol>
<p>那有没有办法可以改进上面所说的情况?</p>
<p>能不能把 3 个后端重复模块代码合并为一个,统一向前端提供服务,当然是可以的。怎么做?</p>
<ol>
<li>前后端分离 - 把前后端代码进行分离,前端展示操作页面和后端功能模块分离</li>
<li>抽象公共模块 - 把多个后端公共模块进行抽象为一个模块,为前端提供统一服务</li>
</ol>
</blockquote>
<h3 id="33-前后端分离抽象公共模块">3.3 前后端分离,抽象公共模块</h3>
<p>页面前后端分离,其实在上面 1.1 小节的单体架构中也可以这样实施前后端分离。</p>
<p>多个终端当然也可以进行前后端分离,这样不用开发多个终端的页面,程序代码进行适配就可以了。前端现在有很多种多终端适配的技术。</p>
<p>后端的多个相同功能模块进行抽象,变成一个共用模块,对外提供服务。</p>
<p>这种方式提供功能服务我想到的有 3 种方式:</p>
<h4 id="第一种单体结构-函数提供接口">第一种:单体结构-函数提供接口</h4>
<p>后端还是在一个单体工程下面,但是公共功能抽象为一个函数或对象接口,对外提供服务。</p>
<p>后端其他模块引入这个模块然后调用函数或者对象,完成程序功能开发。</p>
<p>应用程序结构图如下:</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138627-1080305814.png" alt="image-20230124225610407" loading="lazy"></p>
<h4 id="第二种用-maven-当作一个远程包引入">第二种:用 Maven 当作一个远程包引入</h4>
<p>在 java 里,用 maven 可以引入一个远程包进行使用。我们可以用这种方式引入公共功能包。</p>
<p>在 Go 里,用 module 模块方法引入远程包使用。</p>
<h4 id="第三种rpc-方式调用">第三种:RPC 方式调用</h4>
<p>这种方式是把应用程序里的公共模块功能变成一个独立的服务,对外提供服务。这个”外“是公司内部的业务可以调用这个服务。公司以外的应用就不可以调用这个服务。</p>
<p>这里也有2种方式,</p>
<p>第一种:只是公共模块独立提供服务,数据库还是共用。</p>
<p>第二种:数据库随着公共模块一起,独立对外提供服务。</p>
<p>我们来讨论第二种情况,既然要作为一个独立的服务存在,它就是自适应自维护的,此时数据库变成独立数据库,跟着它的服务模块一起独立。</p>
<p>此时不仅应用模块进行分离,应用服务器也进行了分离。</p>
<p>这时候就有点微服务的味道了。</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138651-689472753.png" alt="image-20230124233108779" loading="lazy"></p>
<h2 id="四微服务架构演进">四、微服务架构演进</h2>
<h3 id="41-架构宏观演进单体-soa-微服务">4.1 架构宏观演进:单体->SOA->微服务</h3>
<p>架构宏观演进如下图:单体->SOA->微服务->serverless</p>
<p><img src="https://img2024.cnblogs.com/blog/650581/202405/650581-20240524225538628-3988166.png" alt="image" loading="lazy"><br>
(来自:blog.bytebytego.com)</p>
<p>有的人认为上面这张架构演进图少了一部分,对业务按照功能进行垂直划分,也就是对大单体应用划分为小的应用,这一架构变化,如是有下面这张架构演进图:</p>
<p><img src="https://img2024.cnblogs.com/blog/650581/202506/650581-20250611014549593-831657714.png" alt="image" loading="lazy"></p>
<blockquote>
<p>现在 SOA 架构已经很少使用了,应用拆分之后,如果服务越来越多,慢慢就进化到微服务架构了。</p>
</blockquote>
<p>对于微服务的了解,可以看看我前面关于微服务系列文章的讲解,比如下面文章:</p>
<ul>
<li>微服务架构学习与思考(03):微服务总体架构图解</li>
<li>微服务架构学习与思考(04):微服务技术体系</li>
</ul>
<p>微服务的技术架构实际是一个体系,它是由很多技术组成的。</p>
<h3 id="42-以-springcloud-和-golang-为基础的微服务技术体系">4.2 以 SpringCloud 和 Golang 为基础的微服务技术体系</h3>
<p>下面重点说说 SpringCloud。</p>
<p>最开始最 netflix 公司开源的以 springcloud 为基础的微服务技术体系,它把微服务体系开源了。不过后来 netflix 放弃维护它开源的微服务框架。</p>
<p>但是 spring 框架的公司和阿里巴巴都开源了自己的以 springcloud 为基础的微服务体系,阿里巴巴叫 springcloud-alibaba。</p>
<p>阿里还开源了另外一个微服务框架 dubbo。</p>
<p>这些框架都提供了一些主要功能:服务发现和注册,限流熔断,链路追踪,RPC通信,网关等功能。</p>
<p>SpringCloud 微服务体系有哪些缺点?</p>
<ol>
<li>代码侵入性强 - 业务层中需要加入治理层代码,与治理层混淆在一起</li>
<li>组件多 - 组件多,学习成本就变高</li>
<li>治理功能不全 - 比如协议转换、动态请求路由、灰度发布等功能</li>
<li>无法实现语义无关性 - 只能是一种语言或几种语言实现,无法做到与编程语言无关</li>
</ol>
<p>针对以上的一些问题,就出现了 Service Mesh 这种架构,它作为一个基础设施层,真正做到与业务解耦,与语言无关,解决复杂架构下微服务应用与微服务应用之间网络相关问题。</p>
<p>其实就是把网络相关功能拆分出来,与业务系统解耦。</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202306/650581-20230602113009682-1481687931.png" alt="image" loading="lazy"></p>
<h3 id="43-service-mesh">4.3 Service Mesh</h3>
<p>Service Mesh 解决复杂系统架构下微服务应用与微服务应用之间网络相关问题,它的实现形态一般为轻量级的网络代理,以应用以边车(SideCar)模式部署。</p>
<h4 id="第一代servicemesh">第一代ServiceMesh</h4>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138685-2139822263.png" alt="image-20230125001047147" loading="lazy"></p>
<p> (from:https://philcalcado.com/2017/08/03/pattern_service_mesh.html ,Phil Calçado)</p>
<p>来看一个全局图:</p>
<p> <img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138613-1576292024.png" alt="image-20230125001700722" loading="lazy"></p>
<p> (from:https://philcalcado.com/2017/08/03/pattern_service_mesh.html ,Phil Calçado)</p>
<p>绿色:应用服务</p>
<p>蓝色:SideCar</p>
<h4 id="第二代-servicemeshistio">第二代 ServiceMesh:istio</h4>
<p>第一代 Service Mesh 是由独立运行的单机服务代理构成,为了提供统一的控制入口,演进出了统一的控制面板,称为 control plane。</p>
<p>控制面板(control plane)和数据面板(data plane,即边车代理)进行交互,比如策略下发、数据采集等。这就是以Istio为代表的第二代Service Mesh。</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004138696-2108022632.png" alt="image-20230125002338290" loading="lazy"></p>
<p> (from:https://philcalcado.com/2017/08/03/pattern_service_mesh.html ,Phil Calçado)</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004140155-1034342437.png" alt="image-20230125002415442" loading="lazy"></p>
<p> (from:https://philcalcado.com/2017/08/03/pattern_service_mesh.html ,Phil Calçado)</p>
<p>Istio架构,Istio 服务网格从逻辑上分为数据平面和控制平面:</p>
<p><img src="https://img2024.cnblogs.com/blog/650581/202406/650581-20240601185403645-731111602.png" alt="image" loading="lazy"><br>
(from:https://istio.io/)</p>
<p>springcloud 与 ServiceMesh 的区别:</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202301/650581-20230125004450863-360256445.png" alt="image-20230125002930584" loading="lazy"></p>
<p> (from:https://medium.com/codex/a-spring-cloud-compatible-service-mesh-6ce58c571012)</p>
<h3 id="44-kubernetesk8s">4.4 kubernetes(k8s)</h3>
<p>一图解千言</p>
<p><img src="https://img2023.cnblogs.com/blog/650581/202305/650581-20230531210315282-60602313.png" alt="image-20230529194906925" loading="lazy"></p>
<p>(来源:redhat blog:spring-cloud-for-microservices-compared-to-kubernetes, Bilgin Ibryam )</p>
<hr>
<p>第1次更新日期: 2023.05.31<br>
第2次更新日期: 2024.05.25 增加单体到微服务架构演进图</p>
<hr>
<blockquote>
<p>大家可以到俺公众号继续讨论:九卷技术录-从单体架构到微服务架构的演进历程</p>
</blockquote>
<hr>
<h2 id="五参考">五、参考</h2>
<ul>
<li>
<p>https://philcalcado.com/2017/08/03/pattern_service_mesh.html Pattern: Service Mesh,详细介绍了微服务到 Servie Mesh的演进</p>
</li>
<li>
<p>https://medium.com/codex/a-spring-cloud-compatible-service-mesh-6ce58c571012</p>
</li>
<li>
<p>https://www.cnblogs.com/jiujuan/p/14452748.html 《电商产品设计全攻略》读书笔记</p>
</li>
<li>
<p>https://www.cnblogs.com/jiujuan/p/13301055.html 微服务架构学习与思考(04):微服务技术体系</p>
</li>
<li>
<p>https://developers.redhat.com/blog/2016/12/09/spring-cloud-for-microservices-compared-to-kubernetes Spring Cloud for Microservices Compared to Kubernetes,(redhat blog,Bilgin Ibryam)</p>
</li>
<li>
<p>https://istio.io/</p>
</li>
</ul>
</div>
<div id="MySignature" role="contentinfo">
== just do it ==<br><br>
来源:https://www.cnblogs.com/jiujuan/p/17066590.html
頁:
[1]