系列文章
- .Net微服务实战之技术选型篇
- .Net微服务实战之技术架构分层篇
- .Net微服务实战之DevOps篇
- .Net微服务实战之负载均衡(上)
- .Net微服务实战之CI/CD
- .Net微服务实战之Kubernetes的搭建与使用
- .Net微服务实战之负载均衡(下)
- .Net微服务实战之必须得面对的分布式问题
- .Net微服务实战之可观测性
前言
本文于 2022.6.22,首发于ITPUB 官方公众号,作者陈珙,未经授权禁止转载。如需转载,请联系 ITPUB 公众号。
开始前我跟大家分享个自己的小故事,大概1年多以前,我给某个企业培训微服务实战,既然是实战当然是从实施落地出发。但是培训完毕后,甲方却反馈我对微服务的概念讲得太少了,他们压根不知道什么回事。开始我以为他们只是谦虚客气一下,因为我认为已经到了202X年了,微服务或多或少都了解一些,但是并非如此,经过我和其他同行沟通来看,我的想法确实以偏概全了。
所以我趁着这次和ITPUB 合作,把以重新理解微服务从他的过去、本质出发跟大家分享自己一些见解。这篇文章原本1万7千多字,经过和DTCC的韩老师沟通后,最终拆成了两部分,下星期会再发另外一篇。
温故而知新
不少同行,对于“什么是微服务”,都在各平台发表过相关理解、看法等。随着这些年的技术发展,只要涉及到“微服务”这三个字已经不再纯粹,几乎无论是什么方向技术,或多或少会跟微服务扯上关系蹭蹭热度。当然,也恰恰基于此,使得我为何重提何为微服务,并且单独拿出从多个方面结合我的个人见解,想与大家深入探讨。
先开头这里,就抛出我自己的一个观点吧,我并不认为非要把技术弄得多复杂,才显得多牛X。再复杂的物品也是由一件件简单的物品组件形成的,而适当的返璞归真才能看清楚事物的本源。
若要想要更清晰地了解、理解、搞清楚“微服务是什么”,我认为只需要认真看懂一篇文章就足够了——2014年马丁·福勒个人博客发表的《Microservices》博文(https://martinfowler.com/articles/microservices.html)
但是,马丁·福勒所著的作品多数是高度总结的,假如你没有亲自实践过,他的作品与思想理解起来相对比较困难,因为他的叙述总体比较抽象。当然,这不影响我自愿重复多次的阅读他的作品——温故而知新。
因此该篇我不会照搬翻译,或是人云亦云,而是会从《Microservices》原文和其他书籍收集回来的资料并结合我的个人见解,来叙述微服务的What、When、Why。
这篇文章没有微服务的How,可能您看完了也不知道应该怎么去实施微服务,但是关系不大,因为我一直坚信,如果你能把某件问题的来龙去脉,清晰无误、通俗易懂地传达给别人,该问题已经解决了70%,那么剩下30%就是寻找解决方法的路上。方法远要比遇到的问题要多得多。如果您对具体的微服务实践有兴趣,可阅读完该文后请移步到《.Net微服务实战》(https://www.cnblogs.com/skychen1218/p/16352324.html)进行扩展阅读。
本篇文章,我将通过选择微服务的原因、微服务的小历史、微服务的特性和我对微服务的个人见解多个角度,分享我对微服务理解的What。你可以总体浏览下大小标题,快速过一遍。抑或是期间挑自己更为感兴趣的部分,直接跳到那里看。
选择微服务的原因
说到这,我想先问这样一个问题,你选择微服务的原因有哪些呢?可能这问题的回答会百花齐放,无论是哪种原因,促使我们选择微服务终须一个或多个的理由。凡是做任何一件事情,都要有目的性,不可盲目,否则只能是毫无价值的冒进。因此在这我给大家分享下我选择微服务的理由。
单体应用的优与劣
在早期的开发,单体应用给开发提供了很多的便捷性:
- 开发简单方便;
- 项目管理集中;
- 进程内调试,排查、定位问题更加便捷。
随着团队与业务规模的增加,单体应用的缺陷就会越发的明显,以我个人实践经历,如果希望引入微服务,我认为得满足以下任意3点,则可以考虑选择微服务:
- 并行开发的代码冲突;
- 加载、编译、部署项目缓慢;
- 代码耦合性越来越高;
- 需要统一数据读写入口;
- 无法按需扩展。
我早些年遇过10人并行开发共有两三百个项目的解决方案,不论是每次项目加载、编译、部署,其实都非常花时间。只要并行开发就会存在冲突,修改的代码资源越集中,出现合并冲突概率还越大。
在单体应用里,我们会以“库”的方式形成组件,以此来进行单元复用,如果在同一个解决方案里共享复用,使用与修改的自由度会更高。
任何事情都会有利弊的,随着项目的发展,参与的人越多,迭代的频率越高,那么“库”的职责边界就越不清晰,代码耦合也会越发严重。而且因为项目多了,为了方便复用,不同的“应用”引用相同“库”的情况也自然会变多,这样就导致了数据的读写入口扩大,假如数据出了问题:
- 不好定位原因。
- “库”出了问题,相关引用的应用都得重新发布或回滚。
微服务的优点
微服务的优点有不少,但是我认为核心优点是独立部署与协议统一,而其他的优点都是基于两者之上进行扩展的。因此本小结会着重叙述这两点,剩下的优点我将会在下文结合微服务的特征再进行详细叙述。
微服务其中之一的优点——独立的进程部署,以软件工程的角度出发,从物理层面约束了团队职责,刻意地划分了业务之间的边界,每个开发组(人员)都会清晰了解各自的领域与职责,使得大家优先思考清楚需求的修改点,该由哪个业务组负责。
另外其中一个优点——数据的读写访问统一协议,以技术设计的角度出发,数据的读写操作都被封装成Http API以此隐藏了技术细节,能大幅度降低调用端的技术人员,对非所属业务模块的细节关注,从而把他们注意力转移到所属的业务层面,减少认知负担。
此外,还可以避免非所属业务的技术人员对数据结构做出了不恰当的修改。
总得来说,微服务从工程化的层面解决了不少单体的“老大难”的问题,但是,既然没有“银弹”的存在,那么“新”的技术同样也会带来更多新的挑战,具体的新问题,我将单独拿出来放到新的一篇文章,跟大家详细地分享下,接下来会跟大家分享一下微服务的过去。
微服务的一些小历史
虽然微服务无论是从理论还是实践上解决了不少单体的“老大难”的问题,但是它并不是一门新的技术,它的诞生年份得追溯到2005年,而它的设计思想得追溯到Unix的哲学思想,因此,要想了解一样事物的本质,那么就应从它的历史发展说起。
维基百科截图
提到微服务,马丁·福勒这个名字肯定不能忽视,不少人认为马丁·福勒创造的微服务。对于该错误的认知,我认为我有必要应该重新说明下。参考了维基百科(https://en.wikipedia.org/wiki/Microservices#History),我把微服务发展历史整理成了时间线。
时间 | 事件 |
---|---|
2005年 | Peter教授在Web Servces Edge大会提出了“Micro-Web-Services” |
2007年 | JuvalLöwy在他的著作与演讲建议用服务构建系统,并意识到细粒度因此扩展了WCF。 |
2011年 | 一个软件架构工作组在威尼斯附近举行的软件架构师研讨会上使用了”Microservice”来代表这种架构模式 |
2012年 | Jame Lewis针对微服务概念在某大会发表了演讲 |
2014年 | Jame Lewis 和 Martin Fowler合写了关于微服务的一篇学术性文章 |
上文我们可以总结出三个核心关键点:
- 微服务的起源最早追溯到2005年;
- 微服务不是由马丁·福勒他本人创造的;
- 那篇举世闻名2014年写的《Microservices》原文是由詹姆斯·刘易斯和马丁·福勒他们两人共同合作编写的。
虽然说微服务架构并非马丁·福勒所创造的,但是称《Microservices》这篇文章是推动微服务的崛起的缘由,一点都不为过,而詹姆斯·刘易斯和马丁·福勒两位对微服务的盛行起到了非常关键的作用。
微服务的特点
上文结合了维基百科分享了微服务的小历史,同时也为微服务、马丁·福勒和《Microservices》原文三者之间的关系,做了个简单叙述,以便大家更加清晰的认识。
原文的九大特征
既然已经了解了微服务的过去,那么接下来得了解它是什么。马丁·福勒曾经在《NoSQL精粹》写过一句话,他并不喜欢给某件东西下定义。因此在书里,他对于NoSQL总结几大共同特征,而拥有这些特征的存储系统可以称之为NoSQL。
同样,他在《Microservices》原文里,对于微服务架构风格也总结出了微服务具有的9种特性(详细请看下文),而我结合了资料与实践提炼了一下关键字也总结了4个关键特征:
对于原文里的九种特征,还有一段更加精炼的总结。大家看的时候可侧重看我提炼和加粗的关键字,稍后我会结合原文与我的个人总结说一下,以便于帮助你快速抓住分享要点。
原文:
The term "Microservice Architecture" has sprung up over the last few years to describe a particular way of designing software applications as suites of independently deployable services. While there is no precise definition of this architectural style, there are certain common characteristics around organization around business capability, automated deployment, intelligence in the endpoints, and decentralized control of languages and data. In short, the microservice architectural style [1] is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.
译文:
“微服务架构”一词在过去几年中出现,用于描述将软件应用程序设计为可独立部署的服务套件的特定方式。虽然没有对这种架构风格的精确定义,但围绕业务能力、自动化部署、智能端点以及语言和数据的分散控制的组织具有某些共同特征。 简而言之,微服务架构风格是一种将单个应用程序拆分为一组小的服务,每个小的服务都在自己的进程中运行并与轻量级机制(通常是HTTP REST API)进行通信。这些服务围绕业务功能构建,并且可以由全自动部署机制独立部署。这些服务几乎没有集中式管理,它可以用不同的编程语言开发,并可以选择不同的数据存储技术。
我总结的四大特征
从上面两段原文,我们可以从中提炼出五小句关键表述:
- 由单个应用拆分为一组小的服务(small);
- 每个服务在独立的进程运行,服务之间使用轻量级的通信机制(lightweight);
- 服务围绕业务构建,同时服务可以自动化独立部署(independently 、automated);
- 可以使用不同的编程语言和数据存储(different)。
对于以上五个关键词和九大特性,我重新总结了自己的经验并得出以下四个特征:
- 轻量级(lightweight、small),通信协议和服务应用自身都应该是轻量级的。
- 自治性(independently),能独立部署运行,且低耦合,服务之间互不影响。
- 异构性/去中心化(different),可以根据业务特殊性,选择合适的开发语言和存储系统。
- 自动化(automated),可以由全自动部署机制独立部署。
总地来说,我给微服务的定义是:从软件工程的层面解决了项目臃肿、并行开发冲突、代码耦合度高的问题,并且它具有轻量级、自治性、异构性、自动化四大核心特性的架构风格。接下来,我会根据上述自己总结的关键词和架构设计方法论,跟大家分享一下我对微服务的理解。
业务与团队
我曾经在《十年技术进阶路,让我明白了三件要事》一文提到一句话,我认为可以引用到咱们做架构设计:
做任何事情就如同咱们写代码Function一样,得有输入同时也得有输出,输入与输出之间还得有执行。
业务需求与组织架构是架构设计的两大核心输入,具体原因有以下四点:
- 设计没有对与错,只有合适与不合适;
- 业务需求了解度越高,设计合适度则越高;
- 在能满足需求的前提优先选择简单、合适的方案,避免过度设计;
- 技术选型应需要考虑自己的团队是否足以支撑。
在《Microservices》原文提到的其中两大特征是与之有关,因此我打算放在一起叙述:
- 围绕业务能力划分团队(Organized around Business Capabilities)
- 是产品而不是项目(Products not Projects)
我从原文中的两大特性里分别提炼了两个核心句:
- 谁构建,谁维护(you build, you run it )
- 康威定律(Conway's Law)
业务
早些年我呆过项目制的公司,所有的项目组的成员是通过资源调配临时组建的。职责划分也很清晰,开发部门完成后就QA团队测试,QA完成测试后就交给运维部门负责运营。批次完成后,该项目由谁会继续参与后续批次的开发与维护,一切都是未知的,而眼前的项目如同一次性产物一般。
然而在微服务里,更加希望的是团队的生命周期与产品的生命周期是一致的,谁构建,谁维护(you build, you run it ),这样做的好处有三点:
- 该团队成员更加熟悉业务,就如前面所说业务是核心输入之一。
- 对系统、产品有一个持续演进与迭代,这样才会有足够的信息与了解,才足以让系统与产品作出更加合适的优化与设计。
- 减少跨职责部门沟通的成本,同个业务组所有的成员都会为同一个产品负责,这赋予了他们责任心与共同的目标。
团队
从以上三点也引出了康威定律(Conway's Law)。
原文
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure — Melvin E. Conway
译文:
任何组织在涉及一套系统(广义概念上的系统)时,所交付的涉及方案在结构上都与该组织的沟通结构保持一致 — 梅尔文·康威
用通俗的话描述意思是:其组织架构等同于系统架构,举个例子,该应用是前后端分离的,那么团队得有前端和后端开发,如果该团队与其应用实施了DevOps,还得有运维开发人员等等。
团队会随着产品的演进而变化(扩招,缩编),而原文里提到了两个披萨原则,建议一个团队6-12个人的大小。从我个人的经验来看,一个人的沟通渠道大于5个以上,沟通占据工作上的比例则呈指数级的增加,如果一个团队少于2人,又容易形成单点问题与压力,因此我认为3-5个人是一个比较合理的小组规模。
我曾经跟某企业做技术交流,他们的开发人员是一个人负责多个服务与项目,结合上文叙述的经验角度来看,存在以下三个问题 :
- 一个人负责多个意味着微服务拆分过细,这个时候思考是否有必须这么细的粒度拆分;
- 容易造成人员单点维护的问题,容易形成“知识孤岛”、“非他不可”的局面;
- 应该为团队定相同的目标,共同为业务系统负责。
小结
上文我主要从软件工程的两个角度(业务需求与组织架构),分享了对微服务的理解。
微服务虽然改变了系统、服务之间的架构模式,但也需要足够的组织架构和软件工程与之支撑。技术服务于架构,架构服务于业务,业务服务于商业,这是我架构设计以来坚持的原则,一切的技术与设计,最终用来服务于业务需求,反之,也是商业与业务成就了技术,抛开业务讨论的技术与架构无疑是“耍流氓”的。
抽象与复用
我认为抽象思维,是我们程序员最基本也是最核心的思维方式,抽象思维结合了共性、类比方法,从问题的“质”的角度进行分析与思考,让我们的关注面主要放在对象、动作与关系,使我们减少了因为具象的细节引起的钻牛角尖的情况,恰好架构设计需要我们具有大局观的能力,而大局观的本质正好是抽象思维。
抽象性
从架构设计思想的抽象角度出发,我认为架构设计的目的主要有三点:确定运作方式、确定职责边界与确定交互方式。
回到微服务,分而治之的本质思想就是"拆",拆是为把耦合性较低的模块是独立成进程进行运作,拆后还得整合把具有关联的服务给组织起来。因此上文的三个设计目的和《Microservices》原文与之对应的三大特性为:
- 通过服务代替组件(Componentization via Services)
- 分而治之(Decentralized Governance)
- 强服务和弱通信(Smart endpoints and dumb pipes)
复用性
在早些年微服务还没盛行的年代,我们或多或少接触的应用,他们引用公共模块是通过"库"的方式提供的,使用“库“的是为了把具有共性的(抽象性)逻辑模块分离出来,以至于达到物理层面的复用,我们称之抽离出来的单位叫组件(Componen)。
原文:
When talking about components we run into the difficult definition of what makes a component. Our definition is that a component is a unit of software that is independently replaceable and upgradeable.
译文:
在谈论组件时,我们遇到了如何构成组件的困难定义。我们的定义是, 组件是可独立更换和升级的软件单元。
然而使用这种“库”方式会两个缺点:
- 如果一个应用引用了10个“库”,任意一个“库”更新了,整个都需要全部更新上去。(一应用、多个库)
- 如果一个“库”被多个应用引用,如果该“库”出了问题,每个涉及到的应用都更新一遍。(多应用、一个库)
由于以上的问题,我们把这些公共引用的"库",改造为可独立部署的进程进行运作,可独立部署就意味着,只要保证服务之间的通信协议统一性,剩下服务内其他实现,我们就可以自由发挥了——技术异构性。
技术异构性
我认为在信息系统角度的技术异构性主要分四个层面:硬件、操作系统、开发语言、存储系统。在《Microservices》原文Decentralized Governance模块提到,不希望开发人员拥有锤子后,就把任何问题视为钉子,通俗点说,就是希望我们根据不同业务场景、解决方案,去选择对应的技术或开发语言。
因微服务的自治性,给与拥有服务的团队按需部署与选择技术栈的机会,让他们委派决策和控制权,我将从战术与战略两个角度出发跟大家分享我的观点:
从战术层面出发,每个技术人员都会有自己擅长的方向,或许有些人认为,更新换开发语言、更换技术方向不就是换个工具而已这有什么难的?我认为,更换技术方向成本并不在于语言,而是在语言所属的生态与改技术方向的思维。
举个例子,C#可以写做客户端与服务端,但是客户端与服务端的技能生态、设计思维有着本质上的区别。如果是服务端的从C#转Java因语言的特性相似,无疑成本是非常少的,但是我们得熟悉Java语言的生态,例如主流框架、工具、插件等,甚至得踩一遍底层上的坑,例如JVM调优等。
因此,我认为并不存在在某个领域方向很厉害的人,在别领域也同样厉害的说法,经验、知识都是需要时间、实践进行积累的。
再进而回到微服务上,我们并不会刻意去制造技术的异构性,在相同业务领域里,在原有的成熟技术并且能满足业务需求情况下,我建议不要刻意去更换,特别是整个团队。
从战略层面出发,我们关注的是团队与架构,团队与架构都有个共同点,抉择与取舍。在有必要的时候,我们根据业务的发展情况按需扩展。
举个例子:假如现有公司的已有完整的业务模式,需要基于已有的业务继续发展,作为团队负责人的你,对于技术团队采取的策略主要两点:降本与提效。
因此你增加原本团队成本30%基础上成立了一个ToB的低代码团队,在未来半年内出第一个Beta版本,并在一年内投入公司内部生产使用,且预计提高后台系统的300%的开发效率。低代码开发平台,则选择小组组长最熟悉的.Net平台开发,而原有Java团队交接了后台系统的项目,团队人力成本根据业务情况相应的减少10%-20%。
Not Only SQL
上文的异构性主要从开发语言与技术选型角度进行叙述,如今这个年代,无论做什么类型的信息系统,基本上离不开存储系统。
NoSQL的特征与类型
20世纪80年代,关系型数据库陆续诞生以来,占据着存储系统的主导地位。随着21世纪的互联网崛起,关系型数据库在高并发与海量数据的场景上,表现的力不从心,而NoSQL的高性能、横向扩展性、多种数据库结构等各种优点,弥补了关系型数据库的不足。在如今的年代混合存储的模式已经是随处可见,NoSQL与关系型数据库的关系,也成为了相辅相成的存在。
马丁·福勒早些年著作的一本书名为《NoSQL精粹》,其中他对NoSQL无法下具体的定义,但是他认为有以下特性的可称之为NoSQL:
马丁·福勒在书中也总结出了共有四种类型的NoSQL,但我个人认为搜素引擎应作为第五种的补充:
去中心化存储
咱们越是保证了微服务的自治性,去中心化的优势越是更加明显,微服务其中一个特性是非集中式数据管理(Decentralized Data Management),微服务可以根据领域内的业务特点选择合适存储系统,就如上文所提到的技术异构性的存储系统。
关系型数据库在高性能、海量数据与扩展性会有一定的局限性,因此现有的互联网系统不单纯把关系型数据库作为它们唯一的选择,混合型存储才是未来的主流。
简单举两个例子,键值型的Redis作为代表,可以存放会话信息、购物车、缓存等临时性的热数据。搜索引擎以ElasticSearch为例,可以代替关系型数据的Like搜索,也可以作为海量数据业务的Query端的存储。
咱们后端开发的核心关注点,主要以数据读写为主。毫不夸张地说,如果后端开发能把常用的存储系统(关系型与非关系型)了解清楚,在对应的业务场景的选择合适的存储系统,此外对已有的业务,能根据业务特性提出优化方案,相信我们在日常遇到的80%问题都能迎刃而解。
因篇幅有限不再做具体叙述,我这里提供两篇曾经记录存储系统优化的文章,可以供大家参考《后端思维之数据库性能优化方案》和《记一次引入Elasticsearch的系统架构实战》。
总结
到这里,今天这一讲就已接近尾声了。关于前面分享的诸多内容点,为了帮助你快速回顾、梳理、思考,我将全文内容的行文框架、每部分侧重讲解的内容等,整理到图中,这样看的时候,也更直观、明晰,以便于帮助你理解、记忆。
整篇文章的篇幅稍微有点长,最后结合我今天分享的内容,再与你交流下我的一点想法、观点等,此外也算是进一步给大家做了个文章的升级版总结。
从微服务的发展来看,微服务不是马丁·福勒创造的,但是他在推动微服务的发展方面,还是起到了非常重要的作用的。我不是马丁·福勒老爷子的黑粉哈,我还是非常建议大家多看几次老爷子的作品,每次看都会有新的感悟。
虽然我自己很喜欢微服务,包括我最近的时间技术关注点都在微服务上。当时我仍然认为微服务并不能解决一切的技术问题,还是那句老话——没有银弹。微服务给我带来了不少的良性成长,但是我也不会逢人就吹嘘它,因为微服务有它的优缺点,我们得对结合具体问题选择方案,而不是强行地把方案硬塞到某个问题上。
毫不夸张地说,80%的信息系统,甚至可能到90%,如果从客观中立的角度出发、分析,都是不需要用上微服务的。因此,要是您选择了使用单体,正在处理您的项目问题,这并不是一件丢人或者觉得很low的事。
我个人认为微服务的引入,更加侧重的是从软件工程的角度出发考虑的,大家可能听到的什么性能问题啊、高并发啊或者别的问题,选择微服务更多是充分不必要的。
另外再提一嘴,微服务它的本质是无法解决性能问题和高并发的,大家在这里可以停下想想,信息系统的性能问题主要瓶颈在数据库,所以调优方案应该从存储系统的类型、设计、架构方案进行选择;高并发方案,无非是从集群、NoSQL、静态和消息队列这些角度出发进行选择。只不过微服务实施后,它的自治性特征,可以使得系统在这些高性能和高并发的场景中,拥有更多的扩展余地。
好了,到这里我们就要结束了,非常感谢你耐心的阅读,后面的分享再见。同时期待后续的某几个时段里,我与你能够有更多思想上的交流、碰撞。如果愿意分享,这一讲也欢迎转发给你的朋友,和他一起讨论。还有,对这一讲的内容分享,有疑问或是不同的差异化、多元化想法,可以提出来,留言区里,我们多交流。