微服务架构与领域驱动设计应用实践-程序员宅基地

技术标签: java  consul  编程语言  分布式  软件开发  

本篇文章一共分为三个部分,分别是微服务架构的演进过程、具体实践微服务的应用技术和领域驱动设计的意识转变。微服务架构已经渗透到互联网应用的方方面面,而领域驱动设计也逐渐被业界所接收。

微服务架构的演进过程

微服务架构几乎都是从 ALL IN ONE 的单体架构演进而来,中间又经历了分布式架构、面向服务架构的演进过程。

单体架构往往以烟筒式方式发展,往往存在两个主要问题:中心化和耦合度高。所谓中心化,就是数据集中存储在单个数据库中,业务系统集中部署在单台服务器上,通过集群部署方式提供服务能力,然而中心化的问题,也就是单点问题。而耦合度高,主要是指其中一个功能模块升级,其它的模块都得一起升级。这里要说明下,模块依赖度高不是单体架构的错,是因为本来架构可能就没有设计好,但是,在实际场景中,随着快速迭代开发,研发换了一波又一波,产品走了一茬又一茬,难免系统架构腐化严重。

看到了单体架构的诸多问题,系统开始通过按功能或模块进行拆分,拆分成多个独立的子系统,系统间通过 RPC、MQ 方式调用,由此逐渐演变为分布式的服务架构。分布式服务架构主要通过服务化和层次化进行解耦拆分,《架构整洁之道》书中提到一点,系统可以降解为策略和层次,而架构设计就是把相同的策略分到同一个组件中,反之,分属于不同的组件。所以,架构设计可以通过分层设计,由高层次服务调用低层次服务,低层次服务通过接口向上提供服务,以实现系统之间的解耦。也正是在这一阶段,单体架构一下子被拆分成几个或几十个系统。

但是随着架构的发展,问题又接踵而来,在没有做好边界的划分之前,系统拆分的服务往往是松散的。正如《架构整洁之道》所讲:软件架构设计本身就是一门划分边界的艺术。所以,很多系统在这一阶段,又往往进行了服务内聚和去层次化的演变过程。所谓服务内聚,就是以领域驱动设计为原则,重新界定领域边界,对模块进行服务整合,对系统进行合并。而去层次化,则是去除服务层次高低之分,按服务调用最优链路提供服务请求,降低深度,以此保证系统的稳定性能。

具体实践微服务的应用技术

系统如何从 0 到 1,从 1 到 2,从 2 到 100,在具体实践微服务的过程并不容易。首先,考虑的第一个问题是:微服务是什么?其实,微服务是一个动作:拆。说到拆,就涉及到两个问题,第一,怎么拆?第二,拆到什么程度。

第一个问题,关于怎么拆,需要关注两个层面,一是发版速度,如商品、交易、促销等不同领域的迭代速度和开发速度是不一致的,所以,应该拆分到不同的领域,否则,就可能耦合在一起,A 上线 B 必须跟着一起上,这可能就应该合并到一起。另一个是能源协同,每个系统后面对应不同的研发团队,一个项目往往需要几个团队分工协作,那么系统拆分必然导致团队协作的成本,所以拆分系统同样也是拆分团队,要考虑协作沟通所带来的成本。

第二个问题,拆到什么程度。其实,已经有很多人对微服务进行了定义,其中我认为最重要的两点:一是微服务或一组微服务,应该是一套独立部署运行的服务,二是微服务所依赖的数据资源应该是彼此间相互独立隔离部署的。

其实,拆只是实践微服务的开始,要搭建整体的微服务框架还要进行四部曲:拆、服务化、高可用、隔离。

服务拆分

微服务讲究拆分,那么多微才是微,以及,怎么才是比较合理的拆分。在架构设计领域,有一个大家都在讲的著名定律:康为定律,可以理解为:一个系统架构的组织关系是和团队的组织关系相匹配的。如交易系统会对应一个交易系统的研发团队,商品系统会对应一个商品系统的研发团队,这种职责明确的组织结构会使得系统开发更高效。

《未来架构》一书中讲过一个 AKF 立方体模型,从三个纬度讲述功能拆分、水平扩展、数据分区所产生的复杂度,如果只有一个系统,单台部署,单点存储,那么它就应该只是一个点,因为随着量级的增大,系统在每个纬度不断延长,逐渐成为一个庞大的立方体。

拆分可以分为系统拆分、功能拆分和读写拆分。如一个单体系统中,按照用户的交互场景看,门户首页可以拆分为前台系统,类目、商品、搜索等功能可以拆分到商品中心,订单、结算、发票等功能则可以拆分到交易中心,这就是简单的系统拆分和功能拆分。而有些功能较为特殊,如商详页,在读取时需要聚合读取,所以又可以进行读写拆分。

