来源:淘系技术

系统设计与架构理论这个问题,回答起来非常宽泛,基本所有的技术理论都可以涵盖。作为一个撸代码快 10 年的后端技术人员,简单发表一下我的看法。

系统设计与架构,与系统的业务类型关联还是很大的,比如传统的业务系统主要关注的是领域建模设计,高并发、高可用、数据一致性等系统,在设计的时候会与业务系统有较大的差别,所以这里针对不同类型的系统,来简单介绍一下设计的时候面临的一些难点与解决方案。

背景常规业务系统设计关键——领域模型

业务系统设计的关键是在于如何定义系统的模型以及模型之间的关系,其中主要是领域模型的定义,当我们在模型确定之后,模型之间的关系也会随之明确。

模型设计可以参考领域模型的经典书籍《Domain-Driven Design》一书,通过这个基本可以对领域定义、防腐层、贫血模型等概念有一个较为清晰的认识了。

单个应用内的领域模型系统也需要注意领域分层,作为开发大家是不是见过、重构过很多Controller-Service-DAO 样式的代码分层设计?往往在在做重构的时候会令人吐血。

设计较好的领域设计这里给一个分层建议:

  接口层 Interface

主要负责与外部系统进行交互&通信,比如一些 dubbo服务、Restful API、RMI等,这一层主要包括 Facade、DTO还有一些Assembler。

  应用层 Application

这一层包含的主要组件就是 Service 服务,但是要特别注意,这一层的Service不是简单的DAO层的包装,在领域驱动设计的架构里面,Service层只是一层很“薄”的一层,它内部并不实现任何逻辑,只是负责协调和转发、委派业务动作给更下层的领域层。

  领域层 Domain

Domain 层是领域模型系统的核心,负责维护面向对象的领域模型,几乎全部的业务逻辑都会在这一层实现。内部主要包含Entity(实体)、ValueObject(值对象)、Domain Event(领域事件)和 Repository(仓储)等多种重要的领域组件。

  基础设施层 Infrastructure

它主要为 Interfaces、Application 和 Domain 三层提供支撑。所有与具体平台、框架相关的实现会在 Infrastructure 中提供,避免三层特别是 Domain 层掺杂进这些实现,从而“污染”领域模型。Infrastructure 中最常见的一类设施是对象持久化的具体实现。

高并发系统设计

在面试中是不是经常被问到一个问题:如果你系统的流量增加 N 倍你要怎么重新设计你的系统?这个高并发的问题可以从各个层面去解,比如

  代码层面

  • 锁优化(采用无锁数据结构),主要是 concurrent 包下面的关于 AQS 锁的一些内容

  • 数据库缓存设计(降低数据库并发争抢压力),这里又会有缓存、DB 数据不一致的问题,在实际使用中,高并发系统和数据一致性系统采用的策略会截然相反。

  • 数据更新时采用合并更新,可以在应用层去做更新合并,同一个 Container 在同一时间只会有一个 DB 更新请求。

  • 其他的比如基于 BloomFilter 的空间换时间、通过异步化降低处理时间、通过多线程并发执行等等。

  数据库层面

  • 根据不同的存储诉求来进行不同的存储选型,从早期的 RDBMS,再到 NoSql(KV存储、文档数据库、全文索引引擎等等),再到最新的NewSql(TiDB、Google spanner/F1 DB)等等。

  • 表数据结构的设计,字段类型选择与区别。

  • 索引设计,需要关注聚簇索引原理与覆盖索引消除排序等,至于最左匹配原则都是烂大街的常识了,高级一点索引消除排序的一些机制等等,B+树与B树的区别。

  • 最后的常规手段:分库分表、读写分离、数据分片、热点数据拆分等等,高并发往往会做数据分桶,这里面往深了去说又有很多,比如分桶如何初始化、路由规则、最后阶段怎么把数据合并等等,比较经典的方式就是把桶分成一个主桶+N个分桶。

  架构设计层面

  • 分布式系统为服务化

  • 无状态化支持水平弹性扩缩容

  • 业务逻辑层面 failfast 快速失败

  • 调用链路热点数据前置

  • 多级缓存设计

  • 提前容量规划等等

高可用系统设计

对于可用性要求非常高的系统,一般我们都说几个9的可用率,比如 99.999% 等。

面对高可用系统设计也可以从各个方面来进行分析

代码层面:需要关注分布式事务问题,CAP理论是面试的常规套路

软件层面:应用支持无状态化,部署的多个模块完全对等,请求在任意模块处理结果完全一致 => 模块不存储上下文信息,只根据请求携带的参数进行处理。目的是为了快速伸缩,服务冗余。常见的比如session问题等。

  负载均衡问题

