瞎扯淡 从上帝视角看微服务

early · December 14, 2018 · Last by early replied at March 05, 2019 · 5764 hits
Topic has been selected as the excellent topic by the admin.

微服务是近年来异常火爆的概念,是 Web 领域极具话题性的方向,无论是出于好奇还是学习,都得踏入一只脚试试水,睁开双眼,窥其本质。

what

要想知道微服务是什么,解决什么问题,追根溯源,不得不先关注它生长的土壤环境: 移动互联网时代

移动互联网已经驰骋近 10 年,掀起了翻天覆地的变化。因为它的蓬勃发展,现今网民的比例已经非常之高,互联网载体对于人的时间占用已经接近极限。在这样的背景下,互联网公司一般有如下特点:

  • 数据量大
  • 访问量高
  • 竞争激烈

为了在上述背景中更好地存活,互联网公司面有两个有些矛盾的需求:

  • 应用必须具有高度的稳定性(服务高度可用)
  • 应用需要有快速的迭代更新能力 (效率)

需要在高速的增长过程中,应对疯狂增长的流量与数据,需要极力避免服务器瘫痪等不可用的现象。

同时,也要保持高度的嗅觉,以最高的效率调整产品特性,并部署到线上。(部署很可能导致服务故障)

这两个需求在产品规模到达一定程度时,几乎成长为两个互斥的点。要解开这个结,就必须在产品的工程化实施过程中,同时保证稳定性与效率,而这并不简单。

挑战来自三个方面:

  • 应用规模增长导致其本身复杂度极速提高(服务器和产品模块)
  • 应用访问量数据量增长导致稳定性下降,特别是单体应用一损俱损(服务器)
  • 人员规模增长导致协作效率急剧下降(沟通和分工)

这可以进一步解释为三大瓶颈:

  • 计算机的处理能力瓶颈
  • 人处理熵的瓶颈
  • 单个应用的容量瓶颈

要避开这些瓶颈解决上诉难点,达到高度稳定、高效率的目标,就得引入新的,理念级别的解决方案,而微服务就是这样的一种方案。

要达到上面的目的,微服务必须具备以下两项作用:

  • 减熵,也就是转移复杂度(降低复杂度)
  • 解耦,降低人或模块之间的相互影响

减熵主要是通过复杂度转移来实现。把一个复杂度高度集中的应用砍成多个小的模块,每个模块尽量独立,形成一个模块群。这样每个小模块的复杂度会远小于原来的应用,也将原来的集中的复杂度,部分转移到了模块群,将内部相互影响的复杂度转移到网络调用等等,实现复杂度的分而治之

在微服务理念中,将大模块砍成小模块的的核心思路是以服务的维度。每个复杂的应用其实都是由多个模块拼接而成的,每个模块或多或少都有一部分核心的职责。以服务的维度来拆分这些模块,核心就是:

  • 以服务的视角将各个模块归类
  • 清晰划分各个模块的职责
  • 各个模块通过网络调用进行通信(拆分前是内部调用)

通过以服务为单位进行拆分,会引导出两个极具价值的结果:

  • 技术减熵。技术人员可以专注于一个个模块,用合适的工具 (语言) 逐一击破。同时避免同一件事被各个模块重复做
  • 协作减熵。产品研发团队可随着服务进行对应拆分,人员螺丝钉化,各自专注于独立的点,提高小团体间协作效率

到这里,可以简单总结下复杂度的转移结果。服务化拆分其本质上是将高度集中的复杂度打散,分而治之,其中复杂度分别存在于产品技术实现团队协作两个维度。

其结果是:

  • 复杂度被打散,各个独立模块复杂度显著下降(人和技术)
  • 各个模块之间通信的复杂度(网络)
  • 各个模块之间连结成系统的复杂度(分布式系统)
  • 各个小团队之间沟通的复杂度(协作)

当复杂度被打散之后,整体的工作难度会有很大减轻,人力资源可以得到合理利用,各个模块之间可以专注于自己的事,不用因为原来集中的复杂度而蹑手蹑脚。这本质也是实现了分工提升效率的理念。

