微服务和领域驱动
一、微服务
1.1 什么是微服务
微服务就是一些协同工作的小而自治的服务。
关键词: 小而自治
-- 小
“小”这个概念,一方面体现在微服务的内聚性上。
- 内聚性也可以称之为单一职责原则:“把因相同原因而变化的东西聚合到一起,而把因不同原因而变化的东西分离开来。”
- 也就是说,微服务应该专注于做好一件事情。
- 由业务边界来确定服务的边界
-- 自治
“自治”这个概念,强调的是,一个微服务就是一个独立的实体。体现在服务之间的松耦合上。黄金法则:你是否能够修改一个服务并对其进行部署,而不影响其他任何服务?
1.2 微服务的好处
- 技术异构性
- 不同服务根据业务场景、性能要求、功能需求采用不同的技术架构
- 新技术的快速实践,技术团队的快速成长
- 弹性/反脆弱性(anti-fragility)
- 服务降级
- 服务容灾、服务熔断
- 扩展
- 传统单体系统,无法做到对局部功能进行扩展
- 根据具体的业务需求,对特定的微服务进行扩展
- 通过架构的手段,节省成本
- 简化部署
- 传统单体应用,即使是一行代码修改,也需要整体重新部署。风险太大。
- 微服务架构,各个服务部署相互独立
- 灵活的发版方式
- 快速回滚
- 风险小
- 架构与组织结构相匹配
- 关联知识点:康威定律
- 服务的可重用、可组合
- 服务的可替代性,快速重写
1. 3微服务的弊端
对运维能力要求高;运行效率会降低;技术要求高,需要处理事务最终一致性等问题。微服务不该是这样的:
二、好服务的特征
2.1松耦合
松耦合指的是,修改一个服务,而另一个相关的服务,不需要修改。微服务的重要特点就是:能够独立修改和部署单个服务,而不会影响、甚至修改系统中的其它服务。
一个服务应该尽可能少地了解与之协作的服务信息。因为过度了解,会导致紧耦合。
2.2高内聚
高内聚指的是,把相关的行为聚集在一起。这样,需要改变行为时,只需要在一处修改,然后独立发布。
我们需要做的是,找出业务领域的边界,然后实现高内聚
三、微服务拆分原则
还是要重申两个重要概念,高内聚和松耦合,对应前面的关键词:小而自治。
3.1限界上下文
微服务一定要有清晰的功能边界。一个微服务对应了一个功能集合,这些功能一定是有一些共性的。比如,订单服务,那么创建订单、修改订单、查询订单列表,一般是订单服务的功能集合。
3.2逐步划分
一开始,我们会首先识别出一个粒度比较粗的服务模型。领域拆分并不是一步到位的,应当根据实际情况逐步展开。从单体应用到微服务体系的拆分过程能很好的说明这个问题。所以如果一开始不知道应该划分多细,完全可以先粗粒度划分,然后随着需要,初步拆分。比如一个电商一开始索性可以拆分为商品服务和交易服务,一个负责展示商品,一个负责购买支付。随后随着交易服务越来越复杂,就可以逐步的拆分成订单服务和支付服务。
四、DDD领域驱动设计
DDD 是一种架构设计方法,微服务是一种架构风格,DDD可以看作是微服务的方法论。两者从本质上都是为了追求高响应力,而从业务视角去分离应用系统建设复杂度的手段。两者都强调从业务出发,其核心要义是强调根据业务发展,合理划分领域边界,持续调整现有架构,优化现有代码,以保持架构和代码的生命力,也就是我们常说的演进式架构。
- DDD是一个很好的应用于微服务架构的方法论;
- 在项目的全生命周期内,所有岗位的人员都基于对业务的相同的理解来开展工作。所有人员站在用户的角度、业务的角度去思考问题,而不是站在技术的角度去思考问题;
- 诞生于2004年,兴起于2014年(微服务元年);
- DDD晦涩难懂,难以落地。因为DDD是方法论,不是行动指南
4.1 领域和子域
领域可以是多个子领域的一个虚拟集合,换句话说多个微服务也可以形成一个大域,不必纠结于领域和微服务之间的数量对应关系。例如在做架构设计的时候可能就把订单域作为一个领域,代表了这个域就是关于订单的,具体该有几个微服务,这需要更细的详细设计来提供。子域可以根据自身重要性和功能属性划分为三类子域,它们分别是:核心域、通用域和支撑域
4.2 界限上下文
任何领域模型都必须是在其特定的上下文环境中,如果DDD超出了其界定的上下文,则会产生歧义或者错误。例如社交媒体中的连接和网络应用中的连接的含义是完全不同的。对于任何上下文,我们都必须要能够建立明确的上下文的关联关系和边界。模型中的角色和边界的定义,在项目中非常重要。
4.3 库
库(Repositories)库指的是所有拥有共同实体和值接口的服务,且这些实体和值都在同一个聚合组中。库通常应该有增加,删除,修改和查找组中对象的方法。可以直接通过应用业务逻辑查询的引用来进行简洁的查询。
4.4 通用语言
通用语言就是能够简单、清晰、准确描述业务涵义和规则的语言。通用语言是团队统一的语言,不管你在团队中承担什么角色,在同一个领域的软件生命周期里都使用统一的语言进行交流。那么,通用语言的价值也就很明了,它可以解决交流障碍这个问题
4.5 聚合和聚合根
聚合(Aggregate):用来定义领域对象所有权和边界的领域模式,是用来帮助简化模型对象间的关系。通过定义对象之间清晰的所属关系和边界来实现领域模型的内聚,并避免了错综复杂的难以维护的对象关系网的形成。
聚合根(Aggregate Root):每个聚合都有一个根对象(聚合根实体),从外部访问只能通过这个对象。根实体对象有组成聚合所有对象的引用,但是外部对象只能引用根对象实体。只有聚合根才能使用仓储库直接查询,如果根实体被删除,聚合内部的其它对象也将被删除。
4.6 实体和值对象
实体(Entity):一个由它的标识定义的对象叫做实体。通常实体具备唯一ID,能够被持久化,具有业务逻辑,对应现实世界业务对象。
值对象(Value Object):一个没有概念上标识符描述一个领域方面的对象,这些对象是用来表示临时的事物,或者可以认为值对象是实体的属性,这些属性没有特性标识但同时表达了领域中某类含义的概念。通常值对象不具有唯一ID,由对象的属性描述,可以用来传递参数或对实体进行补充描述。
4.7 领域事件
领域事件是对领域内发生的活动进行的建模。一个消息监听可以当成一个领域事件,表示发生了什么事情,然后需要做什么。领域事件对象用于记录模型产生的离散事件,我们必须谨慎选择和记录领域事件,仅仅对于那些有意义的事件进行记录。
4.8 领域和数据库
一般按垂直业务拆分,一个服务对应独立的库(也可能出现多个服务公用一个库,从设计上通常没有公用表),绝大多数情况下,一个服务和一个数据库搭配,对外提供接口。数据库应该被视为每个领域服务层微服务的私有数据库。
4.9 领域内拆分
领域拆分并不是一成不变的,应当具体情况具体分析。比如大众点评,其订单服务就拆分为了order-service和order-query-service,一来为了读写分离,二来order-query-service作为单独应用可以按需水平扩容。
4.10 核心子域、支撑子域、通用子域
-- 核心子域:
决定业务成功和公司核心竞争力的子域,整个系统最重要部分。 Eric Evans 曾提出如下问题助识别核心域:
- 为何这系统值得写?
- 为何不直接买个?
- 为何不让外包写?
若你对这几个问题的回答能帮你找到这个系统非写不可的理由,则它就是核心域。如电商系统的订单、商品服务。
-- 支撑子域(Supporting Subdomain)
不是你的核心竞争力,但又得做,市场无现成方案的子域。既不包含决定产品和公司核心竞争力的功能,也不包含通用功能的子域,但又必需。
具有企业特性,但不具通用性,如:
- 数据代码类的数据字典等系统
- 排行榜,可能根据各种信息排名,这种东西没人会按你需要做个,但对你自己,又是扩展自己系统的重要举措
- 调用银联、支付宝等第三方支付,即下游
- 报表系统
- 监控系统
-- 通用域(Generic Subdomain)
无太多个性化需求,同时会被多个子域使用的通用功能子域。如认证、权限等,无企业特点限制,无需太多定制化。行业里都这么做,即便不自己做,也不影响业务运行。
如很多 App 要给用户发通知,这种功能完全可买个服务,丝毫不影响业务运行。
五、DDD领域驱动经典四层设计
脚本式编程(dao+service)与DDD领域驱动模式区别如下:
5.1展现(表现层/用户接口层)(Presentation Layer):
负责以Restful的格式接受Web请求,然后将请求路由给Application层执行,并返回视图模型(View Model),其载体通常是DTO(Data Transfer Object);
5.2应用层(Application Layer):
主要负责获取输入,组装上下文,做输入校验,调用领域层做业务处理,如果需要的话,发送消息通知。当然,层次是开放的,若有需要,应用层也可以直接访问基础实施层;应用层连接用户接口层和领域层,不应该实现领域模型的核心领域逻辑。主要职能:协调领域层多个聚合完成服务的组合和编排。应用服务主要负责服务组合、编排和转发,处理业务用例的执行顺序以及结果的拼装。在应用服务中还可以进行安全认证、权限校验、事务控制、领域事件发布或订阅等。
5.3领域层(Domain Layer):
领域层是领域模型的核心,主要实现领域模型的核心业务逻辑。领域模型的业务逻辑主要由实体和领域服务来实现。其中实体会采用充血模型来实现业务功能,如单一实体(或值对象)不能实现时,就交由领域服务进行组合和协调聚合内多个实体(或值对象),实现复杂的业务逻辑。
主要是封装了核心业务逻辑,并通过领域服务(Domain Service)和领域对象(Entities)的函数对外部提供业务逻辑的计算和处理;
5.4基础实施层(Infrastructure Layer):
主要包含Tunnel(数据通道)、防腐层,Config和Common。这里我们使用Tunnel这个概念来对所有的数据来源进行抽象,这些数据来源可以是数据库(MySQL,NoSql)、搜索引擎、文件系统、也可以是SOA服务等;Config负责应用的配置;Common是通用的工具类。
基础层贯穿DDD所有层。其职能:提供通用的技术和基础服务,包括第三方工具、驱动、消息中间件、网关、文件、缓存以及数据库等。
六、如何进行DDD领域驱动设计
DDD 包括战略设计和战术设计两部分,它们分别从不同的视角出发,完成领域建模和微服务的拆分和设计。事件风暴(Event Storming)是落实领域驱动的一种常用方法,使用事件风暴能够通过领域事件来识别出聚合根,组合的聚合根则又组成限界上下文,限界上下文则正是我们寻找的“微服务”的概念。
6.1战略设计
是从业务视角出发,划分业务的领域边界,建立基于通用语言和业务上下文语义边界的限界上下文,构建领域模型。而限界上下文就可以作为微服务拆分和设计的边界。以一种领域专家、设计人员、开发人员都能理解的“通用语言”作为相互交流的工具,在不断交流的过程中发现和挖出一些主要的领域概念,然后将这些概念设计成一个领域模型;
6.2战术设计
则是从技术视角出发,侧重于对领域模型的技术实现,按照领域模型完成微服务的开发和落地。在战术设计中会有聚合、聚合根、实体、值对象、领域服务、领域事件、应用服务和仓储等领域对象,这些领域对象会以代码的形式映射到微服务中完成设计和系统落地。 由领域模型驱动软件设计,用代码来表现该领域模型。领域需求的最初细节,在功能层面通过领域专家的讨论得出。
七、领域模型建模
UML建模示例:
@startumlhide circlenote "知识库领域建模" as knowledge_uml #yellowentity 知识库 {kie_knowledge==知识来源:工单、设备类型: 知识、案例知识状态: 待提交、已发布、已撤销查看次数:调用详情次数
}entity 知识操作日志 {kie_knowledge_operation_log==操作名称知识ID操作人ID操作人名字是否成功(success)操作类型: 存入草稿,撤销,发布
}entity 知识关联对象 {kie_knowledge_linked_object==知识ID对象上下文快照: jsonb
}entity 知识点赞记录 {kie_knowledge_like_record==用户ID知识ID点赞标识:bool
}知识库 ||--|{ 知识操作日志
知识库 ||--o{ 知识关联对象
知识库 ||--o{ 知识点赞记录@enduml
相关文章:

微服务和领域驱动
一、微服务 1.1 什么是微服务 微服务就是一些协同工作的小而自治的服务。 关键词: 小而自治 -- 小 “小”这个概念,一方面体现在微服务的内聚性上。 内聚性也可以称之为单一职责原则:“把因相同原因而变化的东西聚合到一起,…...

Redis如何做到内存高效利用?过期key删除术解析!
大家好,我是小米,一个热衷于分享技术的小伙伴。今天我要和大家探讨一个关于 Redis 的话题:删除过期key。在使用 Redis 进行数据存储和缓存时,我们经常会遇到过期数据的处理问题。接下来,我将为大家介绍为什么要删除过期…...

EFDC模型教程
详情点击链接:EFDC建模方法及在地表水环境评价、水源地划分、排污口论证 一,软件安装 1.1 EFDC安装 1.2 EFDC-Explorer安装 1.3 Delft3D安装 1.4 Google Earth安装二,EFDC模型 2.1 EFDC模型 2.2 EFDC-DSI模型 2.3 EFDC的…...

URLConnection(三)
文章目录 1. 配置连接2. protected URL url3. protected boolean connected4. protected boolean allowUserInteraction5. protected boolean doInput5. protected boolean doOutput6. protected boolean isModifiedSince7. protected boolean useCaches8. 超时 1. 配置连接 U…...

针对KF状态估计的电力系统虚假数据注入攻击研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

2023-05-25 LeetCode每日一题(差值数组不同的字符串)
2023-05-25每日一题 一、题目编号 差值数组不同的字符串 二、题目链接 点击跳转到题目位置 三、题目描述 给你一个字符串数组 words ,每一个字符串长度都相同,令所有字符串的长度都为 n 。 每个字符串 words[i] 可以被转化为一个长度为 n - 1 的 …...

MI小米验厂知识点
【MI小米验厂知识点】 小米科技有限责任公司成立于2010年3月3日,是专注于智能硬件和电子产品研发、智能手机、智能电动汽车、互联网电视及智能家居生态链建设的全球化移动互联网企业、创新型科技企业。小米公司创造了用互联网模式开发手机操作系统、发烧友参与开发改…...
损失函数——交叉熵损失(Cross-entropy loss)
交叉熵损失(Cross-entropy loss)是深度学习中常用的一种损失函数,通常用于分类问题。它衡量了模型预测结果与实际结果之间的差距,是优化模型参数的关键指标之一。以下是交叉熵损失的详细介绍。 假设我们有一个分类问题࿰…...

电商ERP接口erp进销存接口
电商API详情接口在ERP中的重要性 电商行业的发展已经改变了人们的消费方式。作为一种连续不断涌现并不断发展的新型销售方式,电商具有开创新市场、大众化消费、商业模式的多样化、效率的提高等优势,对传统零售业产生了极大的冲击。而ERP作为企业资源规划…...

leetcode 922. 按奇偶排序数组 II
题目描述解题思路执行结果 leetcode 922. 按奇偶排序数组 II. 题目描述 按奇偶排序数组 II 给定一个非负整数数组 nums, nums 中一半整数是 奇数 ,一半整数是 偶数 。 对数组进行排序,以便当 nums[i] 为奇数时,i 也是 奇数 &#…...

Unity四叉树地图
当使用Unity构建大规模的游戏地图或场景时,使用四叉树数据结构可以提高性能和效率。四叉树是一种基于分割的数据结构,将空间划分为四个相等的子区域,并以递归方式构建树结构。在游戏开发中,四叉树常用于空间分区、碰撞检测和可视化…...

【unity插件】OpenFracture插件实现物体破裂和切割
插件地址 https://github.com/Mustenaka/OpenFracture 使用注意事项 1.如果要导入自定义网格,则必须在导入设置中将“启用读/写”设置为 true。否则,您将收到错误。 2.网格必须是非相交和封闭的。否则,重新三角测量将失败。 上面描绘的是凳子的线框模型。注意横杆如何与…...

Spring Security实现登录
前言 Spring Security是Spring框架下的一个用于身份验证和授权的框架,它可以帮忙管理web应用中的用户认证、授权以及安全性问题。本文将介绍如何使用Spring Security实现用户登录功能,本文主要包括以下内容: 环境准备Spring Security核心概…...

小狐狸ChatGPT付费创作系统1.9.7独立版 + H5端 + 小程序前端增加AI绘画+GPT4接口
小狐狸ChatGPT 1.9.7独立版经播播资源测试了版本比较,本版核心增加了GPT4.0接口功能,小程序端内置了AI绘画功能。体验下来问答速度感觉体验更好。小程序端有更新请对应开发工具更新上传,本版无开源端。播播资源提供的安装教程详见下方&#x…...

双目测距联合YOLOv8 项目总结
代码贴:双目测距--5 双目相机 联合 YOLOv8_爱钓鱼的歪猴的博客-CSDN博客 0、图片筛选 可以用matlab,对双目图像做个一个筛选,也就是做双目标定。 熟悉matlab的小伙伴完全可以用matlab做双目标定,我是没咋接触过不知道怎么导出标定结果&#…...

Windows提权:利用MSSQL数据库,Oracle数据库
目录 MSSQL提权:使用xp_cmdshell进行提权 MSSQL:使用sp_OACreate进行提权 MSSQL:使用沙盒提权 Oracle提权:工具一把梭哈 总结 MSSQL在Windows server类的操作系统上,默认具有system权限。 MSSQL提权:使…...

linux常见的二十多个指令
目录 一、指令的概念 二、28个常见的指令 ⭐2.1 ls指令 ⭐2.2 pwd指令 ⭐2.3 cd指令 ⭐2.4tree指令 ⭐2.5 mkdir指令 ⭐2.6 touch指令 ⭐2.7 rmdir指令 ⭐2.8 rm指令 ⭐2.9 clear指令 ⭐2.10 man指令 ⭐2.11 cp指令 ⭐2.12 mv指令 ⭐2.13 cat指令(适…...

内蒙古自治区住房和城乡建设分析及解决方案
安科瑞 徐浩竣 江苏安科瑞电器制造有限公司 zx acrelxhj 摘 要:为深入贯彻落实《国务院办公厅关于印发新能源汽车产业发展规划(2021—2035年)的通知》(国办发 ﹝2020﹞39号)、《国家发展改革委等部门关于进一步提升…...

JavaEE进阶5/25(属性注入)
目录 1.更简单的存取Spring对象 2.获取Bean对象(对象装配)DI 3. Resource注入 4.Resource注入和Autowired注入的区别 1.更简单的存取Spring对象 2.获取Bean对象(对象装配)DI 对象装配(对象注入)有三种方…...

【Java学习记录-4】相关名词和概念记录(持续更新)
目录 1 注解2 包3 权限修饰符4 状态修饰符1. final2. static 5. 多态6.抽象类7.接口 1 注解 Override是一个注解,可以帮助我们检查重写方法的方法声明的正确性 注意: 私有方法不能被重写(父类私有成员子类是不能继承的)子类方法…...

《程序员面试金典(第6版)》面试题 16.25. LRU 缓存(自定义双向链表,list库函数,哈希映射)
题目描述 设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。 题目传送门:…...

kong网关启用jwt认证插件
认证流程: 1、创建一个用户 2、生成jwt的所需要的key和密钥 3、在https://jwt.io/的生成jwt token 4、启用jwt插件 5、发送请求的时候携带jwt的token信息 官方指导:https://docs.konghq.com/hub/kong-inc/jwt/configuration/examples/ 一、创建一个新的…...

day12 - 图像修复
在图像处理的过程中,经常会遇到图像存在多余的线条或者噪声的情况,对于这种情况我们会先对图像进行预处理,去除掉对图形内容有影响的噪声,在进行后续的处理。 本节实验我们介绍使用图像膨胀来处理图形的多余线条,进行…...

1720_Linux学习中的问题处理
全部学习汇总:GreyZhang/little_bits_of_linux: My notes on the trip of learning linux. (github.com) 这个有点学习的方法论的意思,画个滋味导图顺便整理一下。 遇到问题的时候,解决的方法大致有3中,而针对学习的建议有一部分是…...

七人拼团系统开发模式详解
七人拼团是最近兴起的一个模式,它通过更人性化的奖励机制,将产品利润最大化让利给参与拼团的用户,达到促进用户主动积极裂变和团队平台引流提升销量的效果,下面就来详细说一下这个模式。 七人拼团最大的特点,就是结合了…...

CPU性能优化:分支预测
条件跳转引起的控制冒险虽然也可以通过在流水线中插入空泡来避免,但是当流水线很深时,需要插入更多的空泡。一个20级的流水线为例,如果一条指令需要上一条指令的执行结束才能执行,则需要在这两条指令之间插入19个空泡,…...

过滤器Filter,拦截器Interceptor
过滤器Filter 快速入门 详情 登录校验-Filter package com.itheima.filter;import com.alibaba.fastjson.JSONObject; import com.itheima.pojo.Result; import com.itheima.utils.JwtUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils…...

kafka整理
kafka整理 一、kafka概述 kafka是apache旗下一款开源的顶级的消息队列的系统, 最早是来源于领英, 后期将其贡献给apache, 采用语言是scala.基于zookeeper, 启动kafka集群需要先启动zookeeper集群, 同时在zookeeper记录kafka相关的元数据 kafka本质上就是消息队列的中间件产品…...

为什么有些情况下需要重写equals()和hashCode()方法?
目录 方法作用实战案例 方法作用 equals():判断对象是否相等,比如判断是否能放入Set集合中 情况1:没有重写equals()方法:由于所有类的默认基类都是Object类,所以默认使用Object类的equals()方法,那就是对象…...

14-Vue技术栈之Vue3快速上手
目录 1.Vue3简介2. Vue3带来了什么2.1 性能的提升2.2 源码的升级2.3 拥抱TypeScript2.4 新的特性 1、海贼王,我当定了!——路飞 2、人,最重要的是“心”啊!——山治 3、如果放弃,我将终身遗憾。——路飞 4、人的梦想是…...