软件部署多份之后,如何保证系统负载?如何选择调用机器?也就是负载均衡问题

  • 狭义上的负载均衡按照类型可以分为这几种:

  1. 硬件负载:比如F5等

  2. 软件负载:比如 LVS、Ngnix、HaProxy、DNS等。

  3. 当然,还有代码算法上的负载均衡,比如Random、RoundRobin、ConsistentHash、加权轮训等等算法

广义上的负载均衡可以理解为负载均衡的能力,比如一个负载均衡系统需要如下4个能力:

  1. 故障机器自动发现

  2. 故障服务自动摘除(服务熔断)

  3. 请求自动重试

  4. 服务恢复自动发现

  幂等设计问题

上面提负载均衡的时候,广义负载均衡需要完成自动重试机制,那么在业务上,我们就必须保证幂等设计。

这里可以从2个层面来进行考虑:

  • 请求层面

    由于请求会重试所以必须做幂等,需要保证请求重复执行和执行一次的结果完全相同。请求层面的幂等设计需要在数据修改的层做幂等,也就是数据访问层读请求天然幂等,写请求需要做幂等。读请求一般是天然幂等的,无论查询多少次返回的结果都是一致。这其中的本质实际上是分布式事务问题,这里下面再详细介绍。

  • 业务层面

    不幂等会造成诸如奖励多发、重复下单等非常严重的问题。业务层面的幂等本质上是分布式锁的问题,后面会介绍。如何保证不重复下单?这里比如token机制等等。如何保证商品不超卖?比如乐观锁等。MQ消费方如何保证幂等等都是面试的常见题。

  分布缩式

业务层面的幂等设计本质上是分布式锁问题,什么是分布式锁?分布式环境下锁的全局唯一资源,使请求串行化,实际表现互斥锁,解决业务层幂等问题。

常见的解决方式是基于 Redis 缓存的 setnx 方法,但作为技术人员应该清楚这其中还存在单点问题、基于超时时间无法续租问题、异步主从同步问题等等,更深一点,CAP理论,一个AP系统本质上无法实现一个AP需求,即使是 RedLock 也不行。

那我们如何去设计一个分布式锁呢?强一致性、服务本身要高可用是最基本的需求,其他的比如支持自动续期,自动释放机制,高度抽象接入简单,可视化、可管理等。

基于存储层的可靠的解决方案比如:

  • zookeeper

    CP/ZAB/N+1可用:基于临时节点实现和Watch机制。

  • ETCD

    CP or AP/Raft/N+1可用:基于 restful API;KV存储,强一致性,高可用,数据可靠:持久化;Client TTL 模式,需要心跳CAS 唯一凭证 uuid。

  服务的熔断

微服务化之后,系统分布式部署,系统之间通过 RPC 通讯,整个系统发生故障的概率随着系统规模的增长而增长,一个小的故障经过链路传导放大,有可能造成更大的故障。希望在调用服务的时,在一些非关键路径服务发生服务质量下降的情况下,选择尽可能地屏蔽所造成的影响。

大部分熔断返回默认值 null,也可以定制,RPCClient 原生支持最好,业务方少改代码(熔断放的地方),进入熔断时,打印熔断日志,同时返回 Exception(业务方定制熔断方法),需要有服务治理平台,可以看到服务的状态、是否降级、是否熔断、可以实时下发阀值配置等。

  服务降级

服务整体负载超出预设的上限,或者即将到来的流量预计将会超过阀值,为了保证重要或者基本的服务能够正常运行,拒绝部分请求或者将一些不重要的不紧急的服务或任务进行服务的延迟使用或暂停使用。

主要的手段如下:

  • 服务层降级,主要手段

  1. 拒绝部分请求(限流),比如缓存请求队列,拒绝部分等待时间长的请求;根据Head,来拒绝非核心请求;还有其他通用算法上的限流比如令牌桶、漏桶算法等等。

  2. 关闭部分服务:比如双11大促0点会关闭逆向退款服务等等。

  3. 分级降级:比如自治式服务降级,从网关到业务到DB根据拦截、业务规则逐渐降低下游请求量,体现上是从上到下的处理能力逐渐下降。

数据层降级

比如流量大的时候,更新请求只缓存到MQ,读请求读缓存,等流量小的时候,进行补齐操作(一般数据访问层如果做了降级,就没必要在数据层再做了)

  • 柔性可用策略

比如一些指定最大流量的限流工具,又或是根据CPU负载的限流工具等,需要保证自动打开,不依赖于人工。

  发布方式引发的可用性问题

发布方式也是影响高可用的一个点,哈哈,以前还经历过一些线上直接停机发布的案例(银行内部系统),不过作为高大上的互联网,主要会采用这几种发布方式:灰度发布、蓝绿发布、金丝雀发布等等。

数据一致性系统设计

一般一些金融、账务系统对这一块要求会非常严格,下面主要介绍下这里面涉及到的事务一致性、一致性算法等内容。

  事务一致性问题

