分布式系统问题
并发性
没有全局时钟
故障独立性
分布式系统概念
分布式优势
资源共享、开放性、并发性、可扩展性、容错性
问题挑战
分布式系统总部特性很难了解
分布式系统响应不可预知
不能自顶向下
设计原则
透明性
开放性:按照普遍标准
可扩展性(规模、分布、可管理性)
增强扩展(垂直扩展):如电脑内存16G->64G
增加扩展(纵向扩展):如一台电脑不够加了很多台
信息安全性:分布式系统更容易被攻击
攻击类型:拦截、中断、更改、捏造
加密+认证+访问权限控制
服务质量(QoS)
分布式系统模型
结构模型
元素
- 通信实体:进程、对象、组件、web服务
- 通信泛型(交互):
-
- 进程间通信
- 远程调用:请求-应带、RPC、RMI
- 间接通信
- 角色和责任:
-
- 客户/服务端
- 对等
- 放置:将服务映射到多个服务器、缓存、移动代码、移动代理
体系结构模式
- 分层(垂直):应用、中间件、操作系统、计算机和网络硬件
- 层次化体系结构:两层、三层、瘦客户
- 中间件:
基础模型
进程分类
服务器进程、客户进程、对等进程
角色与职责
Client-server:服务器客户
peer process:P2P系统、BT系统
放置
代理服务器与缓存
移动代码
如Applets
移动代理
Web爬行者(爬虫)
分层
操作系统->中间件->分布式应用
层次化体系结构
两层客户机-服务器结构
客户机和服务器进行联系交互
瘦客户机模型
浏览器直接拿来用、没有安装过程
胖客户机模型
玩游戏下软件、安装程序才能使用、部分能力或所有能力分布到客户机、再比如银行的ATM
多层客户机-服务器结构
分出不同的服务器做不同的事。
比如网上银行系统的三层系统结构。
比如Nginx负载均衡。
中间件
分布式中的进程和线程
进程和线程的概念、模型、上下文切换
进程的概念
进程的状态
中断处理与调度
进程和线程的区别
线程的状态
上下文切换
进程切换与线程切换的区别:最主要区别在于进程切换涉及到虚拟地址空间的切换而线程切换不会。这也是进程切换比线程切换慢的原因。
八股知识点(操作系统):
进程是处理机调度的基本单位,同一个进程中的所有线程共享该进程分配到的所有资源。
一个进程可以包含多个进程,但至少包含一个线程。
一个线程只能属于一个进程。
并行与并发
并行:同一时间同时执行。强调同一时刻,你打游戏和你女朋友打你同时进行。当你按下时间静止,看到很多进程或线程活着,
并发:同一时间段多个任务轮流执行。强调一段时间很多事情同时发生,但同一时刻只能干一件事。你打完游戏后去哄你女朋友,然后可能接着打游戏或者做别的事。当你按下时间静止,只能看到一个进程或线程活着,其他都在排队。
线程的三种实现方式
分布式通信
分层通信协议
OSI七层、五层、TCP/IP四层
中间层协议
中间件层
- 独立于应用的协议,支持中间件服务
- 通信协议(RPC等)
中间件层位于传输层和应用层之间。
远程过程调用(RPC)
- 将单机环境下的过程调用延伸到分布式系统环境。
- ISO将RPC作为计算机网络,分布式计算机系统的国际标准化草案。
- 一种信息交换的标准规程。
透明性:你看不见RPC的存在,所以从用户来看,是透明的。
指用户可以像调用本地过程一样调用不同地域的不同计算机上的过程。
call remote procedure(RPC)
数据复制
扩展:集群的水平扩展和垂直扩展有什么区别? - Zhai_David - 博客园
1.主从节点(写少读多)(主读写+从读)
支持主从复制系统有:
- 关系型数据库:MySQL、SQL Server、PostgreSQL等
- 非关系型数据库:MongoDB、RethinkDB、Espresso等
- 消息队列:kafka、RabbitMQ
同步复制与异步复制
同步能保证数据的一致性
异步不能保证数据的一致性(但响应很快)
添加新的follower?
可能会出现数据不一致的问题,可以通过加锁解决。
也可以不用数据库加锁:建立leader数据的镜像,然后把镜像拷贝给follower,然后通过log(日志)记录对主节点的所有操作,比如对某数据的增删改查,然后通过看log记录的操作,从节点就可以完成和后来主节点一样的操作。
follower故障:(追赶式恢复)
leader故障:一个从节点会升级为新的主节点(这个过程叫故障恢复)、选举流程,投票机制。即使最后原先的主节点活过来,也只能变成新主的仆从。
复制日志的实现?
Statement-based replication(基于语句的复制,把”修改“记录下来)(但是也有问题:比如表达式中的时间函数NOW()等等)
Write-ahead log (WAL) shipping(预写日志)(将字节变化写在日志里,但是有问题,如果引擎不同的话)
Logical(基于行)log replication ()(把每一行的变化记下来,比如MySQL的binlog)
Trigger…(基于触发器的复制)
一文让你彻底明白分布式系统中的数据复制是怎么一回事? - 古明地盆 - 博客园
复制滞后问题
1.读己之写
用户在主节点改,在主节点读。这样就可以避免读不到数据的问题。
2.单调读
因为有时候会产生时光倒流。解决方法:让某个用户只在一个节点读,别老是跳来跳去(单调读取)。
3.一致前缀读
2.多主节点复制
多个主节点:允许多个节点写数据。
数据中心:
冲突解决机制:防止2个主同时读写,造成冲突。(双主写冲突解决方法:最后写入获胜(时间戳)、副本分配唯一id、…)
应用场景:
手机和笔记本上的微信同时登录
协同编辑
3.无主复制
没有主从概念,所有节点都是主节点,都可以读和写。
当节点故障时写入数据库
无主,共3个副本,1个坏了。写入,2个成功就视为写成功(少数服从多数)–>读取(少数服从多数)–>不能不管那个旧的,把读的新数据写给那个旧的。(旧的版本号比新的版本号低,所以version低的那个是旧的)
读写的法定人数quorum:
w+r>n(所以读写的副本必然有w+r-n个重叠)(只有有重叠才能一定保证读的副本里有新写进去的副本)
w、r大于n/2(少数服从多数)
7个副本最多能容忍3个副本错误
5个副本最多能容忍2个副本错误
3个副本最多能容忍1个副本错误
少数服从多数
分布式事务
事务不是一个天然存在的东西,是人为创造出来的。
什么是事务?
简化异常的处理,将读写请求合并到一组,构成一个逻辑单元,交给数据库。数据库将逻辑单元的所有操作视为一个操作,要么成功(提交),要么失败(回滚)。应用程序可以在事务执行失败时,安全地进行重试,应用程序可以不必担心事务操作部分成功,部分失败。
ACID含义
原子性:把多个操作放在一个事务里,要么全成功,要么全失败
一致性:约束。比如外键限制、唯一性限制。
隔离性:并发执行的事务各自隔离,并不影响互相执行的结果。隔离性也叫串行化,每个事务提交给人感觉像串行提交一样。串行的隔离性很少用(一个一个做),对性能影响较大,一般我们会用弱一点的隔离性。
持久性:事务写入的任何数据不会丢。(write-ahead log)WAL预写日志。
多对象事务操作
ACID中的原子性和隔离性主要针对客户端在同一事务中包含多个写操作时,数据库所提供的保证。
隔离性
脏读
一个事务读到了另一个事务还未commit的写操作
原子性
保证前一些操作可以撤销,避免不一致(有的做了有的没做)。
单对象事务操作
仍存在原子性和隔离性问题。
弱隔离级别
读提交
两个保护:没有脏读(读时,只能读已经提交后的数据)、没有脏写(写时,只能覆盖已经提交后的数据)。
脏读:读了未提交的数据。回滚麻烦。
脏写:写(或者说覆盖)了未提交的数据。
如何实现读提交
(写数据时加锁)使用行锁,来防止脏写。(和串行的区别,串行的读和写都加锁)
?来防止脏读
快照隔离和可重复读
解决读提交可能遇到的问题。
**快照隔离:**记录每个事务的修改记录,保留数据的多个版本,因此也称为多版本并发控制(MVCC:multiple verson concurrency control)
表中的每一行都有一个created_by字段和deleted_by字段。
写偏和幻读
写偏(移)解决方法:加锁
串行化
可序列化隔离通常被认为是最强的隔离级别。
3种
真正的串行执行
一个线程处理所有事务,避免使用锁,单一CPU工作。
在存储过程中封装事务。
存储过程的概念:SQL – 存储过程(详细)_sql存储过程-CSDN博客
两阶段锁定(2PL)
两阶段锁(2PL)是数据库控制并发操作的简单规则,用一句话概括:
“加锁阶段只加锁不解锁,解锁阶段只解锁不加锁”
就像去图书馆借书:
- 借书阶段:你可以不断借新书(加锁),但不能还书(解锁)
- 还书阶段:你只能还书(解锁),不能再借新书(加锁)
🔑 关键点:
- 保证事务不会中途释放锁后又去抢新锁
- 避免出现A事务读的数据被B事务修改后又读到的混乱情况
- 所有锁会在事务结束时(提交或回滚)统一释放
💡 实际效果:
- 就像排队办业务,一个人办完所有手续才会离开窗口(不会办到一半让给别人)
- 虽然可能排队时间变长,但保证不会出现数据错乱
这是数据库维持数据一致性的基础方法,现代数据库会优化这个机制(如配合MVCC)来提高并发性能。