Skip to content

基础架构

单机房的内部架构

单机房典型架构角色功能:

  1. DNS服务器:域名映射为公网IP(机房入口)。
  2. LVS (Linux Virtual Server):提供公网IP作为机房入口,作为四层负载均衡器分发请求到Nginx集群。
  3. Nginx:七层负载均衡器,根据HTTP(S)协议头/URL路径转发请求到对应的业务HTTP服务器。
  4. 业务服务层 (HTTP服务):处理用户请求,根据URL向RPC服务发送业务逻辑处理请求。
  5. 业务服务层 (RPC服务):执行核心业务逻辑,访问数据层或调用其他RPC服务。
  6. 存储层:所有存储系统的集合,包括分布式缓存(如Redis)、关系型数据库(如MySQL)、NoSQL数据库。
  7. 服务发现:保存每个服务的动态访问地址列表,供其他服务查找(功能与DNS相似)。
  8. 消息中间件:请求异步执行、服务间解耦、请求削峰填谷。

客户端连接机房的技术:DNS

  • TCP/IP通信基础:IP地址(标识设备、网络寻址)。
  • 域名:易读易记的字符型地址方案,DNS实现域名到IP的翻译。
  • DNS意义
    • 互联网公司创建易记域名。
    • 通过多IP映射实现负载均衡。
    • 架构升级/IP变更时,仅修改DNS,对用户无干扰。
    • 可实现灵活负载均衡策略(如剔除宕机IP)。
  • 域名结构:层次化树形结构,根 -> 顶级域名 (TLD) -> 二级域名 -> 三级域名等。
  • 域名服务器类型
    1. 根域名服务器:全球互联网中枢,掌握全部顶级域名名称与IP映射。
    2. 顶级域名服务器:管理顶级域名下的二级域名解析,寻找二级域名服务器IP。
    3. 权威域名服务器:对特定域名进行解析,最终决定域名解析到哪个IP(DNS核心)。
    4. 本地域名服务器 (本地DNS):不属层级结构,但对DNS重要(缓存),由网络运营商提供,主机查询时首先查询。
  • 域名解析过程 (递归查询)
    1. 客户端查询本地缓存(浏览器缓存、Hosts文件)。
    2. 无则向本地域名服务器发起请求。
    3. 本地域名服务器向根域名服务器请求。
    4. 根返回顶级域名服务器地址。
    5. 本地域名服务器向顶级域名服务器请求。
    6. 顶级返回权威域名服务器地址(或直接返回IP)。
    7. 本地域名服务器向权威域名服务器请求。
    8. 权威返回最终IP,本地域名服务器缓存并返回给客户端。
  • DNS解析记录格式:Domain (域名), TTL (生存周期), Class (协议类型,IN-因特网), Type (记录类型,A-IPv4, AAAA-IPv6), Rdata (记录数据)。

HTTP DNS

  • DNS存在的问题
    • 访问延迟高:递归查询耗时。
    • 调度精准性差:本地域名服务器 IP 不准确定位客户端地理位置,可能返回非最优节点。
    • 域名转发:运营商为节约资源转请求到其他运营商DNS,导致IP不符,访问慢。
    • DNS劫持:攻击方式,解析到错误或恶意IP (运营商劫持、黑客篡改Hosts)。
  • HTTP DNS原理
    1. 客户端指定HTTP DNS服务器IP(固定IP),使用HTTP调用域名解析接口,传入域名和客户端IP。
    2. HTTP DNS服务器向权威DNS服务器发起解析请求,返回最优IP。
    3. 客户端获取IP后,直接向此IP发送业务请求。
  • HTTP DNS解决的问题
    • 降低域名解析延迟:直接访问,缩短解析链路。
    • 防止域名劫持:绕过运营商本地DNS。
    • 调度精准性更高:获取真实客户端IP,基于精确位置/运营商信息解析到更近/最优IP。
    • 快速生效:不受传统DNS多级缓存影响,更新更快覆盖全量客户端。
  • HTTP DNS实践
    • 容灾策略(重要)
      1. 先尝试HTTP DNS。
      2. 失败则降级到本地DNS。
      3. 再失败则使用预留的域名兜底IP地址。
    • 安全策略:使用HTTPS。
    • IP地址选取策略:HTTP DNS下发多个最优IP,客户端依次校验连通性。
    • 批量拉取策略:冷启动/网络切换时批量拉取映射数据并缓存。

接入层的技术演进

  • 早期架构问题:业务HTTP服务器直接绑定公网IP。
    • 可用性低:DNS无法高效感知实例宕机。
    • 可扩展性差:扩容需额外配置DNS,生效慢。
    • 安全风险高:业务IP暴露公网。
  • 解决方案:引入中间层 (Nginx)。

