为何拆微服务这么艰难

微服务,这三个字正在席卷着目前的互联网软件行业,尤为在近几年云原生迸发后,彷佛人人都对微服务有了更普遍的使用和理解,张口就是各类各样的问号,有着强大的好奇心。golang

无独有偶,我有一个朋友鲤鱼在内部微服务的早期(每一个业务组起步)就常常遇到下述的对话:web

  1. 张三:为何要拆如今的代码?数据库

  2. 鲤鱼:由于 !@)&&#@!)&#!&)@!&!的缘由。微信

  3. 张三:那即将要作的 “微服务” 是按照什么维度去拆分的服务?网络

  4. 鲤鱼:常见的通常根据 !@#*@!#&!(@&!@)#@ 的方式来拆分。架构

  5. 张三:照你这么说好像也不大对,我看每一个业务组拆分的维度彷佛都不大同样?编辑器

  6. 鲤鱼:嗯,每一个业务组还有本身的看法,不会彻底相同。函数

  7. 张三:。。。因此微服务的拆分维度究竟是什么?微服务

为何想拆

为何张三会有这个疑问呢,其实是由于研发内部但愿从原先的大单体,大仓库向微服务体系拆分转换,其原先大单体仓库结构,类 Monorepo:工具

但类 Monorepo 又有很多的问题,像是:

  1. 单个 Repo 体积过大:致使 Git 没法直接拉取。当你设置完再拉取时,在网速慢时还能去泡杯咖啡,而且在开发机性能不佳的状况下,IDE 会比较卡,代码运行起来也慢。

  2. 单个 Repo 存在公共函数/SDK:在代码仓库中,必然存在公共依赖。所以在解决代码冲突时,若遗留了冲突符,且在动态语言中,不涉及便运行正常。但其实在上线后却又影响到其余业务,可真是糟糕透顶,分分钟被迫抱着事故。

  3. 单个 Repo 模块职责/边界不清:在实际的软件开发中,涉及数十个业务组同时在一个大 Repo 下进行开发,没有强控边界的状况下,每每会逐渐模糊,即便在设计时管得住本身,你也不必定能 100% 防止别人模糊你的边界。

  4. 单个 Repo 包含了全部的源码:出现公司源代码泄露时,会致使整个 Repo 外泄,至关的刺激和具备教育意义。由于虽然开放和协同了,不属于大家组的业务代码你也有权限查看了。

固然,Monorepo 是否又彻底不可行呢?实际上国外 Google,Facebook,Twitter 等公司都有在使用 Monorepo,并取得了必定的收益。

其实作 Monorepo 是须要相应的大量工具支撑,若单纯只是一个 Repo 塞多个模块,基本都作很差,甚至引火烧身。还不如早早拆开,至少能确保各业务线服务的相对独立性。

拆成什么样

张三在明白了拆的缘由后,就出现了第二个问题,那就是 “微服务” 要按照什么样的维度去拆分服务?

张三公司内部对于这块的知识处于模糊不清的阶段,所以须要进行深刻了解,便于后续的团队共识和方法论创建,理所固然,十万个为何也就出现了。

大单体变独立服务

最多见的拆分的方式是按照业务模块进行服务的拆解,像是前文所提到的业务模块,在设计上边界很是清晰,这种状况直接拆成各个服务就能够了:

而在拆分后,又会遇到一个新的问题,也就是张三问第三个问题 “每一个业务组拆分的维度彷佛都不大同样?”。

由于在实际的执行过程当中,严谨一些会由 SM 与 RD 一同开会探讨/规范第一版的服务划分,而在持续的快速的迭代中,每每新服务的拆分都是由一线 RD 亲自操刀。

即便是架构师亲自操刀,在相对复杂的业务模型下,不一样架构师划分出来的也有可能不彻底一致,所以不管是哪一种状况,你都会发现每一个业务组拆分的维度多多少少都不同了,毕竟人与人的思想都是不同的,一千我的有一个千个哈姆雷特,所以张三的疑惑是正常的。

就像下图,核心是定义一只鱼,在不一样人的眼中能演化出各类奇奇怪怪的鱼:

大数据库变独立数据库

在之前早期的大单体快速迭代中,每每是一个大数据库包含全部的业务数据库(甚至数据库帐号都不分),这种时候就会带来各类问题。

像是某一天,你所负责的业务模块数据库莫名其妙出现了一些奇奇怪怪的值,你可能就要抓破脑壳去各类代码和 binlog 查了。更甚还有被网络攻击后,数据库配置被获取,直接跳板一拖直接整个脱裤,那但是糟糕透顶了。

所以在常见的应用设计中,应用程序在链接数据库时会指定链接特定的域名(例如:eddycjy-user),方便将来迁移。而且每一个业务服务分别给予独立的数据库只读权限,进行软隔离。

