DDD - 微服务落地的技术实践

文章目录

  • Pre
  • 概述
  • 如何发挥微服务的优势
  • 怎样提供微服务接口
    • 原则
    • 微服务的拆分与防腐层的设计
  • 去中心化的数据管理
  • 数据关联查询的难题
    • Case 1
    • Case 2
    • Case 3
  • 总结

在这里插入图片描述


Pre

DDD - 软件退化原因及案例分析

DDD - 如何运用 DDD 进行软件设计

DDD - 如何运用 DDD 进行数据库设计

DDD - 服务、实体与值对象的两种设计思路:贫血模型与充血模型

DDD - 聚合、聚合根、仓库与工厂

DDD - 微服务设计与领域驱动设计实战(上)_统一建模语言及事件风暴会议

DDD - 微服务设计与领域驱动设计实战(中)_ 解决微服务拆分难题

DDD - 微服务设计与领域驱动设计实战(下)_落地微服务设计实现


概述

如今,做一个优秀的程序员越来越难。激烈的市场竞争、互联网快速的迭代、软件系统规模化发展,无疑都大大增加了软件设计的难度。因此,对于架构师的能力要求也越来越高 :

作为顶级架构师应当具备这样两个核心能力:

  • (1)能够将业务转换为技术;
  • (2)能合理利用技术支撑业务。

能够将业务转换为技术,意味着需要将更多的精力放到对业务的理解中。技术本身并不能产生价值,必须具备超强的业务落地能力,能够将用户的业务需求落地到技术方案,开发出用户乐于使用的产品和功能,用户才能为之买单,企业才能挣钱。具备这样的能力,才能够强力地帮助企业产生效益,才能体现价值。学习 DDD 就能让你掌握快速学习业务领域知识的能力。

能合理利用技术支撑业务,意味着必须具备广博的知识与开阔的视野,能将用户的业务痛点,快速落地形成合理的,甚至是最优的技术方案。做出用户需要的功能,让用户为之买单,从而为企业产生效益。然而,如今是一个技术快速更迭的时代,各种高新技术层出不穷。每次新产品的开发不是将原有的技术拿来炒冷饭,而是运用更多的新技术解决新问题,让产品更有竞争力与生命力。因此,必须有广博的技术知识与超强的技术落地能力。


DDD - 微服务设计与领域驱动设计实战(上)_统一建模语言及事件风暴会议

DDD - 微服务设计与领域驱动设计实战(中)_ 解决微服务拆分难题

DDD - 微服务设计与领域驱动设计实战(下)_落地微服务设计实现谈到 DDD 落地微服务的分析设计过程,然后将这些设计最终落实到每个微服务的设计开发中。微服务的落地其实并没有那么简单,需要解决诸多设计与实现的技术难题,我们就来探讨一下吧。


如何发挥微服务的优势

微服务也不是银弹,它有很多的“坑”。 当我们将一个庞大的业务系统拆分为一个个简单的微服务时,就是希望通过合理的微服务设计,尽量让每次的需求变更都交给某个小团队独立完成,让需求变更落到某个微服务上进行变更。唯有这样,每次变更只需独立地修改这个微服务,独立打包、独立升级,新需求就实现啦,才能发挥微服务的优势。

image.png

然而,过去很多系统都是这样设计的(如上图所示),多个模块都需要读取商品信息表,因此都通过 JDBC 直接读取。现在要转型微服务了,起初采用数据共享的微服务设计,就是数据库不变,然后简单粗暴地直接按照功能模块进行微服务拆分。这时,多个微服务都需要读取商品信息表,都通过 SQL 直接访问。这样的设计,一旦商品信息表发生变更,那么多个微服务都需要变更。这样的设计就使得微服务的变更与发布变得复杂,微服务的优势无法发挥


image (1).png

