大家好,我是Z哥。

不管是十几年前 SOA 的流行,还是 7、8 年前微服务的大行其道,还是如今云原生的展露锋芒,背后都离不开一件事,程序拆分或者说服务拆分。否则,一个单体应用,以上的这些技术潮流好像都与它没什么关系,只是一个看客。

虽然Z哥我没有从头开始完整地亲历过以上三个时期,但是这三个时期都有过我留下的足迹。所以我想我接下去分享的内容应该对处在云原生时代的大家有所帮助。

/01  拆分有什么好处/

拆分的目的很容易理解,分而治之。本质是将复杂的大问题分解成更简单的多个小问题,从而解决它。

而在拆分之前的单体系统中,我们往往面临着哪些问题呢?

01  数据库瓶颈

所有的业务都由一个数据库承载着,随着业务的发展,数据库日常内存吃紧,时不时还搞出个 cpu 90% + 以示它的怒火。

02  增加人员对开发效率提升的边际效益递减

项目里的代码量从 10 万行,增长到 100 万,再到 1000 万。随着代码量的增加,代码之间的耦合问题越发严重,开发效率明显降低。好吧,效率不够数量来凑。扩招了更多的人进来,但是发现耦合问题更加严重了,经常出现 A 等 B 提交代码,B等 C 提交代码,C 等 A 提交代码的情况……

03  运维成本指数级增加

随着项目参与人员的增加,每天发布程序的次数也增加了。可怕的是,代码量也在增加,导致每次编译发布的时间也增加了,这对开发效率来说是双重打击。每天发布的时间加起来可能就占了半天。

希望你所在的团队不要处在如此痛苦的场景中。

/02  什么时候拆?/

拆分虽好,但也不是万能的灵丹妙药。对于大多数组织来说,一个新系统不适合一上来就按照拆分的思路来做。因为拆分需要基于对当前业务、当前系统、当前环境的理解之上的,而面对一个未来充满未知的新业务,我们当下的信息积累是不够的,如果过早拆分,很容易导致边界划分不合理的情况,这在后续会带来不小的负面作用。甚至,可能这个产品在经过市场验证失败后就被砍了,之前的工作做得再多、再完美,全白费了。

因此相对来说,从一个已有的单体系统中逐步拆分出一个个模块反而容易得多,因为确定性更高。

单体系统和分布式系统对成本与业务复杂度之间的关系是这样的。

因此,在这个临界点附近进行拆分工作的性价比是最高的。

对于如何判断是否达到了这个临界点,我认为至少要符合以下三点中的两点。

  • 业务已在市场站稳脚跟,规划中业务发展速度未来可能会加速。

  • 开发人员持续扩张,并且未来还将继续。

  • 平均单人开发效率下降。多个开发人员之间的工作相互影响、依赖,导致解决这些冲突所花费的成本占到了总开发成本的 30%以上。比如,提交的代码冲突、你等我 coding 完才能继续 coding 这种(往往这样的情况下,每个迭代的版本也很大)。

/03  拆分前的准备工作/

并不是以上条件满足了就可以拆了。在实际拆分之前,我们要做一些准备工作。这其中最为关键的是两件事:

  • 统一拆分原则

  • 基础设施建设

因为从单体系统到分布式系统不仅仅是技术的升级,更是开发理念的转变。

这两件事的具体就不展开了,前人已经总结过很多了,我就简单罗列一下。在应用拆分这件事上比较适用的是:

  • 高内聚低耦合

  • 闭包原则

  • 接口隔离

  • 演进思维

  • 避免循环依赖

另外,分布式系统中常用的基础设施主要是以下这些:

  • 消息队列

  • 缓存

  • 日志系统

  • 服务治理

  • 监控

  • 网关

  • 配置中心

  • 数据访问组件

以上这些是必须项,其它可选项还有不少,比如:分布式文件系统、容器管理平台、CI/CD 等等。

/04  拆分思路/

