Skip to main content

我理解的架构 & 架构师(兼谈微服务)

·6270 字·13 分钟
系统设计·架构 microservices
Table of Contents

一个好的架构离不开三个核心东西:问题、技术、人

不同的架构师 #

types-of-technology-architects

 软件开发是以最终产品为导向的,所以本质上我倾向把自己当作软件工程师或者系统架构师,软件产品的制造者和拥有者。下面的内容比较杂。

我理解的架构和架构师 #

从事商业性的系统开发超过二十年了,经手的 mission critical 系统最少也有十几,二十个,对自己最擅长的方面做个总结。

  • 架构 architecture 来源于建筑行业,架构就是 blueprint 实施蓝图。软件架构的实质还是软件,也就是代码 ⏤ 架构师自己如何编写码,只是没有全部亲自做出来。对于复杂系统,架构应该是系统设计之上更高级的抽象,我认为的架构,系统设计,和代码应该是同源的,划分代码,组织代码,运行代码,支撑代码,等等,都是以代码为核心。

所谓架构和系统设计,其本质、基础、核心都是编写代码,也就是架构师给出的代码结构,脱离代码的架构设计都是耍流氓,不能解决业务问题的程序也是耍流氓。

  • 系统设计和软件如何编码一样,范围很广,基础理论杂,主要还是来源于实践经验,里面的很多设计决定和哲学观点类似。所以不仅仅是懂怎么做的,更多是体会为什么要这么设计,所以遵循原则很重要虽然都是些大白话,如 SOLID 原则:
    SOLLID
    不过我更喜欢/倾向从代码角度看待架构,架构和系统的本质还是编程,系统级别的编程,所以编程的一些经典原则也非常适用:
-   DRY Don’t repeat yourself
    系统设计中你碰到的问题别人都已经碰到过了,向高手学习他们的解题方法。另外,别重复别人的错误。

-   KISS:Keep it simple, stupid!
    我更喜欢解读成 Keep it stupid, so it can be simple(笨方法往往是最好的方法)。

-   Avoid Creating a YAGNI:You aren’t going to need it

-   Abstraction Principle

-   Minimize Coupling
    如果代码的力量来源抽象,那么系统的威力就来源于解耦,“抽象”和“解耦”两根大棒,但不要“滥用”(有代价),架构设计的好坏往往就体现在“抽象”和“解耦”的能力上。

-   Separation of Concerns

-   Single Responsibility Principle

-   Maximize Cohesion
    像搭积木一样,解决问题和写代码时尽量采用组合或延续的办法而不是从头开始,consistency 是软件工程质量的关键。

-   OCP Open/Closed Principle
    开闭原则 (OCP) 指出软件实体(类、模块、函数等)应该对扩展开放但对修改关闭。这意味着可以在不修改源代码的情况下扩展软件实体的行为。完整性和灵活性是架构师和优秀程序猿时常考虑的问题,也是和菜鸟的区别所在。

-   Don’t make me think
    把问题讲清楚,问题已经解决一大半了。

-   Principle of least astonishment
    一切和预期的一样,no news is good news。

-   Avoid Premature Optimization

系统设计一半是科学,一半是艺术,优良的系统设计遵循编程的原则和模式。

  • 复杂系统的设计是需要有技术手段做支撑的,架构师本身必须是个很好的程序员,具备相当的“深度”与“宽度”。所以架构师必须爱好学习,持续学习,持续编码,保持对最优秀技术的敏感度,才能设计出真正优秀的架构。

复杂系统的设计是需要有具体核心技术做支撑。

  • 面对的是复杂系统的设计,通常没有固定的对错答案和所谓的 silver bullet。一个优秀架构师的成长需要经验积累,这和通常单项技术被动学习有所不同。一个优秀架构师最重要的能力是分析和抓住复杂事物的本质。例如五代战机的特点就是 4S - 隐身性能、超音速巡航、高机动型和超视距打击,五代战机的设计核心就是回答如何实现 4S。架构师最重要的能力还来源于深度思考,学习的不只是技术本身,还思考技术的前因后果,思考解决问题的方法论 ⏤ 也就是套路,不断归纳和总结。