Nginx

  • 代理分类
    • 正向代理:代理客户端(如VPN),客户端知道自己访问的是代理。
    • 反向代理:代理服务器(如Nginx),客户端不知道访问的是代理,对外表现为目标服务器。
  • Nginx作为反向代理
    • 强大的基于域名和HTTP URL的路由转发功能。
    • 通过nginx.conf配置worker_processes (工作进程数), worker_connections (连接数), http块 (包含serverupstream)。
    • server块:listen (监听端口), server_name (虚拟主机名), location (URL路径处理规则), proxy_pass (反向代理目标)。
    • upstream块:定义服务池,包含server实例地址。
  • Nginx负载均衡策略
    • 轮询 (默认):按时间顺序分发,故障自动剔除。
    • 加权轮询:按权重分配请求,权重高更容易被访问。
    • ip_hash:根据客户端IP哈希,确保同一IP请求访问同一实例 (不保证负载均衡)。
    • least_conn:转发给连接数最少的服务器 (适用于请求响应时间长,实现更好负载均衡)。
    • url_hash (第三方):对URL哈希,提高相同请求缓存命中率。
    • fair (第三方):根据响应时间、失败数、请求量综合选择最空闲服务器。
  • Nginx作为七层负载均衡器:基于HTTP协议(OSI第七层)。
  • Nginx实时感知业务服务地址变更
    • 问题:业务频繁迭代扩容导致upstream配置频繁变更。
    • 解决方案:
      • ngx_lua模块:嵌入Lua脚本。
      • ngx_http_dyups_module模块:Nginx无需重启热更新upstream配置。
      • 流程:定期从服务注册中心获取最新地址列表 -> 生成最新upstream配置 -> 通过ngx_http_dyups_module更新。
  • Nginx优势
    • DNS指向Nginx,业务服务器IP切换无需配置DNS。
    • 实现客户端与业务服务器间的负载均衡。
    • 对外只暴露一个公网IP,节约IP资源。
    • 保护业务服务器,增强安全性。
    • 增强系统可扩展性,准实时生效。
    • 提高业务服务器可用性(实例故障自动迁移)。

LVS (Linux Virtual Server)

  • 定义:Linux虚拟服务器集群系统,Linux内核一部分,运行于操作系统层面。
  • LVS vs. Nginx
    • Nginx:OSI七层(应用层),异步转发,强调“代理”,支持失败转移,功能强大。
    • LVS:OSI四层(网络层),同步转发,强调“转发”,性能更高(免去应用层解析)。
  • 常用名词
    • DS (Director Server):四层负载均衡器节点 (LVS服务器)。
    • RS (Real Server):DS请求转发目的地 (真实工作服务器)。
    • VIP (Virtual Server IP):客户端请求目的IP (DS的公网IP)。
    • DIP (Director Server IP):DS与RS通信IP (DS的内网IP)。
    • RIP (Real Server IP):后端服务器IP。
    • CIP (Client IP):客户端IP。
  • LVS转发模式
    1. NAT模式 (Network Address Translation)
      • 原理:修改请求报文的目标IP/端口。
      • 特点:请求/响应均经过DS重写,DS是RS网关。
      • 条件:DS需两块网卡,DS与RS同局域网,DS为网关。
      • 缺点:响应数据大,DS易成性能瓶颈。
    2. FULLNAT模式 (Full NAT)
      • 原理:在NAT基础上再次进行源IP地址转换(将CIP改为DIP)。
      • 特点:不要求DS与RS同局域网或DS为网关。
      • 缺点:请求到达RS后丢失客户端IP地址。
      • 推荐模式:网络环境适应性强。
    3. TUN模式 (IP隧道模式)
      • 原理:DS将请求报文封装到新数据包,目的IP为RS的RIP,通过IP隧道发送。RS解密原数据包,直接响应客户端。
      • 特点:DIP/RIP不一定同网络,RS/DS网络需支持IP隧道。RS需配置VIP绑定到lo网卡。
      • 优点:DS只转发请求,RS直接响应,性能高于NAT。
    4. DR模式 (Direct Routing)
      • 原理:DS改写请求报文的MAC地址将请求转发到RS,RS直接通过网关返回响应给客户端。
      • 特点:DS/RS需同物理网络。RS需配置VIP绑定到lo网卡。
      • 优点:性能最好(不涉及IP隧道加密/解密)。
  • 模式优劣势总结
    • NAT:RS无需VIP,DS作网关,性能一般。
    • FULLNAT:RS无需VIP,网络要求低,丢失客户端IP,性能一般。
    • TUN:性能好,服务器需支持IP隧道,RS需配置VIP。
    • DR:性能好,DS/RS同物理网络,RS需配置VIP。
  • 选择:强网络适应性选FULLNAT,高性能选DR。

