小强开饭店-从单体应用到微服务
本篇博客通过小强开饭店的通俗易懂的故事,带你了解后端服务是如果从单体应用演变到微服务的。如果有说的不对的地方,欢迎各位大佬强势怼。
小强开饭店
有一天,小强为了早日奔赴小康生活,打算开一个饭店来帮他快速的实现这个目标。
饭店开业了
于是他盘下了一个店面,一顿装修之后,雇了一个厨师,便开业了。
饭店生意变好了
刚刚开业那段时间还好,店里的人虽然多,但是都还能应付的过来。
小强请的厨师手艺很好,再加上小强经营得当,宣传的也不错,慢慢的店里的生意越来越好。
慢慢的,顾客越来越多。很多时候厨师都忙不过来,大家只有排队在外面等着。渐渐的有些顾客变得十分不耐烦,等不下去了就走了,然后给了这家店差评。这种情况愈演愈烈,小强看到这不是个办法啊,得做点什么。
招聘厨师
小强下了血本,又另外聘请了几位厨艺很好的厨师。
有了这些厨师的加盟,虽然客人很多,饭店的经营也还是能够勉强的应付的来。口碑也慢慢的由差变好。随着口碑的变好,慕名而来的也随之越来越多。
生意火爆
随着顾客越来越多,即使厨房的厨师已经招聘满了,都还是应付不过来。
于是厨师也变成了暴躁的厨师。有的时候因为太忙了还罢工不干了。还得小强去苦口婆心的劝。小强心想这也不是个办法,再这么下去口碑又得下去。于是小强摇身一变,变成了强老板。
强老板开了分店
强老板拿着开饭店赚的钱,在城里的很多地方开了分店,十分的膨胀。这样一来,客人不用大老远的跑到那一家店去了,可以选择离自己近的店。很快,原来的那家生意也渐渐的恢复正常,各个分店的业绩也有所提高。
但是随着强老板的强势宣传,以及顾客之间的自传播,这个参考被越来越多的人知道了。但是由于顾客分散,每家店的火爆程度都不同。有的店甚至陷入了跟最开始的店一样的境地,大量的顾客排队。但是有的店的生意却又十分冷清。
强老板心想,这肯定不行啊,这样下去早晚得血亏。于是强老板摇身一变,变成了强总。
强总开了个顾客中心
所有想去餐馆用餐的顾客都来这里,由强老板统一安排的大巴再送至各个分店。每辆车轮流的送至每一家分店。这样一来,就不存在某一家分店生意十分火爆而另外的店生意惨淡的情况了。
强总已达成奔赴小康的目标
读后感
其实这个想法是很久以前不知道在哪儿看博客的时候,看到一位大佬的类比,确实是忘了。而最近刚好在准备分享,所以就打算详细的以图文和故事的方式来让没有了解过这方面的人快速的了解一下。
其实我也纠结过要不要将里面类比概念的解释穿插到故事里,但是后面想了一下,这样应该会干扰到大家对故事本身的理解,从而达不到通俗易懂的效果。所以我将解释单独放在了最后面。
单个饭店
最开始的单个饭店其实就是一个App或者一个网站,来给用户提供服务。可以理解为前端,或者客户端。
单个饭店的厨师
而单个饭店中的厨师,其实就是后端,提供数据,提供服务。一个厨师就对应着一个后端服务的实例。
随着App的访问量越来越大,最初的单体应用已经无法扛住这么大的压力了。导致其他的用户进入系统时,系统无法正常的服务。就跟我们现在打开一个网站一样,凡是超过2-3秒没有反应就直接宣告它的死刑了,直接退出-卸载二连。
单个饭店的多个厨师
多个厨师则是相应的后端服务启动了多个实例,每个实例都是完全一样的,只不过是运行在不同的机器上或者不同的端口上。
每次的请求由这些实例来均摊,这样也的确能够暂时解决访问量大的问题。但是维护起来十分的麻烦,部署的流程也很繁琐。每次部署你得更新所有的实例,万一数量多,又在不同的机器上,很有可能因为操作失误引发线上的事故。而且有可能让老版本的服务兼容新版的前端或者客户端,造成不必要的BUG。
再退一万步,就算所有的实例都在同一个服务器上,万一真的访问量到了一定的量级,你得维护多少个实例啊。人工成本巨大。而且一不小心,一觉起来,本身没有问题的服务,因为一晚上发生了事件引发了热点,导致你的应用访问量剧增,增到超过你的所有实例能够承受的极限,服务挂了。
再退一万万步,就算你自己维护没有烦死,前端的兄弟可能早就收拾你了。你没有做请求分发的话,所有的服务器地址得由前端去维护。
分店
这里的分店指微服务中的一个服务的多个实例。与之前人工维护的多个实例不同,这个是由工具帮我们维护。
这里我拿Docker Swarm举个例子。在Portainer中,你新建了一个服务之后可以选择设置Replicas,也就是实例的数量,当然默认是一个。你可以起10个,20个,但是这里得考虑到你的服务是否支持这样做。如果你的服务不是无状态应用,就很难做到可以自动的做横向扩展。
分店的生意火爆
其实也是一样的,即使有很多个实例,你如果不能控制请求打到哪个服务上的话,某些实例承受的压力大了一样的会挂。
强总的顾客中心
顾客中心大家可以理解为网关。更具体点可以理解为Zuul。
你的服务有了网关之后,所有的请求都从网关走。根据以及配置的路由,网关可以判断到你想具体到哪个服务去。
然后就会从自己的服务集群中找到对应的服务,获取到所有的服务实例的服务器IP以及端口。前面说到有可能请求会集中到某几个实例上。而我们可以使用工具来解决这个问题。例如,使用Spring Cloud的核心组件Ribbon。
这个组件的作用是做负载均衡,它可以使所有到某个服务的请求,平均的分发到该服务的每个实例上去。从而避免某几个服务的请求超过其能承受的阙值。当然,Ribbon需要和Spring Cloud的其他核心组件相互协作的。
另外一个版本的故事
小强搞了个新闻App,用Spring Boot搭了一个后端,找人用React Native写了个App,就这样上线了。因为其内容和推广都还不错,所以受到了用户的喜爱。
但是随着访问量越来越大,服务器渐渐扛不住压力。有的用户进App之后甚至要5-6秒才有反应,而且慢的出奇。于是小强开始给服务尽量的无状态化,然后在一个服务器上启动了几个实例。
一段时间之后,访问量又增大了。小强只好硬着头皮,继续加实例数量,你强任你强,加实例我在行。
有一天,小强一觉起来,发现服务炸了...啊不是,是挂了。因为发生了一些事情引发了巨大的社会舆论,App的访问量剧增。导致新加的实例也没能扛住。
就这样,小强老实的开始了重构。使用Spring Cloud搭建了一个微服务集群,把服务拆分之后,给每个服务启动了几个实例。同时使用Eureka和Feign来进行服务之间的通信,使用Ribbon来做负载均衡。
就这样,这个App暂时稳定了下来。不过还有很多事情可以继续去做。
参考:
往期文章:
- 什么?你竟然还没有用这几个chrome插件?
- 手把手教你从零开始搭建SpringBoot后端项目框架
- 用go-module作为包管理器搭建go的web服务器
- WebAssembly完全入门——了解wasm的前世今身
相关:
- 个人网站: Lunhao Hu
- 微信公众号: SH的全栈笔记(或直接在添加公众号界面搜索微信号LunhaoHu)