系统设计具有非常强烈的问题驱动 + 架构师自我思考 + 可实践的特点,优秀的架构必须能够回答系统的核心问题是什么,解决的关键方法是什么。

  • 通常程序员只是一个人在编码,向组长负责。而架构师需要面对不同的 stale holder,带领一大群人编码完成项目,需要很好工程能力以及跨领域的知识。 一个优秀的架构师对系统设计考虑的问题必须全面,内部的,外部的,看得到的,看不到的,现在的,将来的,技术的,非技术的,例如新技术的成熟度,实施该模块团队的技术储备,用户体验,项目的资金和时限,承受风险的能力,管理上级和客户期望,领域趋势,等等。这些东西都是不能从书本直接得到,而需要经验的积累。

系统设计是一个架构师对技术,人,问题综合理解的体现。

主要的架构模式 #

10 Architecture Patterns Used In Enterprise Software Development Today

更多可参考:

微软文档:Application design patterns

solution-architecture-patterns

分布式系统的学习 #

微服务 #

微服务是什么和为什么 #

4、5 年前就开始了所谓的微服务(Microservices),做过布道,做过大规模实施。 微服务是什么,众说纷纭,可惜听起来还是不甚了了。我的总结:

微服务 4 个特点
设计解耦 design independently
商业拆分
这里讲的架构不是技术架构,而是商业逻辑架构,这在大层面上决定了软件如何拆分,这可以应对商业需求在情况下不明确或者比较复杂下,先找出"基本解"。design independently 接下来的好处就是各部分的开发是可持续演化性(continuously evolutionary),而单体架构(monolithic),在商业不明确或比较复杂情况下,特别是创业公司,设计上无法完全确定下来,导致开发迟迟无法开动或完成;同时一个部分的变化会直接引发整体做出变化,这导致两种恶性后果,一是某一部分成为瓶颈拖累整体,另一个是开发后,大家都无法持续改进。例如典型的三层架构,很多表,很多代码都是和自身负责的模块无关;一个小改动整个项目需要重新构建;某个底层库由于各个模块都依赖,到了一定时候,各个模块的视角不同,有的模块想改进这个库或采用完全新的技术,但动不了了,成为技术瓶颈或死结,所谓的 legacy,重构无望,这时候只有等更高层做决定,推倒重来。注意微服务不只是技术拆分,因为,代码技术上是可以做到随意拆分,而企业或商业运作是不能随意拆分的,拆分需要符合体制和流程,微服务的系统最终由人来运作,所以不是所有的项目都适用微服务架构。
技术解耦 implement independently
多元化技术
要体现微服务的最大威力一定是采用 polyglot,已有的软件解决方案可以直接采纳,管他是 javascript 还是 python 开发的,管他是自己开发还是他人已经提供的,也不管是通过 lib 或者还是 api。传统的 java 或 .net 包头包尾,一种数据库,一个通用数据层,要承担不同的技术考量,结果自然局部非最优解。技术解耦带来了技术革新,例如各种 nosql,而且在不同公司,不同项目中可实现重用,实现快速开发,宏观层面上发挥了最大效益。所以微服务属于八仙过海各显神通,不再是单一的三层架构,从一层(如 serverless),到 n 层,都是可能的。
资源解耦 sourcing independently
游击队战术
一个 service 团队的规模不超过两个 pizza。小团队才能带来快速灵活技术和快速迭代,“大象能跳舞”是个伪命题。要注意的是游击队战术不是适用所有的企业和商业模式,也不是所有的企业具备游击队的人员结构,所以微服务不是每个企业都适合的。
部署&运行解耦 deploy&run independently
自动化运维
自动化运维(DevOps)不是微服务特有的,在现有的项目或系统上完全可以实施自动化运维,也可以看到巨大效益,CI/CD 在微服务提出之前已经存在了。但自动化运维是实施微服务的必备技术,拆分和 ployglot 后对自动化运维提出了很高的要求,一堆不同质的东西可以单独部署,升级,同时又要组合在一起无间隙运行。容器技术的出现,对微服务所要求的大规模自动化运维提供了必要的技术基础。

微服务的核心仍就是沿用模块化式思路设计整个系统,目的是达到软件的可重用可扩展

纵观开发历史,微服务不是什么新东西,仍旧是代码的拆分和集成,和 component-based 或 SOA 是一致的,只是层面不同。微服务不是针对小型软件或者单个项目层面,因为大部分的软件项目还没有等到解耦,拆分,长期演化成为”硬“需求,项目已经结束或者死掉啦。但反之,不同技术实力的团队,不同的项目,不同的地点,不同的时间,重复开发和实现,微服务解耦特性就能把软件的复用和扩展价值发挥出来,否则都是在做 silo application/project。所以微服务在政府,大公司或大型项目中推广和应用才能发挥其威力。