在实现减熵之后,各个模块能独立专注地解决自己的问题,人力资源也得到了高效的利用,生产力得以极大提升。但这离产品最终上线和交付还有一段距离。这段距离就是上面所说的复杂度转移的结果:

  • 因为复杂度被转移到了网络上,各个模块会相互干扰甚至牵制
  • 因为复杂度被转移到了系统上,协调和组织各个模块变得复杂
  • 因为复杂度被转移到了团队沟通,各个团队之间会相互影响

上面这三个点可以被称作耦合,微服务的第二大功能就是要解耦合。因为人本身的灵活性,以及团队之间沟通的结果本质上都是通过产品交付来实现,所以上面两个复杂度最终在技术上演变成了各个服务之间的复杂度。 (下面将模块改称为服务

  • A 服务上线前要等 B 服务先上线
  • 多个服务依赖一个公共的服务 C
  • C 服务更新时(调用地址等),需要依赖的服务跟着更新
  • 新加一个服务 E,需要老的服务 D 修改
  • 各个服务复用统一的日志/限流/权限等等功能

由于上面这些依赖或者说耦合的存在,即使各个服务间的生产力很强大,但要将各个服务连接成一个系统,并交付出去,还是一件很困难的事情。所以,必须要将各个服务间的相互影响降低到最小,同时让各个服务能无缝利用统一的基础设施。

how

通过上面的分析,我们已经知道微服务的核心是:通过服务化拆分的思路来进行减熵,实现资源高效利用,提升生产力;再通过解耦来降低各个模块间的相互影响,使得整个系统在变化中能快速交付。接下来就举个简单例子介绍一下如何做到这两点。

服务化拆分的第一步是:

  • 以服务为单位,清晰划分服务的职责
  • 整合各个模块间复用或相似的模块,避免重复造轮子

第二步是:定义拆分后模块的通信方式。定义接口和交互方式,将各个模块串起来。是通过 rcp 还是 HTTP,数据的交互是 MQ 异步通知还是用接口实时同步,这些都得仔细推敲。

借用上图为例,当用户预定一个航班时,内部的服务可以分为如图的这么些模块,每个模块独立成一个服务分别部署。其中和调整库存、时间表查询等服务交互时需要用接口的方式实时调用,而管理奖励就可以用 MQ 异步通知。而具体的拆分粒度和交互方式,就得根据具体业务和可支配的资源而定,逐步进行演化,没有一个定量的拆分方式。

对于流量不高且趋于稳定的系统,上诉的服务化拆解一般就可以满足需求了。但是对于高流量高速迭代的系统,还需要解耦

借助上面航班预定的简单例子。当业务流量高速增长或应对流量高峰时(搞促销),对应的服务需要扩容,而原系统中的航班预定这个核心的服务持有其他服务的地址,当某个服务扩容后,航班预定这个服务就需要知道扩容后的新地址,方便调用。当高峰过去,新增的服务下线时,又得让航班预定知道某些地址已经下线了。像这样,每个子服务发生变动都需要通知它的调用方,这是一个非常繁琐且易出故障的地方,当调用的链路变得复杂后,可行性几乎为零。而这只是系统耦合点之一。

为了解决类似的问题,常见的微服务架构中的服务注册、发现应运而生,借此实现各服务自由的弹性伸缩。经过上面的梳理,它也变得容易理解。

当需要上线新服务时,服务自己向服务中心注册,服务中心也会定期检测服务是否下线或可用性,服务中心会将这些数据以适当的方式告诉调用方,实现解耦和高可用。类似的还有服务限流服务熔断服务鉴权等等,这里不再赘述。顺带地,完整的微服务架构还包括日志处理配置中心流量监控等等自动化的设施作为辅助,替代人力,实现高效率、高可靠的系统。

当服务的数量到达一定的数量时,调用链会变得异常复杂,追踪管理它们也会产生一个新的复杂点。同时,服务注册发现本身也需要高性能、高稳定,这又是一个新的挑战。

when

通过上面两个部分的梳理,已经能初步得知微服务是什么,以及如何打造微服务。回头看这两部分,可以描述为:为了减轻复杂度,引入了貌似更加复杂的东西。可以用递弱代偿来解释,为了解决某一部分弱点,引入了一系列补偿措施来解决问题,而这些新引入的措施使得系统本身变得更弱(递弱),又需要不断引入新的补偿来规避这些弱点,直到达到一个平衡状态,而这个平衡状态本身并不能保持稳定。像极了人类本身的发展状态。(详细可参阅《物演通论》)

明白了这一切,在是否选择微服务架构,或者思考把微服务架构做到什么程度时,必须要看清楚微服务是否能解决自己的问题,同时能否消化掉其衍生出的挑战。得思考是否有强大的运维力量,是否能驾驭分布式系统的复杂性等等。

搞清问题、选择合适、量力而行、逐步演化。

ServiceMesh 顺便了解一下

Reply to freefishz

文章关注本质,serviceMesh 只是一种解耦的方式而已,是微服务理念的部分实践,相信随着技术发展,还会出现更多的解耦方式。

我们的差不多的路程和看法、包括实践

  1. 降低复杂度
  2. 解耦合。模块化之后不仅减少开发的复杂度、也能减少测试的复杂度。(我也很喜欢说 熵 或者 信息量)
  3. 部分核心模块的权限问题(财务模块、支付网关、核心技术门槛?)
  4. 利用语言本身的优势、比如 Golang 来处理一些计算模块 & Rails 用来持久化 & Node 天生的选择器来处理一些其他业务

最后都殊途同归了 RPC、MQ

感谢楼主的整理。我们实践了很多,但是很少有时间来复盘书面化整理、奔波于业务的琐碎之间

最重要的还是 清晰划分各个模块的职责,划分不好,一样是一团粥。 比如会有这种注释出现,由于 A 系统做了 xxx,所以在 B 系统,我要这么 xxx。。。

如果微服务做的不完善的话(有的公司没有那么多人力来做),同样会有 A 服务拖垮了 B 服务的情况。。。

微服务 监控 没有弄好,debug 会非常难

Reply to yfractal

所以说是 递弱代偿,要量力而行,选择当下合适的方案,逐步演化。(希望后面我真正开始完备实践的时候,能不激进踏实地这么走。)

Reply to so_zengtao

熵用来描述系统的混乱程度,是非常非常棒的一个概念。说大点,脑力劳动所做的一切都是在减熵,减熵能力越强,所产生的价值越大,剩下的都是随时可替换的体力活,这是大部分只重视应用的码农的最终归宿。

自勉,希望多年以后我能真正在减熵的路上走好,而不是成为干体力活的“全栈工程师”。

可不可以这么理解?减熵是目的,微服务是手段?

jasl mark as excellent topic. 23 Dec 02:43
Reply to yfractal

我觉得可以。微服务的理解有很多差别,我个人认为:微服务本质是在互联网时代提升产品交付效率的一种理念级的手段。

往技术上扯就是当前的微服务架构,为当前互联网大型项目量身定做的一种方案,通过三个方面来提升效率:

  • 减熵。复杂度转移,大目标拆小,实践起来就是拆服务、ServiceMesh(将各个服务面临的网络复杂度转移给 ServiceMesh) 等等
  • 解耦。降低各个服务间的相互影响,使各自的工作可以并发且独立
  • 融入自动化,降低错误率,减少人力参与,提升产品的稳定性

这一切本质上都是在提升效率,这是软件工程的主要目标之一吧,特别是前几天看了阿里提出的2-1-1(两周内交付 85% 的需求),感触尤其深。

梳理完这几点,再回头看像 SpringCloud 全家桶那些东西,全部都是围绕上面三点来的。至于现在概念很火爆的 ServiceMesh,其实也是这样,只不过它似乎将解耦、复杂度转移、自动化一起同时实践了。门外汉看热闹,我就不继续瞎扯了。

ServiceMesh 的主要目的就是降低微服务的门槛,提供一系列开箱即用的微服务基础架构。

Reply to freefishz

本质上为了 解耦/转移复杂度,为了提升效率。

继续往下想想,为什么要用微服务?微服务本质上就是用来提升效率的,当年的 SOA,企业服务总线等等都是这样。它们都只是工具,手段而已。

是为了使用微服务才提出 ServiceMesh,还是为了进一步提升效率而提出 ServiceMesh 呢?假设某一天不使用微服务了,ServiceMesh 依然有它的价值,不会受影响,只是可能会微调。

我是在说 ServiceMesh 的理念,讨论的可能不是同一个。

为什么会有 ServiceMesh 呢? 就是因为微服务落地门槛太高,太过复杂。

服务注册/发现、限流、熔断、负载均衡、灰度发布... 对一个中小企业来说,自己搭建维护这一套东西成本太高了。

ServiceMesh 将上述功能抽离出来,作为通用的基础设施统一提供(终于可以不用依赖 SpringCloud 了)。 这和就像 Rails 的理念非常像,基础服务都已经提供了,只需要专注业务实现。 厂商也可以遵循统一的接口规范,提供企业级服务,帮助中小企业快速落地微服务。

ServiceMesh 如果没有了 Service,还 Mesh 啥?

Reply to early

感谢回复 👍 👏

还好很多场子都喜欢重复造轮子 😄 ,而且同样的东西,大家理解程度不一样,结果也会不一样。

我明白微服务是很好的东西,解决了很多问题。但实践起来又有很多无奈。。。

我们最近刚好有个市场运营需求,用消息队列解了耦。但由于部署环境网络不连通,只好用 http 再把消息传出去。。。然后 rpc 又没时间搭。。。不过消息队列还是有必要的,市场想法多,如果让他们的需求一直入侵主代码,会越来越难维护。而且市场的需求挂掉话也不应该影响主项目。

Reply to early

感谢回复 👍 👏

还好很多厂子喜欢重复造轮子 😄 ,而且同样的东西,大家理解程度不一样,结果也会不一样。

我明白微服务是很好的东西,解决了很多问题。但实践起来又有很多无奈。。。

我们最近刚好有个市场运营需求,用消息队列解了耦。但由于部署环境网络不连通,只好用 http 再把消息传出去。。。然后 rpc 又没时间搭。。。不过消息队列还是有必要的,市场想法多,如果让他们的需求一直入侵主代码,会越来越难维护。而且市场的需求挂掉话也不应该影响主项目。

Reply to yfractal

想请教一下关于市场部门的临时需求,跟业务的主线需求有分歧的时候,怎么编排代码会比较好?

Reply to luikore

我们有一段时间要搞 grpc,然后 grpc 死活搭不起来。我跟同事说,为什么非要等到 grpc?为什么不先切分服务?调用用什么不可以?grpc 好了,换一下就可以了。但就是说不通。

我一直觉得一个模块,对外提供服务、屏蔽实现细节,就可以了。至于是否是微服务只是表现形式罢了。

我也觉得很多架构属于“为了微服务而微服务”,并没有真正的分析自己业务的特点,盲目的把服务粒度做的很细。

亚马逊有一个“两个批萨原则”,我觉得微服务也是同理,最理想的情况就是每个 team 需要管理的微服务只有 12 个,本地开发一个 docker compose 启动所有的微服务。否则一定会为了某个功能应该放在哪个微服务争吵起来。

@luikore 给你一百个赞👍

21 Floor has deleted
Reply to luikore

移动互联网催生了微服务这类的效率改善措施,业界有很非常多好的正面的有指导意义的微服务例子。有人浑水摸鱼,或者胡搞一通,以某项技术来获取利益,这也挺正常,每项技术出来都会被炒,不过这是人或做事方式的问题,和技术本身关系不大。

ServiceMesh 由谁来做,也许对大多数码农来说没有区别。把大多数显得牛逼的项目中的开源组件拿掉,可以发现很多码农的核心价值趋近于零。不过这些牛逼的开源组件确实是部分码农搞出来的,总有人在做有挑战的事情。

Reply to early

能把这些开源组件组合起来卖钱也是一种能力,产生的价值比开源组件大,所以也谈不上谁比谁牛的,各有专攻。

Reply to ericguo

技术的应用肯定是有很大价值的,从有些角度来看技术的应用比其本身更有价值。不过这个价值是大部分是由企业家/产品经理来引导,”架构师“来选型做抽象,剩下的那些价值就不大了,可替代性太强了,很多是框架下简单的重复而已。

Reply to yfractal

我一直觉得一个模块,对外提供服务、屏蔽实现细节,就可以了。至于是否是微服务只是表现形式罢了。

As we always do .

微服务+js 全栈 应该是最牛的搭配

啥叫 熵?求解

29 Floor has deleted
30 Floor has deleted
Reply to aldrich

描述系统混乱程度的经典概念。维基百科

You need to Sign in before reply, if you don't have an account, please Sign up first.