服务化

微服务首先需要有微服务基础设施,没有微服务基础设施,实践微服务就是一场灾难。以 SOA 落地方式为例,SOA 落地方式主要有:分布式服务化和集中式管理(ESB),分布式服务化的技术手段有 Dubbo 或 Spring Cloud 等等,必须有整套的如服务发现、服务订阅、服务监控、服务追踪、服务日志等微服务基础设置,才能进行微服务架构。不能简单只有 p2p 的服务调用就开始服务化,那是不现实的。

服务治理

当服务拆分的设计方案确认完毕,而服务化的基础设施也部署到位,那么系统往往一下子就会突然发布出成百上千个服务接口,就像一个网络一样,每个服务或微服务就像网中的一个节点,彼此之间关联和联系。但是,服务网络应该被设计成为一个有向无环图,否则,就是一团麻。如开始的时候,只是 A 调用 B,但随着业务发展,需要修改,但是因为对 A 不了解,就加个环节 B 调用 A,如此形成了环形调用,不仅逻辑复杂了,还降低了稳定和性能。

这里的服务治理不是讲中间件团队的服务治理,如超时优化、启动优化等等,而是作为应用平台对服务的治理。服务治理又分为三个阶段:服务梳理、服务界定和服务编排。所谓服务梳理就是梳理系统对外开放的服务化接口,包括服务的 provider 和 consumer,以及服务分组、动态路由等依赖的梳理,然后对拆散的服务进行归类、界定,确定服务领域从属性,依据领域模型重新界定服务边界,最后通过服务迁移、切换,对同一领域的服务接口进行服务整合,提供统一的服务出口,实现服务编排。

为什么要进行服务治理?那先来看看不进行服务治理的坏处。

微服务化拆分必然会在初期产生代码到处拷贝,没有一套代码,必然会造成复杂的扩散,如同样语意的 A、B 两个接口,如果 A 接口存在性能问题需要加缓存,那么 B 接口也会存在同样的问题,并需要同样的改造,这样复杂度就会到处蔓延,同时也无法实现统一的服务层架构,还有,如果同样语意或相似语意的接口太多,那么接口就是混乱的,无法实现有限接口的治理,如果系统出了问题,可能很难定位问题。业务逻辑是依赖于数据的,如果接口是混乱的,那么慢 SQL 等质量差的 SQL 就无法进行有效收口改造,同样就更加难以实现数据库拆分和解耦。综上,服务治理的过程就是从无序到有序的过程。

总结一下看从拆分到服务化的过程,就是将原来一个整体的服务打碎,碎成一块一块的零碎服务,然后再对服务重新归类、整合,形成一个一个新领域的、独立的服务。如单体架构就像一个宏伟的城堡,如果相对其中一个点进行调整和改造,那么可能面临着牵一发而动全身的风险。

微服务化就是以一系列小的服务去支撑一个应用的方法论。简明扼要的说,就是:分而治之。

服务高可用

服务拆分并服务化之后,是不是就完事了,不!真正的微服务实践才刚刚开始,简单提供了一个接口,是没有意义的,它必须具备高可用、高性能、高并发的三高特性,尤以高可用最为重要。保障服务高可用的方法有很多,如数据异构、多级缓存、超时与重试、熔断、异步并发、降级、限流、消息队列、压测与预案等。

重点说下数据异构,所谓数据异构,就是将通过顺序消费或并发消费的方式,订阅 MySQL 数据库的 binlog,然后通过消息,如 Kafka 等 MQ 方式,异地存储到缓存或其它数据源中,如 Redis、Elasticsearch 等。数据异构现在被普通使用,实现数据聚合,形成数据闭环。

在进行数据异构的过程中,需要关注几个关键点,一是 CAP 原则,即强一致性往往被舍弃,而采用最终一致性的设计。二是缓存,缓存在微服务架构中,不能被当成银弹来使用,使用缓存必须正视的问题有:热点缓存 & 大 Value 缓存、缓存穿透等问题。三是消息,消息现在还存在的问题有:延迟问题、消息的不稳定性(如丢消息)、消息的不确定性(如 timeout)、消息补偿、柔性事务等问题。而这些是微服务高可用架构实践中,不能不面对的问题。

服务隔离

隔离也是服务拆分的一种,为什么单独讲?因为服务拆分、服务化、服务治理和服务高可用都是在事前或事中可以做的,然而,有些系统已经成了某个样子,那么我们接收时,首先能做到的就是迅速对系统进行隔离,保证业务之间不互相影响,具体实践包括:进程线程隔离、集群/机房隔离、读写隔离、动静隔离、爬虫/热点隔离等。