LVS+Nginx接入层架构

  • 组合优势
    • LVS性能高,便于Nginx集群化,提高Nginx可扩展性 (LVS作为Nginx的四层负载均衡)。
    • Nginx功能强大,作为业务HTTP服务器的七层负载均衡器,提高业务服务高可用/可扩展性。
  • 单点问题:LVS是单点故障。
  • LVS高可用方案Keepalived + VIP (主从热备)。
    • Keepalived:主节点A和从节点B。主节点通过ARP告知VIP对应的MAC为MAC-A。
    • 故障切换:从节点B监听到主节点A宕机后,代替主节点A回复ARP,告知VIP对应的MAC为MAC-B,流量转向B。
  • LVS性能瓶颈:单台LVS有上限。
  • LVS水平扩展:多台LVS对外提供服务,配置N个VIP,客户端依赖DNS轮询决定访问哪台LVS。
  • 最终完备架构特点
    • DNS轮询扩展LVS性能。
    • Keepalived保证LVS高可用。
    • LVS扩展Nginx性能。
    • Nginx作为七层负载均衡器,提高业务HTTP服务的高可用/可扩展性。

服务发现

  • 定义:为每个服务提供可以自动发现下游服务地址列表的能力。
  • 服务注册中心:管理每个服务的地址列表 (注册) 和将某服务的地址告知调用者 (发现)。
  • 注册与发现流程
    1. 服务实例启动后,将地址信息注册到服务注册中心。
    2. 调用者向服务注册中心查询服务地址。
    3. 服务注册中心返回地址列表。
    4. 调用者向任意实例发起调用。
  • 通信方式:主动查询 或 订阅推送 (服务注册中心主动推送最新地址列表)。
  • 业界组件:Spring Cloud Eureka, CNCF CoreDNS。
  • 可用地址管理
    • 服务实例启动注册,退出注销。
    • 探活能力(关键):
      • 主动探活:服务注册中心周期性探测(效率低,不适合大规模)。
      • 心跳探活 (推荐):服务实例定期发送心跳包,服务注册中心更新最近心跳时间,超时则认为不可用并摘除。
    • 摘除保护策略:若已摘除地址数超阈值(如30%),停止摘除并报警,防止过度摘除导致服务不可用。
  • 地址变更推送
    • 推送风暴问题:大规模推送会占用大量网络带宽。
    • 解决方案
      • 推送增量数据而非全量。
      • 服务注册中心部署大量实例,分摊推送压力。
      • 推拉结合:少量节点推送,其他节点周期性拉取。
  • 服务发现的价值:调用者无需关心被调用者地址,服务可弹性伸缩,真正为微服务带来弹性。

RPC服务 (Remote Procedure Call)

  • 定位
    • HTTP服务:服务于后台外部,与用户请求交互(校验、打包响应),更像业务服务层的“网关”。
    • RPC服务:服务于后台内部,实现核心业务逻辑,强调“微服务”。
  • RPC目标:屏蔽网络编程细节,像调用本地方法一样调用远程方法。
  • RPC通信流程
    1. 序列化:方法输入参数对象转化为二进制数据。
    2. 编码:二进制数据编码为约定协议格式的数据包。
    3. 网络发送
    4. 解码:被调用方将数据包解码。
    5. 反序列化:得到方法名和输入参数。
    6. 执行方法
    7. 结果返回:同样流程返回给调用方。
  • RPC框架:gRPC, Thrift等,可利用协议定义文件生成脚手架代码。
  • RPC与HTTP关系:RPC是一种设计,与HTTP不是对立概念,RPC底层网络通信可使用TCP或HTTP实现。
  • HTTP服务调用RPC服务:HTTP服务通过服务发现获取RPC服务地址,再通过RPC协议进行通信。