通过 DDD 的指导,是希望做“小而专”的微服务设计。按照这样的思路设计微服务,对商品信息表的读写只有“商品维护”微服务。当其他微服务需要读写商品信息时,就不能直接读取商品信息表,而是通过 API 接口去调用“商品维护”微服务。这样,日后因商品信息变更而修改的代码就只限于“商品维护”微服务。只要“商品维护”微服务对外的 API 接口不变,这个变更则与其他微服务无关。只有这样的设计,才能真正发挥微服务的优势。

为了规范“小而专”的微服务设计,在微服务转型之初,先按照 DDD 对数据库表按照用户权限进行划分。每个微服务只能通过自己的账号访问自己的表。当需要访问其他的表时,只能通过接口访问相应的微服务。这样的划分,就为日后真正的数据库拆分做好了准备,微服务转型将更加平稳


怎样提供微服务接口

因此,微服务的设计彼此之间不是孤立的,它们需要相互调用接口实现高内聚。然而,当一个微服务团队向另一个微服务团队提出接口调用需求时,另一个微服务团队该如何设计呢?

原则

首先第一个问题,当多个团队都在向你提出 API 接口时,怎么提供接口。如果每个团队给你提需求,就必须要做一个新接口,那么你的微服务将变得非常不稳定。因此,

  • 当多个团队向你提需求时,必须要对这些接口进行规划,通过复用用尽可能少的接口满足他们的需求
  • 当有新的接口提出时,要尽量通过现有接口解决问题。这样做,就能用更低的维护成本,更好地维护自己的微服务。

接着,当调用方需要接口变更时怎么办?

  • 变更现有接口应当尽可能向前兼容,即接口的名称与参数都不变,只是在内部增加新的功能。这样做是为了不影响其他微服务的调用。

  • 如果确实需要更改现有的接口怎么办?宁愿增加一个新的接口也最好不要去变更原有的接口

  • 调用双方传递的值对象需要完全一致吗?当然不用。当被调方因为某些变更对值对象增加了字段,而这些字段调用方不使用时,那么调用方不需要跟着变更值对象。因为微服务间的调用是采用RESTful 接口,以 JSON 的形成传递数据,是一种松耦合的调用。因此调用双方的值对象可以不一致,从而降低了需求变更的微服务更新范围

  • 最后,调用方 如何调用接口呢?这里分为 同步调用与异步调用

    “用户接单 Service”在完成下单以后,用消息队列通知“饭店接单 Service”,就是异步调用。

    “用户接单Service”常常要查找用户表信息,但前面说了,它没有查询用户表权限,因为用户表在“用户注册”微服务中。这时,“用户接单 Service”通过同步调用“用户注册 Service”的相关接口。

微服务的拆分与防腐层的设计

具体设计实现上,就是在“用户接单”微服务的本地,增加一个“用户注册 Service”的 feign 接口。这样,“用户接单 Service”就像本地调用一样调用“用户注册 Service”,再通过这个 feign 接口实现远程调用。这样的设计叫作“防腐层”的设计。如下图所示:

Drawing 2.png

微服务的拆分与防腐层的设计图

譬如,大家想象这样一个场景。过去,“用户注册 Service”是在“用户下单”微服务中的。后来,随着微服务设计的不断深入,需要将“用户注册 Service”拆分到另外一个微服务中。这时,“用户下单Service”与“取消订单 Service”,以及其他对“用户注册 Service”的调用都会报错,都需要修改,维护成本就很高。这时,在微服务的本地放一个“用户注册 Service”的 feign 接口,那么其他的 Service 都不需要修改了,维护成本将得以降低。这就是**“防腐层”的作用,即接口变更时降低维护成本**。


去中心化的数据管理