而在业务量上来后,也会对业务数据库进行硬隔离,分配特定的 RDS 实例,就不会互相影响了。

环境隔离,独立

在服务拆分后,大多会采起独立部署的方式,将二者之间的环境隔离开来,互不干扰,互不影响:

像在云原生中,常见于在 Kubernetes 将一个业务服务做为一个 Service 部署发布,再根据实际的资源和调度状况进行 Pod 的扩缩容就能够了,资源也不会有直接干扰,且外部/内部调用都是有统一的入口管理。

拆分的阵痛

业务接口聚合

在服务拆分的过程当中,老是会有阵痛出现。

例如在服务须要获取 “项目” 和 “房源” 信息时,究竟是由谁来聚合这两个服务的信息。是否是应该由 BFF 来聚合:

或是应该新写一个胶水服务,用于聚合“项目” 和 “房源” 信息,保证其聚合性,减轻 BFF 的负担:

又或是在量级愈来愈多的状况下,是否是要怀疑一下,这两个服务拆分是否是有问题,“项目” 和 “房源” 在当前业务模型下是否应是一家:

显然在鲤鱼的经历中,这三种类型他都见过,不一样的人总会在不一样的思想和业务模型下选择了不一样的解决方案,还真的没有绝对准确的准则。

分久必合,合久必分

随着对服务化的进程推动,常见的会遇到两种状况:

  • 刚接触服务化时:服务一个没有,偶尔会有一个新的小业务,竟然能拆出好好几个微型服务,并扬言要把剩余业务直接抄底重构了,都拆掉,怎么劝都劝不回头。

  • 随着业务的不断发展:快速迭代,服务愈来愈多,工期压缩,多个 RD 交叉背好几个业务服务,有点力不从心,发现拆的好像有点问题,从最新的状况来看,某某几个服务彷佛应该合在一块儿。

  • 业务阶段性稳定:。。。这,之前这块好像有点问题,也太难拓展了,不该该这么拆,谁调了我,个人上下游是谁。

大多数的状况都是第二和第三者,但在实际操做中也不见得会合并服务,大多数 RD 会选择吞进内心,由于服务变迁所带来的工期延长和影响面没法直接预估(且存在历史代码,人员可能已经离职多年)。即便是服务拓扑也只能查看到必定时间内的服务调用,不会看到所有,所以上下游均没法 100% 肯定。所以综合来看,弊大于利。

在解决方案上,更多的是在下次新服务规划时控制划分变量(由于已经有更成熟的经验了)。

实在不行了,才有可能会新起聚合服务将本来的多个服务聚合,又或是采起版本号等方式进行新老分流。甚至下定决心,蚂蚁搬家,起新服务一个个板块重构,一个个挪,持续灰度,“完全” 解决历史包袱,完成转化。

拆分准则

张三又发话了,你说的我都懂,内部微服务都发展好几年了,做为已经有丰富研发经验的人,能不能释出一套微服务拆分的准则呢,不然每个人都要经历一遍,怎么办,有没有什么基本准则能够遵照呢,你看如今 DDD 那么火,能不能 DDD 一下,让核心一致呢?

机智的鲤鱼掐指一算,张三确定想的是让全部业务组的拆分,都能依据拆分的核心准则走,实现你中有我,我中有你,看哪哪都有影子,核心不跑偏就行,创建一套完美的方法核心论:

这种建议右拐 Google “微服务如何拆分”,网上有超级多的指导资料,建议先培养在团队内的共识。毕竟在每次拆服务时让每个人都对照着那一长串的 “微服务拆分准则” 是一件很不科学的事情,更多的工程师会依据自身的经验进行当前其认为的最合理拆解。

而准则,你认为的核心 A,在他人眼里并不必定是正确,他可能认为是 B,所以在事业部,业务团队中达成共识并把拆分思想融合进每位 RD 思想中,长期的共同分析如今的拆分状况,且让你们基本认同才是最重要的。

同时让全公司都依据一个准则来作,在服务拆分这种没法利用工具流程强控制的状况,自己就是一个伪命题,更多的会是人与人之间的妥协,基本上会变成一个少有人看的 “指导” 文档。

总结

在微服务中,服务的拆分老是能让人如此细细品味,本文并非具体的讲某几个知识点,更多的是阐述在服务化发展的历程中的 “冲突点” 又或是 “矛盾点”,不一样的人总有不同的理解,但愿可以给你们带来一些思考。

且在阅读微服务相关指南时,更建议看企业实践后拆分的经验分享,不然单纯看 “指南” 没有过多的意义,要看具体的公司/团队状况和业务模型。

推荐阅读

Monorepo:

  • Why Google Stores Billions of Lines of Code in a Single Repository

  • Monorepos: Please don’t!

  • Why might a project/company use a monorepo?

Microservices:

  • Nginx Refactoring a Monolith into Microservices


本文分享自微信公众号 - GoCN(golangchina)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索