存储层技术:MySQL优势

  • 关系型数据库:采用关系模型组织数据,以行和列形式存储数据(二维表),使用SQL操作数据。
    • 主键:唯一标识行记录的属性组。
  • MySQL优势
    • 易用、功能强大(事务、触发器、存储过程),管理工具多。
    • 支持千万级数据记录的大型数据库。
    • GPL开源协议,可自由定制。
    • InnoDB事务性存储引擎符合ACID模型,保证完整可靠存储。
  • 高可用架构1:主从模式
    • 组成:一台Master(处理写请求),若干Slave(从库)。
    • 数据一致性:Master与Slave通过主从复制技术保持。
    • 高可用:Master故障时,Slave提升为Master。
    • 主从复制原理
      1. Master数据变更写入binlog (二进制日志文件)
      2. Slave启动I/O线程与Master建立连接,读取binlog。
      3. I/O线程将日志保存到relay log (中继日志文件)
      4. Slave启动SQL线程从relay log获取日志,本地重新执行SQL回放数据。
    • 异步复制:Master提交事务不等待Slave确认,可能导致数据丢失。
    • 半同步复制 (MySQL 5.5+):Master提交事务前等待至少一个Slave确认接收binlog (写入relay log),减少数据丢失风险,但影响写性能。
    • 复制风暴:过多Slave直接复制Master导致压力倍增,可采用级联复制 (Slave向Slave复制)。
  • 高可用架构2:MHA (Master High Availability)
    • 目标:10-30s内完成MySQL主从集群自动故障检测和切换,最大程度保证数据一致性。
    • 组成
      • MHA Manager (管理节点):决策层,负责故障检测、切换。
      • MHA Node (数据节点):部署在每台MySQL服务器上,修复主从数据差异。
    • 故障转移流程
      1. MHA Manager周期探测Master心跳,失联则认为宕机。
      2. MHA Manager判断哪个Slave的binlog最接近Master。
      3. MHA Node尝试SSH访问Master,若可达则获取binlog,对比Slave数据并补齐差异;若不可达则对比Slave间relay log差异并补齐。
      4. MHA Manager构建新主从关系,备选Slave提升为Master。
    • 优势:与半同步复制结合可大幅降低数据丢失风险。
  • 高可用架构3:MMM (Multi-Master Replication Manager for MySQL)
    • 目标:MySQL双主故障切换和管理。
    • 组成:Master 1 (写请求),Master 2 (备用,与Master 1互复制,一般半同步),若干Slave (异步复制Master 1),mmm-monitor (检测、决策),mmm-agent (节点代理),write vip (对外写IP,绑定其中一个Master),read vip (对外读IP,绑定Slave)。
    • 故障转移流程:agent/monitor检测Master 1宕机 -> monitor要求Master 1移除write vip -> monitor要求Master 2绑定write vip成为Master -> monitor要求Slave向Master 2复制数据。
    • 缺点:较古老,不支持MySQL GTID,社区不活跃,处于无人维护状态。
  • 高可用架构4:MGR (MySQL Group Replication)
    • 版本:MySQL 5.7.17+。
    • 特性
      • 一致性高:基于分布式共识算法Paxos,保证多节点数据一致性。
      • 容错性高:只要不超过一半节点宕机,即可对外服务。
      • 灵活性强:支持单主模式(自动选主)和多主模式(每个节点可处理写请求)。
    • 组成:至少3个MySQL节点组成复制组。事务提交需超过一半节点决议通过。
    • 多主模式:写请求高并发场景易产生事务冲突,导致大量回滚。官方推荐单主模式。
    • 单主模式:MGR自动选Master, Master故障时自动根据权重/ID选主。
    • 优势:强一致性(数据不丢失),高容错性。
    • 缺点:每个写请求涉及与复制组内多数节点通信,写性能不及异步/半同步复制。适合高一致性要求、写请求量不大的场景。