按照前面 DDD 的设计,已经将数据库按照微服务划分为用户库、下单库、接单库、派送库与饭店库。这时候,如何来落地这些数据库的设计呢?微服务系统最大的设计难题就是要面对互联网的高并发与大数据。因此,可以按照“去中心化数据管理”的思想,根据数据量与用户访问特点,选用不同的数据存储方案存储数据:

  • 微服务“用户注册”与“饭店管理”分别对应的用户库与饭店库,它们的共同特点是数据量小但频繁读取,可以选用小型的 MySQL 数据库并在前面架设 Redis 来提高查询性能;

  • 微服务“用户下单”“饭店接单”“骑士派送”分别对应的下单库、接单库、派送库,其特点是数据量大并且高并发写,选用一个数据库显然扛不住这样的压力,因此可以选用了 TiDB 这样的 NewSQL 数据库进行分布式存储,将数据压力分散到多个数据节点中,从而解决 I/O 瓶颈;

  • 微服务“经营分析”与“订单查询”这样的查询分析业务,则选用 NoSQL 数据库或大数据平台,通过读写分离将生产库上的数据同步过来进行分布式存储,然后经过一系列的预处理,就能应对海量历史数据的决策分析与秒级查询。

基于以上这些设计,就能完美地应对互联网应用的高并发与大数据,有效提高系统性能。设计如下图所示:

Drawing 3.png

在线订餐系统的去中心化数据管理图

数据关联查询的难题

Case 1

此外,各个微服务在业务进行过程需要进行的各种查询,由于数据库的拆分,就不能像以前那样进行 join 操作了,而是通过接口调用的方式进行数据补填。比如“用户下单”“饭店接单”“骑士派送”等微服务,由于数据库的拆分,它们已经没有访问用户表与饭店表的权限,就不能像以往那样进行 join 操作了。这时,需要重构查询的过程。

如下图所示:

image (2).png

查询的过程分为 2 个步骤。

  • 查询订单数据,但不执行 join 操作。这样的查询结果可能有 1 万条,但通过翻页,返回给微服务的只是那一页的 20 条数据。

  • 再通过调用“用户注册”与“饭店管理”微服务的相关接口,实现对用户与饭店数据的补填。

这种方式,既解决了跨库关联查询的问题,又提高了海量数据下的查询效率

注意,传统的数据库设计之所以在数据量越来越大时,查询速度越来越慢,就是因为存在 join 操作。因而,在面对海量数据的查询时,干掉 join 操作,改为分页后的数据补填,就能有效地提高查询性能。

Case 2

然而,在查询订单时,如果要通过用户姓名、联系电话进行过滤,然后再查询时,又该如何设计呢?这里千万不能先过滤用户数据,再去查询订单,这是一个非常糟糕的设计。我们过去的数据库设计采用的都是3NF(第 3 范式),它能够帮助我们减少数据冗余,然而却带来了频繁的 join 操作,降低了查询性能。因此,为了提升海量数据的查询性能,适当增加冗余,即在订单表中增加用户姓名、联系电话等字段。这样,在查询时直接过滤订单表就好了,查询性能就得到了提高


Case 3

最后,当系统要在某些查询模块进行订单查询时,可能对各个字段都需要进行过滤查询。这时就不再采用数据补填的方式,而是利用 NoSQL 的特性,采用“宽表”的设计。按照这种设计思路,当系统通过读写分离从生产库批量导入查询库时,提前进行 join 操作,然后将 join 以后的数据,直接写入查询库的一个表中。由于这个表比一般的表字段更多,因此被称为“宽表”。

由于 NoSQL 独有的特性,为空的字段是不占用空间的,因此字段再多都不影响查询性能。这样,在日后的查询时,就不再需要 join 操作,而是直接在这个单表中进行各种过滤、各种查询,从而在海量历史数据中实现秒级查询。因此,“订单查询”微服务在数据库设计时,就可以通过NoSQL 数据库建立宽表,从而实现高效的数据查询。


总结

基于 DDD 的微服务设计,既强调对业务的分析理解,又强调对业务的技术落地。 在这个过程中,微服务间要通过 feign 接口相互调用,数据要通过补填关联查询。此外,还有聚合的实现、仓库和工厂的设计。所有这些内容都需要在 DDD 设计思想的基础上,落地实现。