在 DB 层面,一般通过 刚性事务 来实现数据一致性,主要通过 预写日志(WAL) 的方式来实现,WAL(write ahead logging)预写日志的方式。就是所有对数据文件的修改,必须要先写日志,这样,即使在写数据的时候崩溃了,也能通过日志文件恢复,传统的数据库事务就是基于这一个机制(REDO 已提交事务的数据也求改 UNDO 未提交事务的回滚)。

除了这个方式之外,还有一个就是通过 影子数据块 来进行数据备份,提前记录被修改的数据块的修改前的状态,备份起来,如果需要回滚,直接用这个备份的数据块进行覆盖就好了。

其他的就是基于二阶段提交的 XA模型 了。

但是目前互联网系统,已经广泛采用分布式部署模式了,传统的刚性事务无法实现,所以 柔性事务成了目前主流的分布式事务解决防范,主要的模式有下面几种:

  • TCC 模式/或者叫2阶段模式

    在 try 阶段预扣除资源(但是不锁定资源,提升可用性),在Confirm 或者 Cancel 阶段进行数据提交或者回滚。一般需要引入协调者,或者叫事务管理器。

  • SAGA模式

    业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,支持向前或者向后补偿。

  • MQ的事务消息

    就是先发 halfMsg,在处理完之后,再发送 commit 或者 rollback Msg,然后 MQ 会定期询问 producer ,halfMsg  能不能 commit 或者 rollback,最终实现事务的最终一致性。实际上是把补偿的动作委托给了 RocketMQ。

  • 分段事物(异步确保)

    基于可靠消息+本地事务消息表 + 消息队列重试机制。目前这也是一些大厂的主流方案,内部一般称为分段事物。

柔性事务基本都是基于最终一致性去实现,所以肯定会有 补偿 动作在里面,在达到最终一致性之前,对用户一般展示 软状态。

需要注意的一点是,并不是所有的系统都适合引入数据一致性框架,比如用户可以随时修改自己发起的请求的情况,例如,商家设置后台系统,商户会随时修改数据,这里如果涉及到一致性的话,引入一致性框架会导致补偿动作达到最终一致性之前,资源锁会阻塞用户后续的请求。导致体验较差。这种情况下就需要通过其他手段来保障数据一致性了,比如数据对账等操作。

  一致性算法

从早期的 Paxos 算法,再到后面衍生的 zab 协议(参考:A simple totally ordered broadcast protocol),提供了当下可靠的分布式锁的解决方案。再到后来的 Raft 算法(In Search of an Understandable Consensus Algorithm),也都是分布式系统设计里面需要了解到的一些知识要点。

最后

这里简单介绍了不同系统设计的时候会面临的一些难点,基本里面每一个点,都是前人在解决各种疑难问题的道路上不断探索,最终才得出的这些业界解决方案,呈现在大家眼前,作为一个技术人员,学会这些技术点只是时间问题,但这种发现问题、直面问题、再到解决问题的能力和精神才是我们最值得学习的地方,也是做为一个系统设计人员或者说是架构师的必要能力。


“技术领导力”视频号开通了,K哥每周安排一场直播,之前聊的主题有:如何应对职场中年危机、如何副业搞钱、技术管理实践......赶快关注,不会错过K哥的每次直播。

作者简介Mr.K,“技术领导力”公众号 作者,从一名普通程序员逆袭成为独角兽公司技术高管。出版过多本畅销书,写出多篇10W+文章。分享:行业趋势、职场经验、团队管理、商业通识等话题。

注:发文24小时后才可以转载,转载请注明:作者、来源、作者介绍。不规范转载一经发现,将永久取消转载资格。

-END-


5万块买来的《副业搞钱手册》,免费送啦!
关注副业怎么搞,回复:fuye


腾讯/谷歌《元宇宙 研究报告 100页》下载

关注AI熊猫教授,回复:yyz666


大家在看:

1.39岁阿里P9失业,资产1.5亿!

2.痛心!B站25岁员工深夜猝死

3.滴滴股票延期解禁,我损失6000万

4.如何用敏捷搞垮一个团队?

5.为什么CTO不写代码,还这么牛逼?

6.如何快速降低一个员工的积极性

