2012 年 James Lewis 在波兰第 33 次 Degree in Kraków 会议上分享了一个案例,名称是 “Micro Services - Java, the Unix Way”。在这个分享里,James Lewis 分享了在 2011 年中参与的一个项目中所采用的一系列实践,以 UNIX 的哲学重新看待企业级 Java 应用程序,并且把其中的一部分称之为“ Micro-Services ”。总结了五大特征:
Small with a single responsibility —— “小到只有单一原则”
Containerless and installed as wellbehaved Unix services —— “去容器化并且作为 Unix Service 安装”
Located in different VCS roots ——“分布在不同的版本控制代码库里”
Provisioned automatically ——“自动初始化”
Status aware and auto-scaling ——“关注状态和自动扩展”
2014 Martin Fowler 试图将 James Lewis 的微服务定义进行一般化推广,使其不光可以在不同的语言架构和技术栈上使用。又可以兼顾敏捷、DevOps 等其它技术,成为一个架构的“最佳实践”集合。提出 9 大特征:通过服务组件化、围绕业务能力组织、是产品不是项目、智能端点和哑管道、去中心化治理、去中心化数据管理、基础设施自动化、为失效设计、演进式设计
2016 年 Sam Newman 《Building Microservice》4 个特征 7 大原则。
4 大特征:可以独立部署。通过网络通信。对消费方的透明。尽可能降低耦合,使其自治。
7 大原则:围绕业务概念建模、接受自动化文化、隐藏内部实现细节、让一切都去中心化、可独立部署、隔离失败、高度可观察。
这里澄清一个观点,在工作过程中偶尔会听到某些同学说,我使用了 Dubbo ,使用了 spring-boot ,或者使用了 Spring-Cloud ,我开发出来的系统就是微服务。个人观点,微服务是一个架构风格或者架构原则,与实现系统的框架无关。比如:一个系统满足了上面的特征和原则,使用 WebService 通讯,难道就不是微服务吗?当然实际实施过程中应该选择一个轻量级的通讯框架。
微服务从 2014 年在国内开始传播,到现在已经有 5 年时间里,关于微服务的优点论述的文章有很多,比如逻辑清晰、简化部署、可扩展、灵活组合、技术易购、故障隔离等等这就不做详细展开。
全面微服务化带来的挑战
1. 可用率降低
全面微服务化之后,原先的单个应用可能会拆分为多个独立进程。为避免进程之间争用资源,一般公司都会独立部署,即单个虚拟机内只部署一个 jvm 进程。由此带来了更多服务器、网络设备、安全设备,这些硬件设备的可靠性都会影响到业务连续性。
服务跨进程间通讯,必然要选择一种通讯协议、序列化框架,额外引入的代码可靠性也会对整体的可用性造成影响。因此,微服务的设计是需要面向故障进行设计,在设计要考虑重试、幂等、故障隔离、熔断、降级等等。
2. 事务复杂度
微服务拆分后,虽然按照领域模型做了解耦,但不可避免会带来分布式事务问题。目前分布式事务在社区也有一些解决方案和开源框架,方案有基于消息队列最终一致、TCC 分布式事务框架以及自动化的分布式事务框架,例如 Seata 等,但分布式事务的处理,对开发人员设计要求比较高,使用成本较高。
在拆分的时候,建议还是尽可能避免分布式事务,引入分布式事务框架要评估成本和收益。
3. 运维复杂度
当一个单体应用拆分为多个微服务之后,应用数量会大幅增加。如果没有一个可靠稳定的运维平台或资源编排平台(如 k8s ),全面微服务化,对运维就是一个灾难,工作量的大幅增加,直接会影响系统稳定性进而影响到业务连续性。
4. 调试优化复杂度
应用拆分后,业务调用关系变复杂,调用链整体变长。如果没有一套合适的调用链追踪平台,很难定位到整个系统的性能瓶颈,调优成本很高。另一个问题是,生产环境业务数据异常时,由于调用链过长,如果没有规范的 Request、Response 日志,很容易造成各服务之间相互甩锅,难以定位问题。全面微服务化之后,由于众多的服务节点,调优排查错误更加依赖于日志平台,高性能的日志平台也会提高效率。
5. 测试难度
在单体应用的时候,调用链路短,一般都是做黑盒测试,测试人员无需了解复杂的业务实现。而进行微服务改造后,单个业务可能会由多个服务组合编排完成,如果继续做黑盒测试,意味着必须等待所有服务开发完成之后才能进行,导致测试周期边长、定位困难,做边界测试需要更多的测试用例才能覆盖,测试整体成本会变高。这种情况下,单元测试、单系统测试的重要性就凸显出来了。如果需要做单系统测试,可能需要 mock 被调用的服务,通讯协议使用 http 还好,社区有很多开源的框架可以使用。如果是 RPC 框架,意味着需要准备一套好用的 mock 测试系统才能支撑单系统测试。
6. 聚合查询
在领域建模的时候,一般是按照用户角度去划分,而运营需求与用户需求天生不是一个维度的。举个例子:按用户维度领域建模,会划分用户服务、订单服务,用户和订单数据存储在不同的数据库,假设运营有一个需求是查询某个年龄段用户的订单,在用户达到千万级的时候,这种需求对微服务体系是个灾难。需要一个强大的大数据平台对数据按业务维度进行聚合,才能满足运营的查询需求和报表功能。
微服务拆分原则
微服务拆分原则中,特别需要提到的是康威定律。
康维定律简单来说就是系统设计(产品结构)等同组织形式,每个设计系统的组织,其产生的设计等同于组织之间的沟通结构。如果单个服务由不同组织管理,需求无法达成统一,面临着令出多头、需求干扰的风险。
伸缩需求,同一个进程之内的不同业务功能,有时在业务量方面会出现较大的差异,具体要求的进程数量会有较大差别,这样的模块锁定在同一进程之内,势必会造成资源的浪费。
部署频率,同一个交付物内不同的组件有着不同的上线频率,会大大的提高上线流程的发生频率,会造成较大的人员浪费。
修改的相关性,如果同一交付物内的不同组件,经常会被同步修改,这可能说明,如果发生拆分,这两个模块应该是”在一起“的。
领域建模,针对业务领域,引入限界上下文(Bounded Context)和上下文映射 (Context Map)对业务领域进行合理的分解,识别出核心领域(Core Domain) 与子领域(SubDomain),并确定领域的边界以及它们之间的关系。依据核心领域和子领域划分微服务边界。
对于一个单体应用,拆分过程应该是循序渐进、逐步拆分、由简到繁、由粗到细,是一个渐进的过程。例如先将有明显边界的业务拆分为独立服务,无法明细边界的先混在一起,等业务需求逐步清晰后再拆。拆分时先拆分为几个相对较粗粒度的服务,根据业务需求情况,逐步将粗粒度的服务中相对稳定,可以沉淀的业务拆分为独立服务。在这个过程中,原有的单体应用也可以承担部分兼容能力,在改造完成前,不对外部系统造成过大的影响。
微服务的拆分是跟业务需求强相关的,如果业务需求变更不多、相对稳定,处理的请求并发量不高,单体应用的稳定性和可维护性更好,更加适用。
总结
微服务不是银弹,是用来处理海量用户、业务复杂和需求频繁变更场景下的一种架构风格。引用一句话“好的架构是演化出来的,而不是设计出来的”。任何一种架构的引入,都会带来利弊两个方面的影响,如何平衡才最重要。
四川新网银行是全国三家互联网银行之一,于 2016 年 12 月 28 日正式开业。新网银行注册资本 30 亿元,由新希望集团、小米、红旗连锁等股东发起设立,是银监会批准成立的全国第七家民营银行,也是四川省首家民营银行,同时也是全国第二家获得国家高新技术企业认定的银行。新网银行坚持“移动互联、普惠补位”的差异化定位,以及“数字普惠、开放连接”的特色化经营,着力打造成为一家数字科技普惠银行,依托领先的金融科技能力、稳健的大数据风控技术和高效的互联网开放平台运营模式,服务小微群体、支持实体经济、践行普惠金融。截止目前服务用户数 2900 多万,累计放款 9000 多万笔。
作者介绍:
谢延泽,目前就职于新网银行,负责技术中台建设,核心系统技术架构设计。关注云原生领域,探索在金融行业实践思路。
本文转载自公众号阿里巴巴中间件(ID:Aliware_2018)。
原文链接:
评论