领域驱动设计的意识转变

从单体架构开始,到分布式架构设计、微服务架构,再到现在领域驱动设计,作为实践微服务的架构师,思想上又有什么变化?

我觉得,程序员都是很闷骚的,但每个程序员心里都住一个大侠,金庸《笑傲江湖》里有气宗和剑宗之分,什么是剑宗,我理解就像是剑招、招数,如 Spring、Spring Boot、Spring Cloud,还有 Tomcat、Netty、Serviceless 等,这些技术、中间件、框架等就像脚手架一样可以帮助我们提高效率,但是,我们是否需要出现一个新技术就学习一个技术呢?而这就让我想到了气宗,它就像是通过对内在规律的掌握,打通任督二脉,实现融会贯通,正如《九阳神功》所说:他强任他强,清风拂山岗,我自一口真气足。如 Kakfa、Flink、Hbase 等分区可用性保障的设计思想都是基于 BigTable 的分区复制策略。

正是重心由外到内的转变,让我认知到,现在系统架构的发展,很多系统架构的复杂度,已经不是简简单单通过引入一些新技术或框架,就能降低系统复杂的。它需要大大的提前对风险、问题、隐患的预知,做到未雨绸缪。《从零开始学架构》书中提到:架构设计的发展历程就是在于降低软件系统复杂的历程。

《架构整洁之道》书中提到:一个软件系统存在的意义,是系统用来赚钱或省钱的那部分代码,那才是整个系统的皇冠明珠。所以,当拿到一个需求的时候,首先考虑的是要解决什么问题,它的问题域是什么,而不是先考虑用哪种技术去实现或解决这个问题,这是本末倒置的处理方法。

从领域驱动设计的角度来看,需求首先是问题域,属于业务边界的事情,梳理了解要实现什么功能和需求,然后在外延到工作边界,确认团队合作的方式,因为很多需求都可能需要跨团队合作的,最后才会到应用边界,即技术实现的解决问题领域。

上图是一个典型的洋葱头模型,它的思想就是阐述了从内到外的思考过程。然后,现实工作中,经常有人从外往内去考虑问题,从我过往的经历举例,一次是数据异构的方案,之前是采用 Storm,后来 flink 开始流行,我就将业务切换到了 flink,但是对于 flink 的调优不到位,从而影响了系统稳定性,还有一次是之前搜索用 solr,后来 es 开始流行,就像切到 es,但是 es 和 solr 两套搜索引擎的搜索排序结果是不一样的,最后,我们只能强奸了业务。其实,这都是不太对的。《架构整洁之道》也提到:良好的架构设计应该尽可能地允许用户推迟和延后决定采用什么框架、数据库、Web 服务以及其他与环境相关的工具。

理解领域驱动设计,需求或问题它开始于一个领域意愿,由领域专家和交付团队一起,输出统一语言和领域知识,统一语言可以是敏捷看板,因为一个团队是由产品、运营、研发、测试组成的,彼此之间是基于统一语言进行沟通的,然后定义领域边界,区分核心领域、普通领域、支持领域,其中核心领域就是由核心团队开发的,支持领域可以是外包等实现的,在通过映射上下文,确认限界上下文,最终确认系统应用边界。

采用领域驱动设计的六边形架构绘制了一张交易系统的领域边界图,不同颜色表明不同领域,U/D 代表上游和下游。这个图还不算完整,因为领域业务逻辑是要为端服务的,而通过对领域的梳理,可以通用的支持很多端。即表达为领域有界,端无界。最终,每个限界上下文即是微服务。

总结

其实,每个系统的微服务架构演进道路各不相同,所以,实践微服务不能一板一眼原封照抄,而是要根据自己的业务特征,合理的裁剪,找到合适落地方案。总结一句话,那就是:因需而变。虽然微服务的路径是不一样的,但方向是相同的。再次回顾微服务的架构演进历程,你会发现,从单体架构开始,进行拆分,形成微服务之后,又因为各种这样的原因,很多微服务架构又在进行合并,现在领域驱动设计来了,又开始重新拆分。真可谓:话说天下大势,分久必合,合久必分。

文章来源:松然聊技术,点击查看原文

DDD实战演练工作坊

DDD实战演练工作坊将于2020年10月17日在北京开课。DDD全过程工作坊将以事件风暴为纵贯线,以领域场景为横切面,驱动从战略设计到战术设计的全生命周期的完整开发过程。内容涵盖事件风暴、限界上下文、上下文映射、角色构造型、场景驱动设计和测试驱动开发。整个工作坊围绕一个全真案例进行演练,实践具有实操价值的领域驱动设计方法。点击下方图片或者阅读原文链接查看详情。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/108891529

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签