存储层技术:Redis

  • Redis特性
    • 基于内存,性能高。
    • 支持丰富数据类型(String, List, Hash, Set, ZSet)。
    • 支持分布式(主从、哨兵、集群),可无限扩展。
    • 单线程事件驱动,数据操作原子性。
  • 应用场景:缓存系统、计数器、限流、排行榜、社交网络等。
  • 高可用架构1:主从模式
    • 组成:1 Master + 若干 Slave。
    • 复制流程
      1. Slave连接Master,发送PSYNC命令。
      2. Master执行BGSAVE生成RDB快照,并创建缓冲区记录数据变更命令。
      3. Master发送RDB快照给Slave。
      4. Slave加载RDB到内存,接收Master数据变更命令。
      5. Master发送缓冲区中记录的变更命令。
      6. Slave执行命令,保持数据一致。
    • 问题:Master向过多Slave复制数据会导致“复制风暴”。
  • 高可用架构2:哨兵模式 (Sentinel)
    • 目标:Master宕机后自动竞选新Master,实现自动主从切换。
    • 组成:主从模式基础 + 若干Sentinel服务器。
    • Sentinel角色:监控Master/Slave心跳。当超过N个Sentinel节点认为Master宕机,则协商选举Slave为新Master。
    • 客户端访问:先访问Sentinel集群获取Master地址,Master故障时从Sentinel获取新Master地址。
    • 优势:无需人工干预主从切换,客户端自动获取新Master地址。
  • 高可用架构3:集群模式 (Redis Cluster)
    • 目标:分布式存储,解决单个Master内存/QPS限制。
    • 组成:多个Redis节点(Master + 若干 Slave组成节点组,代表一个数据分片)。
    • 要求:至少3个Master,每个Master至少1个Slave。节点间可相互通信。
    • 数据分片:基于哈希槽 (Hash Slot),共16384个槽位,Master瓜分。
      • 计算公式:slot = CRC16(Key) mod 16384
    • 客户端访问流程
      1. 客户端连接任一节点,获取槽位与Master映射关系并缓存。
      2. 读/写数据时,根据Key计算槽位。
      3. 根据槽位在本地缓存定位Master地址,发送请求。
    • Gossip协议:用于集群元信息(节点加入、扩缩容、故障转移)的灵活自动变更,最终一致性协议。
      • 消息类型:meet, ping, pong, fail。
      • 节点故障转移
        • 主观下线:节点A认为节点B下线。
        • 客观下线:集群中超过一半节点认为B主观下线。
        • B客观下线后,其从节点接管槽位,提升为Master。
    • 优势:去中心化架构,槽位管理便捷,可扩展性强,自动故障发现/恢复,Redis官方出品。
    • 缺点:集群节点数量多时(上千个),Gossip协议会造成大量网络通信,形成“Gossip风暴”,严重占用网络带宽。

中心化集群架构 (解决Gossip风暴)

  • 思路:舍弃去中心化,拥抱中心化,使用中间代理维护集群节点元信息。
  • Twemproxy (Twitter开源)
    • 原理:客户端请求 -> Twemproxy -> Redis节点。Twemproxy根据路由规则转发。
    • 优势:客户端透明,减少连接数,Twemproxy集中路由。
    • 不足:无友好管理后台,不支持平滑扩缩容(主要痛点)。
  • Codis (豌豆荚开源)
    • 数据划分:N个槽位(默认1024),slot = CRC32(Key) mod N
    • 核心组件
      • Codis Server:二次开发Redis服务器,支持数据迁移。
      • Codis Proxy:中间代理,接收/转发客户端请求。
      • ZooKeeper集群:保存Redis集群元信息(槽位、节点地址、Proxy地址),提供服务发现。
      • Codis Dashboard/Codis Fe:集群运维管理工具(扩缩容、槽位迁移、Web操作页面)。
    • 架构:每个数据分片定义为Redis Server Group (Master + 若干 Slave)。
    • 客户端访问流程
      1. 客户端从ZooKeeper获取Codis Proxy列表,选择连接。
      2. 客户端向Codis Proxy发送请求。
      3. Codis Proxy根据Key计算槽位,通过ZooKeeper定位负责槽位的Redis Server Group。
      4. Codis Proxy转发请求到Redis节点。
      5. Redis节点处理,结果返回给Codis Proxy。
      6. Codis Proxy返回给客户端。
    • 平滑扩缩容 (槽位迁移):A节点将槽位S关联数据复制到B,期间A继续对外服务。若请求数据D属于S,且正在迁移,则A强制D迁移到B再转发请求到B。
    • 故障宕机:新版本Codis建议每个Redis Server Group引入Sentinel节点处理。
    • 推荐:Redis集群节点较多时(上千),推荐使用Codis类中心化架构。

存储层技术:LSM Tree

  • 特性:对高并发写友好,兼顾查询效率。NoSQL数据库(如BigTable, HBase, Cassandra, TiDB)核心数据结构。
  • 原理:基于“磁盘/内存顺序读/写性能远高于随机读/写性能”结论。
  • 组成部分
    1. MemTable (内存中):保存最新更新数据,按Key字典序有序组织 (红黑树/跳跃表)。
      • 写请求直接在MemTable处理:新增、修改、删除(标记为tombstone)。
      • 预写日志 (WAL):数据修改命令提交MemTable前先追加记录到磁盘WAL文件,保证可靠性。
    2. Immutable MemTable (只读内存):MemTable达到一定大小后转为只读,后台线程将其持久化为SSTable。
    3. SSTable (Sorted String Table, 磁盘文件):持久化的、有序且不可变的键值对存储结构。
      • Key-Value连续存储,文件尾部存储稀疏索引(提高查找速度)。
      • 合并操作 (Compaction):周期性对SSTable进行合并,清除冗余记录。
        • 使用Leveled Compaction Strategy (LCS):SSTable分Level层级,Level N文件合并下沉到Level N+1。
        • LCS保证:所有Level SSTable大小一致(如160MB),每个Level限制文件总大小,单个/同Level内SSTable之间数据有序且无Key重叠。
  • 读/写数据流程
    • 写流程:WAL -> MemTable -> (满) Immutable MemTable -> SSTable (Level 0) -> (满) 合并下沉到Level 1 -> ... -> Level N+1。
    • 读流程:按数据新旧程度,MemTable -> Immutable MemTable -> Level 0 SSTable (最新) -> Level 1 SSTable -> ... -> Level N SSTable。