然而,如果每个模块都要反复地写代码去实现这些功能,DDD 的设计将显得异常烦琐,因此迫切需要有一个既支持 DDD,又支持微服务的技术中台,封装这些代码,简化微服务的设计。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/67918.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Leetcode 热题 100】763. 划分字母区间

问题背景 给你一个字符串 s s s。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。 注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s s s。 返回一个表示每个字符串片段的长度的…

ChatGPT是强人工智能吗?

ChatGPT是强人工智能吗? 本文从人工智能发展的三个阶段的角度,分析当前强大的AI大模型所处的阶段,并通过对比各阶段的定义,明确各阶段的特点和未来发展方向; Narrow AI(弱人工智能)、AGI(人工通用智能)和 ASI(人工超级…

通过视觉语言模型蒸馏进行 3D 形状零件分割

大家读完觉得有帮助记得关注和点赞!!!对应英文要求比较高,特此说明! Abstract This paper proposes a cross-modal distillation framework, PartDistill, which transfers 2D knowledge from vision-language models …

深入探索 Nginx 的高级用法:解锁 Web 服务器的强大潜能

在当下互联网技术飞速发展的浪潮中,Nginx 凭借其轻量级、高性能的特性,在 Web 服务器和反向代理服务器领域脱颖而出,成为众多开发者和运维工程师的得力工具。它不仅能高效处理静态资源,在负载均衡、反向代理等方面也表现出色。然而…

【大模型】ChatGPT 高效处理图片技巧使用详解

目录 一、前言 二、ChatGPT 4 图片处理介绍 2.1 ChatGPT 4 图片处理概述 2.1.1 图像识别与分类 2.1.2 图像搜索 2.1.3 图像生成 2.1.4 多模态理解 2.1.5 细粒度图像识别 2.1.6 生成式图像任务处理 2.1.7 图像与文本互动 2.2 ChatGPT 4 图片处理应用场景 三、文生图操…

从零到一:Spring Boot 与 RocketMQ 的完美集成指南

1.Rocket的概念与原理 RocketMQ 是一款由阿里巴巴开源的分布式消息中间件,最初用于支持阿里巴巴的海量业务。它基于发布-订阅模型,具备高吞吐、低延迟、高可用和强一致性的特点,适用于消息队列、大规模数据流处理等场景。以下是对 RocketMQ …

mysql数据库启动出现Plugin ‘FEEDBACK‘ is disabled.问题解决记录

本人出现该问题的环境是xampp,异常关机,再次在xampp控制面板启动mysql出现该问题。出现问题折腾数据库之前,先备份数据,将mysql目录下的data拷贝到其他地方,这很重要。 然后开始折腾。 查资料,会发现很多…

MySQL日期时间函数详解

简介 本文主要讲解MySQL中的日期时间函数,包括:NOW、CURRENT_TIMESTAMP、CURDATE、CURRENT_DATE、CURTIME、CURRENT_TIME、STR_TO_DATE、DATE_FORMAT、TIME_FORMAT、DATE、TIME、YEAR、MONTH、DAY、HOUR、MINUTE、SECOND、QUARTER、YEARWEEK、WEEKDAY、…

ChatGPT 写作系列

ChatGPT 辅助写作 | 专栏 1 写作核心​ 先讲一下 ChatGPT 写作的核心。核心就是需要有文章大纲,而且文章大纲要足够细致。​ 具体怎么做呢?​ 提前准备多级标题大纲,刚开始有两个级别的标题就行,等用熟练了再细化。分一级标题&…

(1)STM32 USB设备开发-基础知识

开篇感谢: 【经验分享】STM32 USB相关知识扫盲 - STM32团队 ST意法半导体中文论坛 单片机学习记录_桃成蹊2.0的博客-CSDN博客 USB_不吃鱼的猫丿的博客-CSDN博客 1、USB鼠标_哔哩哔哩_bilibili usb_冰糖葫的博客-CSDN博客 USB_lqonlylove的博客-CSDN博客 USB …

【Java】Java抛异常到用户界面公共封装

前言 在Java中处理代码运行异常是常见的技术点之一,我们大部分会使用封装的技巧将异常进行格式化输出,方便反馈给用户界面,也是为了代码复用 看看这行代码是怎么处理异常的 CommonExceptionType.SimpleException.throwEx("用户信息不…

mkv转码mp4(ffmpeg工具)

基于windows,Linux也可以用,都是命令行 下载路径(https://github.com/BtbN/FFmpeg-Builds/releases) 下载安装包:ffmpeg-n6.1-latest-win64-lgpl-6.1.zip,(根据自己的平台选择下载)并…

力扣-数组-414 第三大的数

解析 先利用set去重&#xff0c;然后用逆向遍历找到第三大的数 代码 class Solution { public:int thirdMax(vector<int>& nums) {set<int> numsToset;for(int i 0; i<nums.size(); i){numsToset.insert(nums[i]);}int index;if(numsToset.size() > …

没有公网IP实现seafile本地IP访问和虚拟局域网IP同时访问和上传文件

前言 Ubuntu 24.04 LTSDocker 安装 seafileOpenWrtTailscale Ubuntu 24.04 LTS 通过 docker desktop 安装 seafile 搭建个人网盘中&#xff0c;已经实现了本地局域网放问Ubuntu IP来访问Seafile&#xff0c;以及通过 Ubuntu 的 Tailscale IP 访问Seafile。但是&#xff0c;文…

私有IP、VLAN和VPC,分别适合哪些场景你知道吗?

当我们在云中构建应用程序&#xff0c;尤其是使用了第三方云服务商的服务并且我们无法完全掌控后端的每部分时&#xff0c;安全性可能是最需要关注的地方。但这是一项充满挑战的工作&#xff0c;因为保护应用程序的方法实在是太多了&#xff01;为了改善安全性&#xff0c;开发…

【Uniapp-Vue3】setTabBar设置TabBar和下拉刷新API

一、setTabBar设置 uni.setTabBarItem({ index:"需要修改第几个", text:"修改后的文字内容" }) 二、tabBar的隐藏和显式 // 隐藏tabBar uni.hideTabBar(); // 显示tabBar uni.showTabBar(); 三、为tabBar右上角添加文本 uni.setTabBarBadge({ index:"…

TCP全连接队列

1. 理解 int listen(int sockfd, int backlog) 第二个参数的作用 backlog&#xff1a;表示tcp全连接队列的连接个数1。 如果连接个数等于backlog1&#xff0c;后续连接就会失败&#xff0c;假设tcp连接个数为0&#xff0c;最大连接个数就为1&#xff0c;并且不accept获取连接…

Java 中的设计模式:经典与现代实践

Java 中的设计模式&#xff1a;经典与现代实践 1. 设计模式简介 设计模式是一种软件开发中的思想&#xff0c;它为我们提供了一些经过验证的、能够应对常见问题的解决方案。学习和掌握设计模式能够让开发者在面对复杂的需求时&#xff0c;能够设计出更加灵活、可维护的代码。…

华为OD机试真题---战场索敌

华为OD机试真题“战场索敌”是一道考察算法和数据结构应用能力的题目。以下是对该题目的详细解析&#xff1a; 一、题目描述 有一个大小是NM的战场地图&#xff0c;被墙壁’#‘分隔成大小不同的区域。上下左右四个方向相邻的空地’.‘属于同一个区域&#xff0c;只有空地上可…

windows下使用docker执行器并配置 hosts 解析

本篇目录 1. 问题背景2. 环境准备2.1 云上开通windows 2022 英文版机器2.1.1 安装 git2.1.2 安装 runner2.1.3 装docker2.1.4 注册runner并使用docker执行器 3. 项目信息3.1 编写window bat脚本3.2 项目.gitlab-ci.yml文件 4. 测试结论4.1 运行流水线 5. troubleshooting问题1&…