另外,微服务还包含了开发团队的架构,运维的架构,这是和以往的纯系统架构概念非常不同的地方,也是实施微服务可能忽略的地方。微服务同时锁定了以 service 为导向的开发和运维模式。

抓住微服务以上四个特点和目的后,很多疑问就迎刃而解。

微服务的技术栈 #

如果在 IT 界呆得够久,了解分布式一路走来的历程,就会明白“微服务”从技术讲没有什么特殊的新问题,微服务技术本身就是分布式系统不断演化至今的产物,只是技术手段的不断翻新,技术点包括:

microservices-stack

在我看来,注册配置数据一致性链路跟踪,是微服务必备的技术点。

对应每个点都可以找到相应的具体技术,微服务的老大和先行者是 AWS,可惜它不开源。业界广泛的开源方案就是 Spring 系列的 Spring Boot & Spring Cloud,另一套是正在兴起是基于容器和 Kubernetes 的 服务网格(Service Mesh)。Spring Cloud 虽然是目前最成熟的方案,但从技术高度讲,我认为是开倒车或者说属于第一代的技术尝试(对比以前的 Corba,DCOM,J2EE,Web Services),不是发展大方向。以 Cloud Native 为基础才是微服务的明天,但是目前火热的 Service Mesh 仍然不成熟。

“坑” #

代码和工程的质量仍是软件的灵魂,拆分和集成并不意味着可重用/可扩展就是必然。相对 monolitch,微服务/分布式系统对技术/人其实提出了很高的要求。如果你不能设计一个优良的单体系统,那么微服务也帮不上忙。

  • 复杂的系统设计商业从来不是 decouple/loosely coupled 的,系统集成依旧是所有复杂商业软件系统设计的难点和关键点,越复杂的系统越需要系统性的设计,微服务设计上往往倾向 decouple/loosely coupled 使系统设计难度陡增。

    一个好的 API 设计已经如此不易,想要设计优良的、对外的、可复用的 service 对大多数小团队其实是无法胜任;
    服务的拆分很容易变成 premature optimization(一开始时就拆分而不是系统成熟时或对系统有成熟认识时拆分),做着做着,Json 和 REST 会变得越来越臃肿,理论上可以各自演进,实际却极大可能从一坨屎变成一坨一坨的屎 💩💩💩;
    Domain-Drive Design(DDD)从来都是个纸上的东西,正确的废话而已,拿来做服务拆分没有太大的帮助,没过几年又会拉出来炒一炒,因为那是个可以忽悠人的好东西;
    所有的微服务拆分之后还要合成一个有机的整体,系统控制和设计不会因为拆分而消失,反而因为拆分而在整体上大大增加数据和系统正确性的难度,统一的系统设计尤其重要,系统如何正确控制和响应各种 分布式系统之殇 Fallacies of distributed computing

    经典的分布式设计或编码 8 种错误假设:

    -   网络是稳定的
    -   网络传输的延迟是零
    -   网络的带宽是无穷大
    -   网络是安全的
    -   网络的拓扑不会改变
    -   只有一个系统管理员
    -   传输数据的成本为零
    -   整个网络是同构的
    

A distributed system is one in which the failure of a computer you did’t even know existed can render your own computer unusable.

对于分布式系统和“大规模”分布式系统,99%的开发人员包括架构师都没有“足够”的实战经验
  • 复杂的分布式编程

    系统实施一致性:大规模的微服务实施往往变成一抓就死,一放就散,游击队战术的引入,各组人马自行乱搞,各种 style,违背了 KISS 和 DRY 的金典,引入更多更复杂的技术,反而使得整体性变得异常复杂,脆弱,低效和难以维护;
    代码可读性下降、出错性上升:异步调用促使程序的碎片化,增加了流程处理和错误处理的复杂度,降低了程序可读性,响应速度,以及数据处理效率;
    程序性能下降:基于 Json 的 REST 还是序列/反序列 RPC 调用增加了数据的正确性和完整性判断,同时调用链急剧加长;
    系统效率下降:采用微服务后,除了把变更数据记录在本地数据库外,还对外广播,同时无形把网络流量拉升若干个数量级,同时相同或类似的数据拷贝存在无数个拷贝和版本(AWS 案例 Scaling up the Prime Video audio/video monitoring service and reducing costs by 90% - Prime Video Tech);
    并发问题:由此而导致奇怪问题次数大增,如网包或 message 丢失,同时 debug 变得比较困难;
    异步计算挑战:分布式系统调用除 RPC 外就是消息系统支撑的 Event Driven Architecture ⏤ 异步是系统集成最主要也是最重要的手段,ESB(Enterprise Service Bus),Event Sourcing,CQRS,Streaming Processing,还有更隐晦的 Reactive Systems 等等,被推崇得像一粒粒银弹/迷魂弹,底层是世纪性的难题 - 如何确保消息的可靠性,顺序性;
    分布式事务以及数据一致性:另一个世纪性的难题,网上那个鼓吹很多的 saga pattern 也是出自那些 evangelist 或者所谓的 paper architect,用来解决复杂业务数据一致性问题基本是不可行的;
  • 复杂的基础设施:运维,监控,调试,恢复手段对微服务尤其重要,例如死信队列,流量重放,数据高可用,动态日志,容器化应用,蓝绿部署,等等

  • 复杂的工具和管理:除了这些直接的运维手段,还有需要各种工具应对接口设计,编码质量,设计文档,项目多模块管理,自动化回归测试等等