具体的拆分其实就是划分边界的过程。强烈建议通过 DDD 的思想进行。

  1. 深入理解业务,从中定义出隐含的实体、值对象。

  2. 从实体对象中找出聚合根,根据实体、值对象与聚合根的依赖关系,建立聚合。

  3. 根据业务场景等环境因素,划分限界上下文。这里的限界上下文就可以与拆分出来的微服务一一对应。

其中最关键的是「抽象」工作,为了更易理解还是来举个例子说一下。比如,当我们在某某养车平台下单一个保养订单,你说其中的“安装”业务该以什么形式进行交易比较合理?Z哥我认为是将其当作一个普通商品看待,当然该平台也的确是这么做的。如此一来,购买机油机滤和安装服务对用户来说是一样的,很自然地被创建在一笔订单里,而不是两笔订单。

如何评估抽象的好不好呢?可以从以下两个角度来观察。

  1. 两个限界上下文之间的依赖应该越少越好。并且依赖的上游不需要知道下游的信息。比如订单 service 依赖商品 service ,但是商品 service 无需知道订单 service 的存在。

  2. 推演可能的未来业务,如果能响应业务变化(不一定 100%满足),则证明该抽象是符合未来预期的,可以在一段时间内支撑业务的持续发展。

不过不管怎样,最终你都在抽象程度、成本、复用性这三者之间平衡。

除此之外,我们还可以根据以下三个维度来进行拆分。

  1. 是否经常变动

  2. 复用程度的高低

  3. 是否有特殊的要求(高性能、安全性等)

好了,总结一下。

这篇呢,Z哥和你分享了我对微服务或者说分布式系统如何拆分的看法。

拆分可以解决单体系统的三个痛点。

  1. 数据库瓶颈。

  2. 增加人员对开发效率提升的边际效益递减

  3. 运维成本指数级增加。

但是拆分也不是越早越好,至少符合以下三点中的两点。

  1. 业务已在市场站稳脚跟,规划中业务发展速度未来可能会加速。

  2. 开发人员持续扩张,并且未来还将继续。

  3. 平均单人开发效率下降。多个开发人员之间的工作相互影响、依赖,导致解决这些冲突所花费的成本占到了总开发成本的 30%以上。比如,提交的代码冲突、你等我 coding 完才能继续 coding 这种(往往这样的情况下,每个迭代的版本颗粒度不得不变得很大)。

然后,拆分前还需要做好两项准备工作。

  1. 统一拆分原则

  2. 基础设施建设

具体实施拆分的思路,建议以 DDD 的思想来进行。

其实任何事都没有一招鲜吃遍天的方法,随着业务、技术的发展,我们的拆分思路也需要持续迭代。如果你之前这方面的实战经验比较缺乏,不妨从我分享的这些方面入手试试,希望能对你有所帮助。

推荐阅读:

  • 接手历史悠久的老项目,干or跑?

  • 如何让自己更自律

原创不易,如果你觉得这篇文章还不错,就「点赞」或者「在看」一下吧,鼓励我的创作 :)

也可以分享我的公众号名片给有需要的朋友们。

如果你有关于软件架构、分布式系统、产品、运营的困惑

可以试试点击「阅读原文

