2025-09-06 23:03:29
摘要:一、缓存
基本上来说,在分布式系统中最耗性能的地方就是最后端的数据库了。
一般来说,只要小心维护好,数据库四种操作(select、update、insert 和 delete)中的三个写操作 insert、update 和 delete 不太会出现性能问题(insert 一般不会有性能问题,update 和 delete 一般会有主键,所以也不会太慢)。除非索引建得太多,而数据库里的数据又太多,这三个操作才会变慢。
绝大多数情况下,select 是出现性能问题最大的地方。一方面,select 会有很多像 join、group、order、like 等这样丰富的语义,而这些语义是非常耗性能的;另一方面,大多数应用都是读多写少,所以加剧了慢查询的问题。
分布式系统中远程调用也会消耗很多资源,因为网络开销会导致整体的响应时间下降。为了挽救这样的性能开销,在业务允许的情况下,使用缓存是非常必要的事情。
缓存是提高性能最好的方式,一般来说,缓存有以下三种模式。
1. Cache Aside 更新模式
这是最常用的设计模式了,其具体逻辑如下。
失效:应用程序先从 Cache 取数据,如果没有得到,则从数据库中取数据,成功后,放到缓存中。
命中:应用程序从 Cache 中取数据,取到后返回。
更新:先把数据存到数据库中,成功后,再让缓存失效。
这是标准的设计模式,为什么不是写完数据库后更新缓存?主要是怕两个并发的写操作导致脏数据。
那么,是不是这个 Cache Aside 就不会有并发问题了?不是的。比如,一个是读操作,但是没有命中缓存,就会到数据库中取数据。而此时来了一个写操作,写完数据库后,让缓存失效,然后之前的那个读操作再把老的数据放进去,所以会造成脏数据。
这个案例理论上会出现,但实际上出现的概率可能非常低,因为这个条件需要发生在读缓存时缓存失效,而且有一个并发的写操作。实际上数据库的写操作会比读操作慢得多,而且还要锁表,读操作必须在写操作前进入数据库操作,又要晚于写操作更新缓存,所有这些条件都具备的概率并不大。
当然,最好还是为缓存设置好过期时间。
2. Read/Write Through 更新模式
在 Cache Aside 套路中,应用代码需要维护两个数据存储,一个是缓存,一个是数据库。所以,应用程序比较啰嗦。而 Read/Write Through 套路……
阅读全文
2025-08-30 20:38:31
摘要:一、分布式锁
我们知道,在多线程情况下访问一些共享资源需要加锁,不然就会出现数据被写乱的问题。在分布式系统下,这样的问题也是一样的。只不过,我们需要一个分布式的锁服务。
分布式的锁服务需要有以下几个特点。
安全性(Safety):在任意时刻,只有一个客户端可以获得锁(排他性)。
避免死锁:客户端最终一定可以获得锁,即使锁住某个资源的客户端在释放锁之前崩溃或者网络不可达。
容错性:只要锁服务集群中的大部分节点存活,Client 就可以进行加锁解锁操作。
1. Redis 的分布式锁服务
我们通过以下命令对资源加锁。
SET resource_name my_random_value NX PX 30000
解释一下:
SET NX 命令只会在 key 不存在的时候给 key 赋值,PX 命令通知 Redis 保存这个 key 30000ms。
my_random_value 必须是全局唯一的值。这个随机数在释放锁时保证释放锁操作的安全性。
PX 操作后面的参数代表的是这个 key 的存活时间,称作锁过期时间。
当资源被锁定超过这个时间时,锁将自动释放。
获得锁的客户端如果没有在这个时间窗口内完成操作,就可能会有其他客户端获得锁,引起争用问题。
通过下面的脚本为申请成功的锁解锁:
if redis.call(get,KEYS[1]) == ARGV[1] then
return redis.call(del,KEYS[1])
else
return 0
end
如果 key 对应的 value 一致,则删除这个 key。通过这个方式释放锁是为了避免 Client 释放了其他 Client 申请的锁。
2. 分布式锁服务的一个问题
虽然 Redis 文档里说他们的分布式锁是没有问题的,但其实还是很有问题的。尤其是上面那个为了避免 Client 端把锁占住不释放,然后,Redis 在超时后把其释放掉,这事儿听起来就有点不靠谱。
我们来脑补一下,不难发现下面这个案例。
1. 如果 Client A 先取得了锁。
2. Client B 在等待 Client A 的工作完成。
3. 这个时候,如果 Client A 被挂在了某些事上,比如一个外部的阻塞调用,或是 CPU 被别的进程吃满,或是不巧碰上了 Full GC,导致 Client ……
阅读全文
2025-08-24 23:12:10
摘要:对于分布式系统的容错设计,在英文中又叫 Resiliency(弹力)。意思是,系统在不健康、不顺,甚至出错的情况下有能力 hold 得住,挺得住,还有能在这种逆境下力挽狂澜的能力。其中着眼于分布式系统的各种“容忍”能力,包括服务隔离、异步调用、请求幂等性、可伸缩性(有 / 无状态的服务)、一致性(补偿事务、重试)、应对大流量的能力(熔断、降级)。可以看到,在确保系统正确性的前提下,系统的可用性是弹力设计保障的重点。
我们很难计算我们设计的系统有多少的可用性,因为影响一个系统的因素实在是太多了,除了软件设计,还有硬件,还有第三方服务(如电信联通的宽带 SLA),当然包括“建筑施工队的挖掘机”,宕机原因主要有以下这些:
网络问题。网络链接出现问题,网络带宽出现拥塞……
性能问题。数据库慢 SQL、Java Full GC、硬盘 IO 过大、CPU 飙高、内存不足……
安全问题。被网络攻击,如 DDoS 等。
运维问题。系统总是在被更新和修改,架构也在不断地被调整,监控问题……
管理问题。没有梳理出关键服务以及服务的依赖关系,运行信息没有和控制系统同步……
硬件问题。硬盘损坏、网卡出问题、交换机出问题、机房掉电、挖掘机问题……
一个分布式系统的故障是非常复杂的,因为故障是分布式的、多米诺骨牌式的。所以,要充分地意识到下面两个事。
故障是正常的,而且是常见的。
故障是不可预测突发的,而且相当难缠。
这就是为什么我们把这个设计叫做弹力(Resiliency)。
一方面,在好的情况下,这个事对于我们的用户和内部运维来说是完全透明的,系统自动修复不需要人的干预。
另一方面,如果修复不了,系统能够做自我保护,而不让事态变糟糕。
一、隔离设计
隔离设计对应的单词是 Bulkheads,中文翻译为隔板,这个概念来自于船舱里防漏水的隔板。我们的软件设计当然也“漏水”,所以为了不让“故障”蔓延开来,需要使用“隔板”技术,来将架构分隔成多个“船舱”来隔离故障。
1. 按服务的种类来做分离
上图中,我们将系统分成了用户、商品、社区三个板块。这三个块分别使用不同的域名、服务器和数据库,做到从接入层到应用层再到数据层三层完全隔离。这样一来,在物理上来说,一个板块的故障就不会影响到另一板块。
上面这种架构虽然在系统隔离上做得比较好,但是也存在以下一些问题。
如果我们需要同时获得多……
阅读全文
2025-08-23 21:03:23
摘要:我们一直在谈论各式各样的架构,如高并发架构、异地多活架构、容器化架构、微服务架构、高可用架构、弹性化架构等。还有和这些架构相关的管理型的技术方法,如 DevOps、应用监控、自动化运维、SOA 服务治理、去 IOE 等。面对这么多纷乱的技术,很多团队或是公司都是一个一个地去做这些技术,非常辛苦,也非常累。
接下来我们来谈一谈分布式架构。
一、概述
1. 分布式的优缺点
首先,为什么需要分布式系统,而不是传统的单体架构。
增大系统容量。我们的业务量越来越大,而要能应对越来越大的业务量,一台机器的性能已经无法满足了,我们需要多台机器才能应对大规模的应用场景。所以,我们需要垂直或是水平拆分业务系统,让其变成一个分布式的架构。
加强系统可用。我们的业务越来越关键,需要提高整个系统架构的可用性,这就意味着架构中不能存在单点故障。这样,整个系统不会因为一台机器出故障而导致整体不可用。所以,需要通过分布式架构来冗余系统以消除单点故障,从而提高系统的可用性。
当然,分布式系统还有一些优势,比如:
因为模块化,所以系统模块重用度更高;
因为软件服务模块被拆分,开发和发布速度可以并行而变得更快;
系统扩展性更高;团队协作流程也会得到改善;
……
不过,这个世界上不存在完美的技术方案,采用任何技术方案都是“按下葫芦浮起瓢”,都是有得有失,都是一种 trade-off。也就是说,分布式系统在解决上述问题的同时,也给我们带来了其他的问题。因此,我们需要清楚地知道分布式系统所带来的问题。
从上面的表格我们可以看到,分布式系统虽然有一些优势,但也存在一些问题。
架构设计变得复杂(尤其是其中的分布式事务)。
部署单个服务会比较快,但是如果一次部署需要多个服务,流程会变得复杂。
系统的吞吐量会变大,但是响应时间会变长。
运维复杂度会因为服务变多而变得很复杂。
架构复杂导致学习曲线变大。
测试和查错的复杂度增大。
技术多元化,这会带来维护和运维的复杂度。
管理分布式系统中的服务和调度变得困难和复杂。
2. 面向服务的架构有以下三个阶段
下面是一个 SOA 架构的演化图。
我们可以看到,面向服务的架构有以下三个阶段。
20 世纪 90 年代前,是单体架构,软件模块高度耦合。当然,这张图同样也说明了有的 SOA 架构其实和单体架构没什么两样,因为都是高度耦合在一起的。就像图中的齿轮一……
阅读全文
2025-08-10 10:55:01
摘要:一、安装Harbor
1. Harbor介绍
Harbor是由VMWare在Docker Registry的基础之上进行了二次封装,加进去了很多额外程序,而且提供了一个非常漂亮的web界面。
Project Harbor是一个开源的受信任的云本地注册表项目,用于存储、标记和扫描上下文。
Harbor扩展了开源Docker发行版,增加了用户通常需要的功能,如安全、身份和管理。
Harbor支持高级特性,如用户管理、访问控制、活动监视和实例之间的复制。
2. 功能
多租户内容签名和验证
安全性与漏洞分析
审计日志记录
身份集成和基于角色的访问控制
实例间的镜像复制
可扩展的API和图形UI
国际化(目前为英文和中文)
3. docker compose
Harbor在物理机上部署是非常难的,而为了简化Harbor的应用,Harbor官方直接把Harbor做成了在容器中运行的应用,而且这个容器在Harbor中依赖类似redis、mysql、pgsql等很多存储系统,所以它需要编排很多容器协同起来工作,因此VMWare Harbor在部署和使用时,需要借助于Docker的单机编排工具(Docker compose)来实现。
Compose是一个用于定义和运行多容器Docker应用程序的工具。使用Compose,我们可以使用YAML文件来配置应用程序的服务。然后,只需要一个命令,就可以从配置中创建并启动所有服务。
4. 部署
需要提前安装好docker
提前下载好安装包:Release v2.13.2 · goharbor/harbor · GitHub
安装docker-compose
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.39.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
docker comp……
阅读全文
2025-08-09 10:45:35
摘要:最近公司有个.net项目需要集群部署,由于不打算使用K8S,计划用docker swarm来搭建整个集群环境。
所以计划用2篇文章,记录一下docker swarm部署的整个过程。
文章使用的环境是本地虚拟机环境,生产环境大同小异。
文中用的到资料下载:docker-swarm.zip
一、安装 Docker
对于 Ubuntu/Debian 系统:
# 查看 ip
ip a
使用工具测试链接,如putty
# 1. 更新软件包索引
sudo apt-get update
# 2. 安装依赖包
sudo apt-get install ca-certificates curl gnupg lsb-release
# 3. 添加 Docker 官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 4. 设置稳定版仓库
echo deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null
# 5. 安装 Docker 引擎
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 检查 Docker 版本
docker --version
对于 CentOS/RHEL 系统:
# 安装依赖包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加 Docker 仓库
sudo yum-config-manager --add-r……
阅读全文
2017-10-22 11:48:21
摘要:高并发系统架构常用案例
通用场景
日用户流量大,但是比较分散,偶尔会有用户高聚的情况;
解决思路
通过服务器架构和代码分流,系统架构设计保证它能够同时并行处理很多请求
场景特征
高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率 QPS(Query Per Second),每秒事务处理量(TPS),并发用户数等
测试模拟工具
Apache Jmeter
2.Visual Studio性能负载测试
3.Microsoft Web Application Stress Tool
分布式
分布式应用和服务,将分层或者分割后的业务分布式部署,独立的应用服务器,数据库,缓存服务器
当业务达到一定用户量的时候,再进行服务器均衡负载,数据库,缓存主从集群
分布式静态资源,比如:静态资源上传cdn
分布式计算,比如:使用hadoop进行大数据的分布式计算
分布式数据和存储,比如:各分布节点根据哈希算法或其他算法分散存储数据。
缓存
分析:高并发业务接口多数都是进行业务数据的查询,如:商品列表,商品信息,用户信息,红包信息等,这些数据都是不会经常变化,并且持久化在数据库中. 高并发的情况下直接连接从库做查询操作,多台从库服务器也抗不住这么大量的连接请求数(前面说过,单台数据库服务器允许的最大连接数量是有限的)。 结论:缓存将是一个不错的选择。浪费内存。
异步
分析:在高并发业务中如果涉及到数据库操作,主要压力都是在数据库服务器上面,虽然使用主从分离,但是数据库操作都是在主库上操作,单台数据库服务器连接池允许的最大连接数量是有限的 。当连接数量达到最大值的时候,其他需要连接数据操作的请求就需要等待有空闲的连接,这样高并发的时候很多请求就会出现connection time out 的情况 。 结论:异步将是一个不错的选择
分层/隔
1.分层,将系统在横向维度上切分成几个部分,每个部门负责一部分相对简单并比较单一的职责,然后通过上层对下层的依赖和调度组成一个完整的系统.
2.分隔,在纵向方面对业务进行切分,将一块相对复杂的业务分割成不同的模块单元.
3.包装成高内聚低耦合的模块不仅有助于软件的开发维护,也便于不同模块的分布式部署,提高网站的并发处理能力和功能扩展. 比如用户中心可以分割成:账户信息模块,订单模块,充……
阅读全文
2017-09-21 20:54:57
摘要:参考
什么是负载均衡--阿里云
反向代理
内容服务器的替身
如果内容服务器具有必须保持安全的敏感信息,如信用卡号数据库,可在防火墙外部设置一个代理服务器作为内容服务器的替身。
当外部客户机尝试访问内容服务器时,会将其送到代理服务器。
实际内容位于内容服务器上,在防火墙内部受到安全保护。
代理服务器位于防火墙外部,在客户机看来就像是内容服务器。
代理服务器成为安全数据库和可能的恶意攻击之间又一道屏障。
即便这道屏障打破,充其量也仅限于访问单个事务中所涉及的信息。
未经授权的用户无法访问到真正的内容服务器,因为防火墙通路只允许代理服务器有权进行访问。
内容服务器的负载均衡器
可以在一个组织内使用多个代理服务器来平衡各 Web 服务器间的网络负载。
在此模型中,可以利用代理服务器的高速缓存特性,创建一个用于负载平衡的服务器池。
对于客户机发往真正服务器的请求,代理服务器座位中间调停者,将所请求的文档存入高速缓存。
如果有不止一个代理服务器,DNS 采用“循环复用法”选择其 IP 地址,随机地为请求选择路由。
即便是同一个 URL发出请求,所采取的路由每次都可能经过不同的代理服务器。
特征:
内容服务器可以处理更高的负载,并且比其独自工作时更有效率。
适用于处理高用量内容服务器的请求
负载均衡
四层负载均衡
四层负载均衡工作在 OSI 模型的传输层,由于在传输层,只有 TCP/UDP 协议,这两种协议中除了包含源 IP、目标 IP 以外,还包含源端口号及目的端口号。
四层负载均衡服务器在接受到客户端请求后,以后通过修改数据包的地址信息( IP+端口号 )将流量转发到应用服务器
七层负载均衡
七层负载均衡工作在 OSI 模型的应用层,应用层协议较多,常用 HTTP、Radius、DNS 等。
七层负载就可以基于这些协议来负载。 这些应用层协议中会包含很多有意义的内容。
LVS(Linux Virtual Server)
也就是 Linux 虚拟服务器,是一个由章文嵩博士发起的自由软件项目。 使用 LVS 技术要达到的目标是:通过 LVS 提供的负载均衡技术和 Linux 操作系统实现一个高性能、高可用的服务器群集,它具有良好可靠性、可扩展性和可操作性。从而以低廉的成本实现最优的服务性能。
SLB
阿里云当前提供四层和七层的负载均衡服务。
四层采用开源软件L……
阅读全文
2017-09-16 10:41:18
摘要:高并发高可用角度架构演进
单机应用(WebSite)
渐渐的随着用户量的增加, 问题:一台服务器已经不够用了,服务器不稳定。挑战:高可用/高并发。 解决方式:于是我们将准备两台服务器搭成集群
简单集群(WebSite)
搭完集群之后,假如原来十个用户访问一台服务器,现在平均开,五个人访问上面的服务器,五个人访问另一个服务器。 用户的体验就会稍微好一点。
好处:简单高可用,假如其中一台服务器挂了,是不影响用户访问的,因为用户可以访问另一台好的服务器
问题:这样做有一个局限性,就是同时存在两个服务器,就会同时存在两个外网IP/域名 。 解决方式:于是我们增加了一个代理服务器,用户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以
负载均衡集群(WebSite)
增加代理服务器后,用户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以了。由代理服务器来负责分发用户是访问服务器A还是访问服务器B。用户具体是访问服务器A还是访问服务器B,我们可以通过nginx里面的权重设置来决定的。
好处:服务器高可用,户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以
问题:这样做不少局限性,数据的存储问题,服务器缺少角色分工,如磁盘损坏,数据是不安全的。
解决方式:于是这里我们使用了JAVA的MVC设计思想,我们将数据进行了抽取,服务器A和服务器B仅负责动态代理的分发,而不负责数据的存储,具体的数据放到数据服务器当中,数据库分离
MVC集群(WebSite)
增加代理服务器后,用户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以了。由代理服务器来负责分发用户是访问服务器A还是访问服务器B。用户具体是访问服务器A还是访问服务器B,我们可以通过nginx里面的权重设置来决定的。
好处:服务器高可用,户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以
问题:用户通过代理服务器分发到应用服务器,而应用服务器负责从数据库服务器进行数据的读取和写入。
解决方式:这里是关系型数据库,是遵循原子性、一致性、隔离性、持久性四大特性的;这时候是业务层分离的,即主服务器负责写,从服务器负责读,这就是数据的一致性和主从库读写分离。
数据库集群(DataBase)
用户通过代理服务器分发……
阅读全文
2017-09-12 13:17:27
摘要:持续发布/部署需求
持续部署和持续发布[CI/CD]:
复杂软件架构,往往带来更多的地面分层,更多的软件节点。系统的节点发布就会变得很麻烦。特别微服务 系统得持续发布,持续部署就是为了解决这些问题
持续集成:
强调开发人员提交了新代码之后,立刻进行构建、(单元)测试,根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起
持续交付:
是在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的Staging环境中更多的测试
持续集成
持续集成(Continuous Integration, 持续集成)
持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
常用的工具:Hudson和Jenkins
持续部署
持续部署(Continuous Delivery,持续交付)
在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的Staging环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境。
Jenkins实现CD: https://blog.csdn.net/xiangnan10/article/details/80332866?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecasedepth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
自动化测试需求
复杂得软件架构,如:PAAS,SAAS,IAAS。过多得分层带来自动化部署,往往也带来自动化测试的需求。 对于自动化,用代码来代替手工,软件测试就是在预设条件下运行系统或应用程序,评估运行结果,预先条件应包括正常条件和异常条件。 Selenium 架构图
自动化运维需求
解决中小形的架构问题: 1.开发人员兼职完成,监控……
阅读全文