怎样提高自己的系统架构水平?相关推荐

  1. 怎么提高自己的系统架构水平

    简介: 系统设计与架构理论这个问题,回答起来非常宽泛,基本所有的技术理论都可以涵盖.作为一个撸代码快 10 年的后端技术人员,简单发表一下我的看法. 原创 勇剑 淘系技术  7月15日 系统设计与架构 ...

  2. 系统架构设计师-软件水平考试(高级)-论文-架构风格

    系统架构设计师-论文-架构风格 前言: 这三个月由于工作等方面的事情,所以没有更新博客. 其实我是有做许多总结的.但是写博客,就需要整理格式,好麻烦啊.... 不过接下来,我会慢慢整理出来的,包括ja ...

  3. 系统架构设计师-软件水平考试(高级)-理论-项目管理

    系统架构设计师-项目管理 前言: 看来技术向的架构XMIND真的没人需要.(或者说,根本就是我的文章没人看...) 忙里偷闲,赶紧发一篇. 如果感觉图片模糊,请将图片下载,或放大图片.(图片绝对清晰) ...

  4. 从铁路订票系统问题看系统架构师的责任和水平

    据新闻报道铁路订票系统采用了排队系统,但排队时间需要30分钟.使很多人不满. 并且系统仍然有登陆不上的问题. 从描述看,系统很可能采用了本博客前面提到的异步处理架构. 但从用户体验看该系统架构师的设计 ...

  5. 2022年计算机软件水平考试系统架构设计师(高级)练习题及答案

    2022年计算机软件水平考试系统架构设计师(高级)练习题及答案,根据最新计算机软件水平考试系统架构设计师(高级)大纲与历年计算机软件水平考试系统架构设计师(高级)真题汇总编写,包含计算机软件水平考试系 ...

  6. 系统架构设计师-软件水平考试(高级)-理论-操作系统

    系统架构设计师-操作系统 前言: 之前文章发布后,发现还是有一定阅读量的,所以决定继续发一些思维导图. 思维导图首先以思维结构为主,其次以考试的内容进行一定的改动(如本次,将"嵌入系统&qu ...

  7. 系统架构设计师-软件水平考试(高级)-理论-计算机网络

    系统架构设计师-计算机网络 前言: 目测这类文章的需求真的不大,就不固定发了. 正好最近又要开始忙了... 如果感觉图片模糊,请将图片下载,或放大图片.(图片绝对清晰) 一,XMIND: 二,补充: ...

  8. 转:秒杀系统架构分析与实战

    原文出处: 陶邦仁   欢迎分享原创到伯乐头条 0 系列目录 秒杀系统架构 秒杀系统架构分析与实战 1 秒杀业务分析 正常电子商务流程 (1)查询商品:(2)创建订单:(3)扣减库存:(4)更新订单: ...

  9. 系统架构性能问题诊断及优化思路,纯干货!

    来源:http://blog.sina.com.cn/s/blog_493a84550102z8t2.html 今天谈下业务系统性能问题分析诊断和性能优化方面的内容.这篇文章重点还是谈已经上线的业务系 ...

最新文章

  1. [Flex][总结]从页面url获取参数
  2. 动态so库的链接:运行时链接和编译时链接
  3. python中链表和数组_数据结构笔记(一):数组、链表|python基础教程|python入门|python教程...
  4. POJ 1661 DP
  5. sql 插入日期格式
  6. Mac 抓包工具Charles4.0.2破解版,安装使用
  7. 什么是ANC降噪技术?耳机工厂来告诉你
  8. 正则表达式 Regular Express
  9. NOI Online Round 3 总结
  10. Python学员信息管理系统
  11. python可以在多平台运行 体现了python语言的,Python 可以在多平台运行,这体现了 Python 语言的 特性。...
  12. 除了性以外,有没有快速、高效的释放压力、清空大脑的方式?
  13. 硬盘主分区和逻辑驱动器的区别
  14. ShowType=0,● 交换机命令show interfaces type 0/port_# switchport|trunk用于显示中继连接的配置情况,下面...
  15. 计算机应用基础主要按键,计算机应用基础教案第一讲:键盘与鼠标(中职教育)...
  16. 鼠标宏编写脚本代码教程_PHP登录脚本代码和教程
  17. 2.某服装店进行促销活动,一件上衣原价90元,裤子原价45元,现一套120元。 如果我买m套上衣和n套裤子,最少花费多少钱?
  18. 海思芯片部署MPP并验证功能
  19. CSS和js和HTML一起做出网页版别踩白块游戏
  20. 脚本录制软件python 按键精灵 tc_使用Python来做一个屏幕录制工具的操作代码

热门文章

  1. 黑马程序员 自编简易记事本应用程序
  2. Ubuntu22.04编译Android切换Python2.7版本
  3. 【random库与math库】python程序对一组随机数求平均值,标准差,中位数,离差,离差方,总体方差,样本方差,样本标准差
  4. 定位、相对定位、绝对定位
  5. 软件加密系统Themida应用程序保护指南(十):高级选项
  6. 【数据库】Windows下如何安装MySql
  7. nextcloud服务器配置文档,NextCloud挂载数据盘
  8. 【航线运输驾驶员理论考试】领航
  9. WEB项目结构小教程
  10. 全连接层tf.keras.layers.Dense()介绍