存储层技术:NoSQL数据库

  1. 文档数据库 (MongoDB, CouchDB)
    • 特点:采用JSON格式存储数据,解决关系型数据库Schema扩展不便问题。
    • 适用场景:数据量大/增长快,字段定义不明确/变化快(如商品参数)。
    • 不适用场景:需事务(无法保证多文档原子性),需复杂查询(如join)。
  2. 列式数据库 (BigTable, HBase)
    • 特点:按列存储数据,而非行式。
    • 优势:统计查询效率高(只读取关注列),存储空间利用率高(字典表压缩)。
    • 适用场景:海量数据插入、极少修改(如用户行为收集),数据分析(离线统计)。
    • 不适用场景:高频删除/修改,不适合在线用户,需事务。
  3. 全文搜索数据库 (Elasticsearch)
    • 问题:关系型数据库模糊查询效率低(LIKE语句全量扫描)。
    • 原理:建立单词到文档的索引关系作为“倒排索引”。
    • 优势:高效关键词搜索,海量数据复杂查询,数据统计/聚合。
    • 不适用场景:高频更新数据(实际是删除旧数据+创建新数据),需事务。
  4. 图数据库 (Neo4j, Titan)
    • 特点:以“图”这种数据结构存储数据(节点-实体,关系-节点间关联)。
    • 优势:直观数据模型,易查询节点间关系,解决关系型数据库不擅长处理实体关系问题。
    • 适用场景:强调关系、需复杂关系查询/分析的业务(如社交网络、知识图谱)。
  5. NewSQL数据库 (Google Spanner, TiDB, CockroachDB)
    • 定位:结合关系型数据库和NoSQL两者优点。
    • 底层:使用分布式键值存储系统(LSM Tree模型)。
    • 革新:放弃NoSQL主从复制,以更小粒度数据分片作为高可用单位,通过Paxos/Raft等分布式共识算法复制数据,采用分布式事务。
    • 优势:保留NoSQL可扩展性,提供关系型数据库事务能力。
    • 现状:数据库领域后起之秀,但仍是小众产品,需更多考验。

消息中间件技术

  • 定义:生产者创建消息投递到队列,消费者从队列读取消息,完成通信。
  • 通信模式优点
    • 生产者单方面完成消息通信,无需等待消费者。
    • 消费者根据自身能力拉取新消息,灵活。
  • 核心用途
    1. 异步化:将非核心业务逻辑异步处理,大幅降低用户请求响应时间。
    2. 流量削峰:消费者根据自身处理能力灵活读取消息,平滑高并发流量,提高服务稳定性。
    3. 解耦:服务间通过消息队列通信,消除直接依赖,利于职责分离,减少事故。

Kafka

  • 定义:分布式、高性能、高可扩展性的消息队列系统,主要用于日志收集和消息中间件。
  • 整体架构组件
    1. Producer (生产者):生产消息。
    2. Consumer (消费者):消费消息。
    3. Topic (主题):消息类型。
    4. Partition (分区):Topic消息分布式存储在多个Partition中,实现负载均衡。每个Partition消息有序,不同Partition间消息无序。由Broker管理。
    5. Broker:Kafka核心,接收/存储消息到Partition,处理消费者消费逻辑。多个Broker组成Kafka集群。
    6. Consumer Group (消费者组):多个消费者实例组成,一个Topic对应一个或多个Consumer Group。
      • 规定:一个Partition消息只能被Consumer Group中一个消费者实例消费。
    7. ZooKeeper (Kafka 0.9+):负责Kafka集群元信息管理。
      • Broker注册、Topic元信息管理 (Partition与Broker关联)。
      • 生产者负载均衡 (消息写入Partition)。
      • 消费者负载均衡 (记录“哪个消费者实例消费哪个Partition”,宕机后Rebalance)。
      • 消费进度Offset记录 (Kafka 0.9+版本已改为Broker本地磁盘保存,提升写性能)。
  • 生产者发送消息流程
    • 指定Partition则直接使用。
    • 未指定但有Key则对Key哈希选Partition。
    • 既未指定Partition也未指定Key则轮询选择Partition。
    • 发送到选定的Partition对应Broker,Broker顺序写入磁盘。
  • 消费者消费消息
    • 以Consumer Group方式工作。
    • 一个Consumer Group可消费多个Topic,一个Topic也可被多个Consumer Group消费。
    • 拉取(pull)模式:消费者主动控制消费速度,实现削峰。