微服务的小结 #

  • 微服务不是新鲜事物,本质是分布式系统;
  • DevOps 必须先行;
  • 微服务架构只覆盖了软件基础架构,系统设计依旧要在整体上回答如何统一完成各种商业需求;
  • 复杂度加大,开发体验下降,对开发者要求提高;
  • 貌似对单一服务的改动更为快捷,但复杂系统的微服务整体实施难度徒增,实施必须谨慎,相当谨慎;
微服务的技术本质是:分布式系统

评论 #

Beyond Microservices: Streams, State and Scalability • Gwen Shapira • GOTO 2020
Seeing this pattern so many times - microservices and event-driven have values but overemphasising the goods and dumping traditional design around apis and db, the system “may” end up with much worse things - event schema vs. normalized db schema, bloated message vs. concise api, building on top of every single piece of event vs. building on top existing modules and functional apis, etc.
Microservices Architecture From A to Z
Overall quite good article, I have 2 things to point out according to what I learn: 1. in principal SOA is same as Microservices, it was just focusing on integration of different systems, so it was not meant for reusability, scalability, ops agility like Microservices; 2. Choreography is a big mistake and most Microservices advocates go for it. The design of softare architecture is tended to be decoupled/distributed but business never be like that and the system design should be always united and integrated. Distributed logic (business or funcational) is just too complicated to get it right especially for a modern business. We all know No.1 rule is to avoid distributed computing. For common or supporting components/services, I will follow choreography pattern. But for core services belonging to the business process (e.g. in e-commerce: shopping cart, warehoursing, payment, accounting) I will stick with orchestration design. I have learned this through a few very big Microservices projects in different industrials.
Microservices Database Management Patterns and Principles
Unfortunately under the context - catalog, shopping cart, ordering, i think, the anti-pattern is the best solution. When in the ideal case to go for microservices, database-per-service is the best practice, the others are actually anti-patterns - its not practical to do that with a huge microservices system and I am strongly doubt those advocates have handson experience. CQRs, Event Sourcing, and Saga, are more like patching approach because the system has been designed as microservices when it is not necessary.
Why Agile Sucks for Building Quality Software
What you are saying is perfectly correct, but then what Agile brings on table specifically for building good software? Agile is not helpful because in reality it focus on the process instead of the meaningful techniques. Agile is more about methodologies and it can come in different forms. So i wont think it sucks but it does not help. Good developers/teams/architects are agile by quality.

熵增 #

以下是 5 个令人惊奇的事实,说明了软件行业在调试和代码修复上到底花费了多少时间:

  1. 平均而言,开发人员每 1000 行代码就会产生 70 个错误
  2. 每 1,000 行代码中有 15 个错误被客户发现
  3. 修复一个 bug 比编写一行代码花费的时间多 30 倍
  4. 开发人员 75% 的时间花在调试上(每年 1500 小时!)
  5. 仅在美国,每年就花费 113B 美元用于识别和修复产品缺陷

注意,这和所使用的编程语言和技术栈无关。99% 的软件项目都是被“复杂度”杀死的,而这是微服务/分布式系统的死结(参考经典文章: How Complex Systems Fail)。作为架构师,抛开各种技术和复杂表象,其工作核心就是: 对抗熵增(We want to fight entropy),而这往往是大家都挂在嘴边,但和最后大家所做所为却恰恰相反的

complexity