这篇博客的本意是希望看到这篇文章的读者能够很轻松的理解我想表达的意思。但程序向的分享经常会不经意间就贴上了代码,很可能就会让人看的很懵。而且我认为分享一个东西,只有对方真正明白了其中的逻辑,才是有意义的分享。所以接下来我会尝试用大家都能理解的语言来聊一聊”微服务“。
【写在前面】
那么,什么是微服务呢?你不一定知道微服务,但是你一定知道麦某劳,而且知道麦某劳有个甜品站。你可能会问,甜品站和微服务有什么关联呢?
让我们先假设不把甜品站独立出来,而是普通的麦某劳店。经营一段时间你会发现,这个地方虽然人流量很大,也有顾客,但是顾客的需求80-90%都集中在甜品,导致甜品供不应求,而其余的菜品则没多少人购买。但是把这个店关了吗?那也不行,始终是有流量的。
所以综合考虑下来,方案就是把甜品这个“模块”从整个店中独立出来,单独对外提供服务。这样既能保住流量,也能避免浪费。
微服务也是一样的,比如电商的服务,假设里面耦合了商品、库存、订单、用户的服务,但是订单这个模块可能会访问的特别频繁,而用户和商品被访问的频率没有那么高,如果为了同时给更多用户提供服务,而再部署一个包含了商品、库存、订单和用户的服务,有两个模块的资源其实没有被充分利用到。跟甜品站的思路是一样的,如果把商品、库存、订单和用户分成四个服务模块,每个服务只负责处理的自己的事情,就像甜品站只卖甜点一样,如果订单的访问量大, 那也只需要再部署一个订单的模块,而不会造成资源利用不充分、耦合性强的情况。
最开始的“整家麦某劳”店对应的概念就是单体应用,后面独立出的“甜品站”就是从单体应用中抽离出的“微服务”。不知道什么是单体应用和微服务是什么没关系,不知道单体应用为什么、以及如何转变成微服务的也没关系,让我们通过一个故事来完整的理解这个概念。
假设正在阅读这篇文章的你,拥有一家饭店。
0.【梦开始的地方】
你盘下了一个店面想卖炸鸡和甜品,于是你简单的把店装修了一下,购置了相关的设备,然后雇了厨师、服务员等相关的工作人员,就开始挂上招牌对外营业了,
0.1 店面
就是我们平常去使用的各种C端产品,如果你没有一个概念,那么可以直接把它理解成钉钉、微信这样一个我们日常都在用的APP就好,它们就是C端产品。
店的招牌(比如肯打鸡和麦某劳)就可以理解为我们平常APP里所能看到的,所能使用的东西,我们叫它客户端。
整个实体店就可以理解为开篇提到的“单体应用”,为客户提供实际的服务。
0.2 装修和购置设备
对应的是我们的开发团队,从产品经理接到客户的需求开始,根据需求整理好原型图,不停的跟客户沟通交流细节,反复的修改原型图,最终定下来的需求。
然后我们的UI同学介入,根据原型图出UI图,并最终确定下来。然后就是前端和后端的开发同学根据原型图中的逻辑,和UI图的样式细节开始迭代开发,并最终将产品上线。
0.3 炸鸡和甜品
有了前面麦某劳的例子,这个应该很好理解。炸鸡和甜品其实就是作为一个C端产品,提供给用户的不同种类的服务。
例如我们日常在用的钉钉,可以用来聊天、开视频会议和预定会议室。
1.【渐入佳境】
随着你不断的推出新的菜品,以及分量足,性价比高,朋友之间口口相传—“那家苍蝇馆子还可以”,也留住了大量回头客。慢慢的,来店里吃饭的客人越来越多,后厨渐渐忙不过来了。很多慕名而来的客人由于等了太长时间仍然没有上菜,更有甚者连座位没有。客人对美食的渴望转化成了失望和愤怒,于是反手就是一个超级差评。
1.1 不断的推出新的菜品
代表我们的产品迭代,不断的推出新功能,以此来为用户提供更多元化的服务,吸引更多的用户来使用我们的产品。例如疫情期间,钉钉在在线学习这块推出了很多新的功能。
1.2 朋友间的口口相传
则代表的是部分用户开始代替广告这种传播途径,开始了社群内的用户自传播。这是很多产品都想达到的目的,把产品的潜力挖掘到极致,让产品说话,为自己代言。
比起漫天飞的广告,这种来自朋友们的推荐,更加受到用户的信任。
1.3 关于差评
“后厨忙不过来”是指用户数量上涨,日常的请求数就会随之增多,而单个服务实例在某个时间单位内能够处理请求的数量是有限的(也就是后厨人数有限,就那么几个厨师,能做的菜数量也有限),这也直接导致了部分用户请求十分缓慢,甚至直接无法访问(后厨实在忙不过来了,有些客人就要等很久)。而用户对于产品的耐心是十分有限的,出现这种情况会导致部分甚至大量用户流失。
2.【蜂拥而至】
随着差评越来越多,你渐渐坐不住了。你觉得再这么下去你可能就要凉了,于是你想,厨师不够用那就多招几个嘛,于是雷厉风行的你贴出了招聘启事,然后顺利的招到了人。
人的问题解决了,那还有座位的问题。之前你没有想到会有这么人多来光顾,所以店里面的桌子和椅子摆的很宽松,但是实际上重新规划一下,还是能够多放好几张桌子的,这样一来就能够同时容纳更多人在店里用餐。
2.1 多招人
我们每个服务所能使用的资源是有限制的,例如你可以给你的JVM设置最大堆内存为1G,也可以加到2G。啊?什么是JVM?不重要,让我们重新理解前面一句话。2个厨师一分钟可以做5个菜,你转手再招2个厨师,那一分钟就可以做10个菜,这对应的概念是扩容,也就是增加服务器能够支配的运行资源,服务器就能够处理更多的请求,服务更多的用户。
这里的扩容是针对CPU和内存
2.2 重新规划桌椅摆放
刚开始开发时没有到用户会有这么大体量,所以大部分的API没有做什么优化,整个服务端应用的框架也搭建的很随意,因为上线的时间很紧,这可能会造成应用在维护性、扩展性和性能上的弊端。
通俗点来说就是,当时为了店里摆放好看,追求ins风,桌椅之间摆的太宽了,但是后来人多了,外面一堆人排队,店里面却熙熙攘攘,但是实际上你却是已经“坐满了”。
这种情况十分不利于后续的迭代的。所以对应到开发中的概念就是,对代码和框架进行重构,优化算法,让API尽量少占用系统资源,降低响应延迟,从而提高整个服务的服务能力。这样一来,服务实例就能扛住更多的请求。
不过有的时候,降低延迟和少占用系统资源不可兼得。如果对响应速度要求很高,就可能会多占一些系统资源,用空间来换时间。就像你把店里重新摆放了,店里容纳的人多了(占用资源多了),这个时候服务的响应时间可能就会变慢(上菜就会变慢),那么用空间换时间是什么呢?就是你会提前准备很多食材、甚至是半成品的食材堆在那里,这样以来,只需要花平时一半的时间就可以把菜做好(比如提前准备好熟油,各种辅料等等)。
3.【山穷水尽】
虽然多招了几个厨师,也重新规划了店里桌椅摆放,但是随着时间的推移,每天来店里吃饭的人还是越来越多,厨师已经不能再招了,已经没有那么多灶台了。之前的“差评热潮”又开始在店里上演。你想着,虽然店里火爆是好事,但是每天有那么多的人来店里看到没有位置就走了,这不是有钱赚不了吗?
而且很多目标用户在第三方网站上看到了这些差评,将会直接影响到客户是否愿意来店里,这会使你丧失大量的隐藏客户。于是你开始了轰轰烈烈的开分店业务,在附近又开了一家店。还是一样的配方,就是这个味~
3.1 开分店
开分店对应的概念是多实体部署,就是把一个同样的服务再部署一个,这样一来来自用户的流量就从一个服务扛变成了两个服务扛。
分店就可以把原本要把总店塞爆的流量给接过去,缓解了压力。
4.【柳暗花明】
随着时间的推移,分店越开越多,生意自然也是蒸蒸日上。但是你作为一个能够不只看表面的布局者,你发现了实际上的情况并没有表现出来的那么好。
有些区域人流量大,而有些区域虽然人流量大,但是对店感兴趣的人不多,甚至分店周围根本没有什么人。而有些地方的分店则异常火爆。虽然热门的店赚的钱能够抵上冷门的店的亏损,但是追求完美的你认为这种情况必须要得到改善,因为这始终是存在对资源的浪费。
所以经过一番调研,你决定在中心区域开一个顾客中心,所有想来餐厅的人都统一的来顾客中心,由顾客中心的人根据各个分店的火爆情况来分批次的把顾客送过去。这样一来,也就解决了有些店火爆,而有些店冷清的情况了。
4.1 人流量分布不均匀
这种情况主要发生在服务端运行了多个实例,那也就对于多个IP地址,而要调用哪个是由客户端来决定的,如果设计的不够好,就会出现某些时候某些实例成为热点实例,甚至出现“差评”实例这种情况,而其余实例则没有承担多少来自用户的流量。
说人话就是,我要是顾客,我去哪家店不是看我心情吗?我想去哪家店就去哪家店。当然实际情况没有这么夸张,客户端会有自己的策略。
而且同时维护如此多的服务端地址也是很麻烦的一件事,如果服务端此时又增加了实例,客户端则需要同步的更新。但是如果用户体量大的话,因为这种问题频繁的发包让用户更新,会对用户造成不好的体验。
4.2 顾客中心
这个比喻有些夸张,现实中有人这么干可能早破产了。“顾客中心”就是我们说的“网关”。有了网关,客户端就不用关心服务有多少个实例,也不用去维护所有的HOST,所有的请求直接从网关走,由网关来决定将当前请求分发到哪个实例。
“客户中心分批次根据情况送顾客”其实对应到的概念是负载均衡,什么意思呢?就是要让客户端产生的流量对所有实例雨露均沾。其实现的方式也有很多,大致分为随机、轮询、一致性哈希、加权等等。
而网关除了负载均衡,还有很多其他的特性。例如,动态的路由、限流、认证、日志、熔断、可编程插件配置等等。
5. 【微服务的关注点】
看完了这个故事,你可能会觉得没有什么,但是实际上你已经了解了一个应用从单体应用架构转为微服务的架构生命周期以及过程。这其中也包括为什么需要转为微服务架构,和转到微服务架构的好处在哪里。如果你都没有意识到自己理解了这个概念,可以再阅读一遍上面的小故事。
其实实际上的微服务要比上面故事所呈现出来的复杂很多,微服务中需要关注的点要比传统的单体应用多的多。在微服务中我们需要关注服务的发现、负载均衡,统一的配置管理,微服务集群的自愈和弹性伸缩,服务的调度和发布,微服务中的调用链监控,包括Metrics监控,日志监控,服务的安全考虑,API的统一管理等等。
首先把强耦合在一起的代码有条理的拆分出来就是一件很复杂的事情,微服务的划分粒度也是一个很大的挑战。例如很复杂的系统,一个用户服务的代码可能有好几千上万行,但是它仍然是一个微服务,没有再拆分用户服务A和用户服务B。而有的服务可能代码量只有几百行,这需要根据实际的业务情况来选择划分的粒度。
除了拆分服务的粒度,微服务本身还有很多组件。大家在故事中只了解了网关。其实还有很多组件。
服务发布就涉及到Jenkins,把我们的应用打包成Docker Image,然后通过自动化工具发布到对应的环境中。我们的应用跑在Docker中,那么我们就需要有一个容器编排工具来管理这么多容器。例如我们现在使用的就是Docker Swarm,跟业界现在流行的Kubernetes一样,有很多人在使用。
有了容器编排工具,就有工具的可视化界面,Docker Swarm对应的Portainer,和Kubernetes对应的Rancher。除此之外我们还要使用Gitlab来做我们的代码版本管理工具,MySQL和MongoDB作为数据存储的解决方案。Redis作为缓存的解决方案。同时需要有一个地方来统一管理所有服务的配置,我们叫微服务的配置中心。
除此之外,服务之间要相互调用就必须要知道对方的地址,就需要一个注册中心,来保管所有服务的地址,并及时的更新服务的状态。
还有很多细节,例如如何去构建一个Jenkins的构建流水线,如果实现一套CI/CD的流程,如果使用ELK去做统一的日志收集,如果在集群内实现SSO啊等等,由于篇幅原因就不在此一一赘述了。
【The End】
如果大家对微服务感兴趣可以下来详细的沟通,也可以去多了解了解Spring Cloud、Dubbo或者Kubernetes,尤其是Kubernetes,我个人认为这一定是未来微服务框架中的中流砥柱。
如果你觉得这篇文章对你有帮助,还麻烦点个赞,关个注,分个享,留个言也可以微信搜索公众号【SH的全栈笔记】,当然也可以直接扫描二维码关注
往期文章
拜了个拜
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。