本文收录于「bksczm」的系列专栏LinuxC/CMySQL面试题Redis一、什么是 Redis1.1 Redis 的定位RedisRemote Dictionary Server是一个基于内存的、开源的高性能 key-value 型 NoSQL 数据库常被用作缓存、消息队列、分布式锁等。传统关系数据库如 MySQL的数据主要存储在硬盘上读写都涉及磁盘 IO效率受硬件限制Redis 把数据主要放在内存中进行操作因此读写速度极快单机可达十万级 QPS。注意Redis 并非完全不碰磁盘它支持RDB 快照和AOF 日志两种持久化机制把内存数据定期/实时写入磁盘防止宕机丢数据。1.2 Redis 与语言级变量的区别两者确实都在内存中操作数据关键区别在于能否跨进程、跨主机共享对比维度语言级变量Redis本质进程地址空间内的内存独立的服务进程访问方式直接内存寻址函数/变量访问基于TCP/Unix socket 通信单主机单进程内效率极高无网络开销较低有序列化和网络开销跨进程共享需要自己做 IPC共享内存、管道等天然支持多个客户端连同一个 Redis跨主机共享不支持需自己写 socket 协议天然支持网络服务生命周期随进程退出而消失独立进程可持久化结论单主机、单进程内用本地变量比 Redis 高效得多但在多进程、多主机环境下要让多个服务共享同一份内存数据Redis 把网络通信 数据管理 并发控制都封装好了远比自己实现 IPC/socket 共享内存优秀。1.3 Redis 与 MySQL 配合缓存架构内存容量远小于外存不可能把所有数据都放 Redis因此实际采用MySQL Redis 结合的方案MySQL作为持久化的主数据库存储全量数据Redis作为缓存存储热数据高频访问的数据。这背后是二八原理约 20% 的热点数据能满足 80% 的访问请求。典型读取流程Cache Aside 模式请求 → 先查 Redis ├─ 命中直接返回内存极快 └─ 未命中查 MySQL → 把结果写入 Redis → 返回1.4 Redis 的核心特性基于内存读写性能极高单线程命令处理模型6.0 之前网络 IO 与命令执行都是单线程基于 epoll 的 IO 多路复用6.0 之后网络 IO 引入多线程但命令执行仍为单线程天然避免了锁竞争丰富的数据类型String、List、Hash、Set、ZSet有序集合、Bitmap、HyperLogLog、Geo、Stream支持持久化RDB快照和 AOF追加日志支持高可用与分布式主从复制、哨兵Sentinel、Redis Cluster 分片集群典型用途缓存、排行榜ZSet、计数器、分布式锁、消息队列Stream/Pub-Sub、限流。二、为什么需要分布式架构演进2.1 单机架构及其瓶颈最初只有一台主机同时承担 服务应用 存储数据库全部功能。单机的硬件资源都有上限资源瓶颈CPU核数有限并行处理能力有上限内存内存条数量和容量有上限外存磁盘容量和 IO 有上限网络半连接队列、文件描述符、带宽都有上限单机一旦达到任何一个资源上限性能就会触顶且无法通过简单升级硬件无限扩展垂直扩展成本指数级增长。2.2 垂直拆分应用与存储分离第一步演进把应用和存储拆到两台主机。应用服务器执行业务逻辑特化CPU 和内存对外存要求不高存储服务器负责数据存储特化外存容量和 IO 性能追求性能用 SSD。这种按职责拆分称为垂直拆分好处是两类服务器可以按需配置、独立扩展。2.3 应用集群 负载均衡应用与存储分离后如果访问量继续增大单台应用服务器仍然扛不住所有请求。于是部署多台应用服务器组成应用集群并在前面增加 负载均衡器网关分发请求。负载均衡器的分层由外到内DNS / GSLB全局负载均衡按地域、机房分流四层负载均衡LVS工作在传输层按 IP端口转发性能极高七层负载均衡Nginx工作在应用层可按 URL、Header 等做更精细的路由。网关本身只做请求转发/分配不做重业务单次处理耗时很短。但极高并发下网关自身也可能成为瓶颈。2.4 多机房 / 异地多活当单个机房的网关和集群也扛不住时或为了容灾、就近接入部署多个机房多套完整集群通过DNS 解析 / GSLB把用户请求分配到最近或最空闲的机房。异地多活多个机房都能独立提供完整服务同城双活/异地灾备侧重高可用和容灾。2.5 读写分离主从复制负载均衡解决了应用层压力但存储服务器的读压力依然巨大。实际业务中读远多于写于是采用一主多从的读写分离主服务器Master数量较少负责写操作从服务器Slave/Replica数量较多负责读操作主节点通过binlog 复制把数据变更同步到从节点。关键点读写分离中每个从节点都保存一份完整的数据副本所以它并没有增大系统能存储的总数据量只是提升了读性能和可用性。主从复制存在延迟可能带来短暂的数据不一致。2.6 分库分表读写分离解决的是性能/并发问题解决不了单表/单库数据量太大的容量问题。分库分表用于水平扩展存储容量和吞吐。读写分离的每个从库都存一份完整数据只提升并发、不增加总容量。当单库 / 单表数据量大到单机装不下时就需要分库分表。切分有两个方向垂直是竖着切切业务、切字段水平是横着切切数据行。一、垂直分库按业务把一个大库里的不同表拆到不同数据库。比如原来一个库塞了用户、订单、商品所有表拆成用户库、订单库、商品库各自独立部署扩容。解决的是业务耦合和单库压力问题。二、垂直分表把一张字段太多的宽表按冷热拆成几张窄表。比如员工表中姓名、工号这种常查的短字段留在主表简历、合同这种少看又占地方的大字段拆到副表用 id 关联。切的是列让常用数据更紧凑。三、水平分库把同一张表的数据行按规则摊到多个结构完全相同的库里每个库表结构一样、只是存的数据范围不同。比如user_id % 3把用户分散到 3 个库容量和性能成倍扩展。四、水平分表分片 Sharding一张大表数据行太多如几十亿订单按规则切成多张结构相同的小表order_0、order_1……规则常用取模或按时间范围。分表还在同一个库里主要解决单表过大把分表分布到多台机器才是真正的分片彻底扩展容量。五、怎么记垂直切的是业务和字段列水平切的是数据行分库是搬到不同数据库分表是把一张表拆成多张表。分库分表带来的新问题分布式事务一个操作跨多个库/表需要分布式事务2PC、TCC、Saga、最终一致性跨库 JOIN / 聚合无法直接 JOIN需要应用层组装或冗余字段全局唯一 ID自增主键在分片后会冲突需要雪花算法Snowflake、号段模式等跨分片分页、排序需要各分片返回后归并扩容与数据迁移增加分片节点时需要重新分布数据一致性哈希可减少迁移量。2.7 引入 Redis 缓存在应用层与数据库之间引入独立部署的 Redis 缓存集群存放热数据进一步降低数据库读压力。引入缓存后带来缓存一致性和经典的三大缓存问题问题描述常见解决方案缓存穿透查询根本不存在的数据请求全部打到数据库缓存空值、布隆过滤器缓存击穿某个热点 key 过期瞬间大量并发请求打到数据库互斥锁只放一个请求去查库、热点 key 逻辑不过期缓存雪崩大量 key 同时过期或 Redis 宕机过期时间加随机值、Redis 集群高可用、限流降级缓存与数据库一致性常用Cache Aside Pattern读时先读缓存、未命中读库并回填更新时先更新数据库再删除缓存。2.8 微服务架构前面的应用集群中每台应用服务器都运行全部业务单体应用。随着业务增长单体应用代码膨胀、迭代困难、相互影响。微服务把完整业务按领域拆分成多个独立服务用户服务、订单服务、商品服务……每个服务独立开发、独立部署、独立扩容通常拥有自己独立的数据库服务之间通过轻量级协议HTTP/REST、gRPC、消息队列通信。代价服务拆分后原本的进程内函数调用变成了跨进程/跨网络调用通信开销增大、延迟上升还引入了分布式事务、服务治理等复杂度。微服务需要配套的服务治理体系服务注册与发现Nacos、Consul、配置中心、网关、熔断限流Sentinel、Hystrix、链路追踪SkyWalking、Zipkin等。三、核心名词辨析3.1 系统 / 应用为了完成一整套服务的一个程序或者一组相互配合的程序群。3.2 模块 / 组件当应用较复杂时为分离职责把其中具有清晰职责、内聚性强的部分抽象成独立概念便于理解和复用。3.3 分布式 vs 集群概念核心含义关注点通俗比喻集群Cluster多台服务器部署同一个业务每台都能独立完成完整任务组成一个整体对外服务高可用、负载均衡多个人干同一件事餐厅有 3 个厨师每个都会做全部菜来客后分配给不同厨师分布式Distributed一个完整业务被拆成多个子模块分别部署在不同服务器上分工协作共同完成整体业务职责拆分、横向扩展多个人分工干不同的事餐厅分配菜员、主厨、传菜员各司其职协作出餐关键区别集群是复制每个节点功能相同挂一个其他节点仍能完整服务高可用分布式是拆分每个节点只负责一部分功能节点之间相互依赖、协同工作两者不是包含关系而是不同维度实际架构中常常组合使用例如一个分布式系统用户服务、订单服务、商品服务中每个服务自身又部署成一个集群用户服务跑 3 个相同实例。分布式按业务拆成不同服务 集群同一服务部署多个相同实例 ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │用户服务 │ │订单服务 │ │商品服务 │ │用户服务×3集群│ └────────┘ └────────┘ └────────┘ └────────┘ 干不同的事分布式 干同一件事集群四、分布式系统的核心挑战架构从单体走向分布式在获得扩展性和高可用的同时也引入了单体系统没有的难题挑战说明数据一致性网络延迟、节点故障导致多副本/多节点数据短暂不一致CAP 理论一致性 C、可用性 A、分区容错性 P 不可兼得分布式事务跨节点操作的原子性保障2PC、TCC、Saga、本地消息表 最终一致性 / BASE 理论网络不可靠网络延迟、丢包、乱序、分区随时可能发生不能假设调用一定成功服务治理注册发现、配置管理、熔断降级、限流、负载均衡、链路追踪高可用与故障转移主从切换、哨兵选举、脑裂问题全局唯一 ID、分布式锁单机自增 ID 和本地锁失效需要跨节点方案运维复杂度节点数量爆炸需要容器化Docker、编排K8s、监控告警体系五、核心总结RedisRedis 是基于内存的 key-value NoSQL通过socket 对外提供服务优势在于跨进程、跨主机共享数据单进程内本地变量更快但多机共享 Redis 更优秀。Redis 支持RDB/AOF 持久化不是纯内存命令执行单线程6.0 后网络 IO 多线程。MySQL Redis配合用二八原理缓存热数据注意缓存穿透、击穿、雪崩和一致性问题。架构演进脉络单机服务存储一体资源有上限→垂直拆分应用与存储分离按需特化硬件→应用集群 负载均衡解决应用层并发→多机房异地多活解决机房级瓶颈和容灾→读写分离一主多从提升读性能不增加容量→分库分表水平扩展容量→微服务按业务拆分独立迭代。存储服务器同样需要大内存Buffer Pool最看重外存容量和 IO。分库分表四种方式垂直分库、垂直分表、水平分库、水平分片会带来分布式事务、跨库 JOIN、全局 ID、扩容迁移等问题。概念辨析集群 多台干同一件事复制求高可用/负载均衡分布式 多台分工干不同的事拆分求扩展/解耦两者是不同维度不是包含关系实际中常组合使用。微服务以网络通信开销和服务治理复杂度为代价换取独立部署和快速迭代。分布式的核心代价是CAP 权衡、数据一致性、网络不可靠和分布式事务。