Kafka的高可用

  • Partition多副本:每个Partition有1个Leader和若干Follower。
    • Leader处理生产者写入和消费者读取。
    • Follower周期性向Leader请求消息复制,作为Leader数据备份。
    • 副本存储在不同Broker上,防止Broker宕机导致Partition不可用。
  • ISR (In-Sync Replica) 机制:Leader维护与自己数据一致的Follower列表。
    • Follower长时间未复制或数据落后过多,则从ISR移除。
    • 只有ISR中所有Follower都确认收到消息,Leader才认为消息写入成功。
    • 特点:同步复制和异步复制的折中,避免Follower宕机对性能/可用性影响,保证多副本数据一致性。
  • 故障恢复
    • Controller角色:Kafka集群中选举一个Controller(借助ZooKeeper分布式锁),负责Partition Leader选举和副本重分配。
    • 故障恢复流程
      1. Broker故障,与ZooKeeper断连。
      2. ZooKeeper通知Controller。
      3. Controller查询受影响的Partition (Leader由故障Broker负责)。
      4. Controller从每个Partition Leader ISR中选择一个Follower提升为Leader。
      5. Controller通知相关Broker。
      6. 被选举的Follower变为Leader,其他Follower转而向新Leader复制数据。

多机房:主备机房

  • 问题:单机房是单点故障(人为破坏、自然灾害、断电、火灾等)。
  • 方案:在主机房所在城市建设一个备机房,完全复制主机房架构。
    • 正常情况:仅主机房工作。
    • 存储层:备机房数据库作为主机房从库,通过专线进行数据复制。
  • 故障切换:主机房故障时,备机房:
    • 存储层从库提升为主库。
    • 修改DNS解析地址指向备机房。
  • “同城灾备”特点
    • 优点:架构搭建简单。
    • 缺点
      • 资源浪费:备机房大部分时间空闲。
      • 可用性存疑:备机房无实战经验,关键时刻可能掉链子。

多机房:同城双活

  • 动机:解决主备机房资源浪费和可用性存疑问题。
  • 改造:将两个机房的接入层IP地址都配置到DNS,实现“双活”,两个机房都能处理部分用户请求。
  • 存储层改造
    • 一个机房作为主库机房(如A机房)。
    • 另一个机房(如B机房)的所有写数据请求跨机房访问A机房对应的主库
    • 读数据请求依赖各存储系统自带的主从复制功能,在本地处理。
    • 优点:写请求延迟增大但可接受(同城距离近,专线延迟5ms左右),写请求占比较低。可将“同城双活”视为单机房使用。
  • 灵活实施
    • “同城”不局限行政区域:强调物理距离近,以缓解跨机房访问延迟,同时避免物理距离过近导致单点失效。
    • “同城双活”可扩展为“同城多活”:可部署更多机房,但存储层需选出唯一主库机房。
  • 分流与故障切流
    • 分流策略:根据用户ID/DeviceID哈希映射到不同机房。推荐DeviceID(未登录用户)。
    • 分流环节
      • DNS分流 (粗糙):解析结果不确定,同一用户可能路由到不同机房,策略变更生效慢。
      • 客户端分流 (推荐)
        • 分流配置平台:部署在各机房,工程师配置域名分流比例 (如sharding, idc包含lower/upper范围和domain专用域名)。
        • 客户端流程:发起请求时若有分流配置,则DeviceID哈希取模,根据范围选择专用域名发送请求。
        • 准实时生效:Nginx响应Header带最新分流配置版本号,客户端若发现本地版本旧,则主动拉取最新配置。
        • 客户端主动容灾:连续N次访问A机房失败 -> 猜测A不可用 -> 尝试拉取A机房配置 (若失败) -> 转而向B机房拉取配置 -> 应用最新配置切流到B机房。
      • HTTP DNS或其他接入层组件:也可支持分流。
    • 切流操作:若故障机房是主库,需将备机房存储层数据库提升为主库。
  • 两地三中心
    • 在“同城双活”基础上增加一个异地备机房(距离较远)。
    • 备机房只做数据备份,不对外提供服务。
    • 笔者看法:投入产出比低,多数场景下“同城双活”足够。