一些微服务拆分的浅见相关推荐

  1. 这才是微服务拆分的正确姿势,值得学习!

    作为Java工程师,微服务拆分则是在开发过程发展到一定阶段不得不面对的技术架构要求.大家可能会遇到这些问题:为什么要拆服务?拆解方法有哪些?公司真的这样拆解微服务的吗? 以上问题统统别担心!慕课网特意 ...

  2. 微服务拆分,选型与演进

    微服务拆分原则 在微服务拆分中,核心需求在于拆开的微服务之间的联系越少越好,数据交互也是越少越好.因为微服务之间的数据一致性非常难处理,如果一致性方面的问题很少,整体做起来就比较简单了. 微服务架构选 ...

  3. SpringCloud微服务实战(四)-微服务中的服务拆分

    订单服务源码 https://github.com/Wasabi1234/SpringCloud_OrderDemo 商品服务源码 https://github.com/Wasabi1234/Spri ...

  4. 服务拆分-案例Demo

    服务拆分原则 这里我总结了微服务拆分时的几个原则: 不同微服务,不要重复开发相同业务 微服务数据独立,不要访问其它微服务的数据库 微服务可以将自己的业务暴露为接口,供其它微服务调用 服务拆分示例 以课 ...

  5. 点餐业务服务拆分分析

    我们有两种方式可以拆分服务,第一种我们的系统分为买家端和卖家端,你可以把vue放到app上,用来做买家端需要的接口,卖家端呢,也就是PC端,由freemark做的html页面作为另外一个边缘服务,两端 ...

  6. 微服务拆分需要考虑的必要因素与坚持原则

    前言:创业公司往往因为有限的时间和投入,把系统所有的功能都聚集在一起.随着业务的不断发展,技术人员开始不断地对架构进行解耦和拆分.微服务在最近几年大行其道,很多公司的研发人员都在考虑微服务架构,或者在 ...

  7. 面试基操:微服务拆分需要考虑什么因素?

    面试官:微服务如何拆分?需要考虑什么因素? 候选人:一般按照功能拆分 面试官:还有吗? 候选人:唔-- 要拆分微服务,首先我们要了解微服务拆了会有什么问题?怎么合理拆服务? 拆分服务会带来什么问题? ...

  8. SpringCloud 从菜鸟到大牛之三 服务拆分 理论

    上一篇文章 介绍了 服务注册的概念 与及 SpringCloud Eureka 的使用 和配置. 接下来,就来 介绍一下 服务拆分?在这里 作为 抛砖引玉 ? 问题 1 如何 拆分? 问题2 什么是 ...

  9. 微服务化之服务拆分与服务发现

    作者:刘超 一.服务拆分的前提 说到微服务,服务拆分是绕不过去的话题,但是微服务不是说拆就能拆的,有很多的前提条件,需要完成前面几节所论述的部分. 首先要有一个持续集成的平台,使得服务在拆分的过程中, ...

最新文章

  1. 设置linux初始root密码
  2. Android架构详解
  3. 日志管理系统的重要性---怼死你的客户
  4. 【Java 虚拟机原理】Class 字节码二进制文件分析 三 ( 访问和修饰标志 | 类索引 | 父类索引 | 接口计数器 | 接口表 | 字段计数器 | 字段表 )
  5. CCF-CSP 201903-1 小中大(C++满分代码)
  6. SpringMVC表单验证与Velocity整合
  7. kettle怎么复制资源库的job_#linux系统下调度数据库类型资源库中的kettle job
  8. (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  9. android开发 视图联动_Flutter混合APP开发
  10. android 不生成odex文件方法
  11. LightOJ 1258 Making Huge Palindromes(KMP)
  12. linux下各种后缀名文件的压缩和解压缩
  13. 电厂运维的cis数据_浅析电力企业信息系统运维综合监管平台设计-
  14. 如何压缩图片呢?这两种方法很管用
  15. 通过自定义注解+反射的形式,使用POI实现excel的导入导出
  16. 微信公众号开发工具汇总
  17. Android 手机安装有微信,还是提示未安装微信
  18. Firefox(火狐浏览器)常见插件应用
  19. luckysheet 只读模式和编辑模式
  20. js 谷歌浏览器 关闭当前页

热门文章

  1. GAE 随机获取实体
  2. mysql 导致iis 假死_解决IIS无响应假死状态
  3. 双谷人才财务管理(序)
  4. 猎豹MFC--CMenu菜单 设置主菜单 给主对话框设置菜单 设置快捷菜单
  5. 三分钟学会缓存工具DiskLruCache
  6. JS iframe父子页面元素调用方法 window parent top 解释
  7. lr java脚本_【上海校区】 LR Java脚本编写方法
  8. 百度新闻 谷歌新闻_每日新闻摘要:到目前为止,Google I / O提供的最佳信息
  9. 原生sql实现restful接口调用
  10. SpringBoot获取ApplicationContext