多机房:异地多活

  • 适用场景:服务于全球用户的世界级应用(如Facebook, Instagram)。
  • “同城双活”对全球应用的问题
    • 用户访问延迟:跨国访问物理距离远,延迟高。
    • 数据合规问题:各国要求本国用户数据独立存储。
    • 灾难问题:部署国战争、暴乱、自然灾害可能导致全球应用不可用。
  • “异地多活”架构要点
    1. 每个机房都在本机房内处理写数据请求:由于异地机房间网络延迟巨大,无法跨机房写主库。每个机房独立部署各存储层主库,存储层间无主从关系。
    2. 数据互通:每个机房将本机房写入的数据复制到其他机房,实现全球数据可见。
      • 通过DRC (Data Replicate Center) 工具实现存储系统间的双向数据复制 (主主复制)
      • 业界项目:阿里巴巴 (Otter, RedisShake, MongoShake), 携程 (XPipe)。

MySQL DRC的原理

  • DRC工具结构
    • Sync-out:伪从,模拟MySQL从库,从本地主库获取binlog数据变更记录,实时传输到远端Sync-in。
    • Sync-in:扮演数据库客户端,收到远端数据后还原SQL语句并在本机房主库执行。
  • 断点续传与数据防重
    • 使用GTID (Global Transaction Identifier):MySQL对每个已提交事务的全局唯一编号。
    • Sync-out记录最新传输成功的GTID,故障恢复后从GTID位置继续传输。
    • Sync-in保存已写入数据GTID集合,收到数据前检查是否已存在,实现数据防重。
  • 防止数据回环
    • 在主库创建辅助表,记录来自其他机房的数据变更事务。
    • Sync-in写入数据时,同时在辅助表插入记录。
    • Sync-out解析binlog,若发现事务有写辅助表,则说明来自其他机房,不传输此数据。
  • 数据冲突
    • 难以解决:在不同机房几乎同时修改同一数据。
    • LWW (Last Write Wins) 策略:最后写入者胜利(基于修改时间戳),但不同机房时间戳可能不一致,不准确。
    • 避免冲突
      • 业务逻辑不依赖数据库自增主键,采用分布式唯一ID。
      • 机房分流尽量保证不同用户被分流到不同机房,避免同一用户数据在多机房同时修改。
  • 总结:MySQL DRC技术核心要点包括伪从、断点续传、数据防重、防止数据回环和数据冲突。

Redis DRC的原理

  • 伪从:Sync-out模拟Redis从库,向Redis主库复制写命令,暂存到本地。
  • 断点续传和数据防重
    • Redis无GTID,需自定义递增唯一ID绑定到每个写命令。
    • Sync-out保存已传输写命令ID,恢复后继续传输。
    • Sync-in保存最近成功写入的写命令ID,若收到ID小于等于此ID则丢弃。
  • 防止数据回环
    • 思路1 (不推荐):改造Redis写命令格式携带机房信息(维护成本高)。
    • 思路2 (推荐):Redis主库识别客户端角色。增加REDIS_SYNC_IN标志,若写命令来自Sync-in,则不复制给Sync-out。
  • 数据冲突
    • 比MySQL更复杂,Redis命令丰富,难实现统一防冲突数据结构。
    • 同样建议尽量避免数据冲突,通过用户分区等方式。

分流策略

  • 全球应用分流要求:必须考虑用户地理位置。
  • DNS地域解析:为不同国家用户配置不同机房接入层IP,多数用户可直达目标机房。
  • DNS分流缺点:用户网络环境(VPN, 非本国SIM卡, 出国旅行)可能干扰解析结果。
  • 固定用户所在国方案 (推荐)用户注册国策略
    • 新用户注册时客户端携带国家信息作为注册国,后台保存。
    • 用户登录时,根据注册国映射到预配置的机房,即使出国/使用VPN也固定访问此机房。
    • 优化:监控用户访问请求国家维度,若连续较长时间与注册国不同,可修改注册国,提升体验。

数据复制链路

  • 全网状结构:每个机房都与所有其他机房建立双向数据复制链路。
    • 链路数:C(N,2) * 2。N个机房时链路数激增(如6个机房15条链路),维护成本高。
  • 星状结构 (推荐):约定一个机房为中心机房
    • 其他机房主库数据仅复制到中心机房。
    • 中心机房再将数据复制到所有其他机房。
    • 优势:显著降低链路数(N-1 * 2),降低架构复杂度。