剑子灵 發表於 2025-9-23 09:46:19

Redis 配置与优化完全指南

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">前言</a></li><li><a href="#_label1">1. 关系型数据库 vs 非关系型数据库</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_0">关系型数据库(SQL)</a></li><li><a href="#_lab2_1_1">非关系型数据库(NoSQL)</a></li></ul><li><a href="#_label2">2. Redis 简介</a></li><ul class="second_class_ul"></ul><li><a href="#_label3">3. Redis 安装与部署</a></li><ul class="second_class_ul"></ul><li><a href="#_label4">4. Redis 常用命令</a></li><ul class="second_class_ul"></ul><li><a href="#_label5">5. Redis 高可用</a></li><ul class="second_class_ul"></ul><li><a href="#_label6">6. 持久化机制</a></li><ul class="second_class_ul"><li><a href="#_lab2_6_2">6.1 RDB 持久化</a></li><ul class="third_class_ul"><li><a href="#_label3_6_2_0">① 原理</a></li><li><a href="#_label3_6_2_1">② 触发条件</a></li><li><a href="#_label3_6_2_2">③ 执行流程</a></li><li><a href="#_label3_6_2_3">④ 启动加载</a></li><li><a href="#_label3_6_2_4">⑤ 优缺点</a></li></ul><li><a href="#_lab2_6_3">6.2 AOF 持久化</a></li><ul class="third_class_ul"><li><a href="#_label3_6_3_5">① 原理</a></li><li><a href="#_label3_6_3_6">② 开启 AOF</a></li><li><a href="#_label3_6_3_7">③ 执行流程</a></li><li><a href="#_label3_6_3_8">④ 启动加载</a></li><li><a href="#_label3_6_3_9">⑤ 优缺点</a></li></ul><li><a href="#_lab2_6_4">6.3 对比总结</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label7">7. 性能管理与优化</a></li><ul class="second_class_ul"><li><a href="#_lab2_7_5">内存指标与碎片率</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_7_6">优化建议</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_7_7">内存淘汰策略</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label8">8. 常见缓存问题与解决方案</a></li><ul class="second_class_ul"><li><a href="#_lab2_8_8">8.1 缓存穿透</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_8_9">8.2 缓存击穿</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_8_10">8.3 缓存雪崩</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_8_11">8.4 综合实践建议</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label9">结语</a></li><ul class="second_class_ul"></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>前言</h2>
<p>Redis 是目前使用最广泛的高性能内存数据库之一。本文从基础概念到安装部署、常用命令、高可用、持久化机制,再到性能优化,一文带你全面掌握 Redis。</p>
<p class="maodian"><a name="_label1"></a></p><h2>1. 关系型数据库 vs 非关系型数据库</h2>
<p class="maodian"><a name="_lab2_1_0"></a></p><h3>关系型数据库(SQL)</h3>
<ul><li><strong>特点</strong>:表格模型(行+列)、使用 SQL 语言、强事务 ACID、纵向扩展(升级硬件)。</li><li><strong>常见产品</strong>:MySQL、Oracle、PostgreSQL。</li><li><strong>场景示例</strong>:银行转账,必须保证两边同时成功,事务性要求强。</li></ul>
<p class="maodian"><a name="_lab2_1_1"></a></p><h3>非关系型数据库(NoSQL)</h3>
<ul><li><strong>特点</strong>:键值对/文档/图结构存储、无需固定表结构、高并发、高可扩展、横向扩展(增加节点)。</li><li><strong>常见产品</strong>:Redis、MongoDB、HBase、Memcached。</li><li><strong>场景示例</strong>:微信聊天,一条消息可能是文字、图片、语音,不适合表格存储,更适合用文档型数据库。</li></ul>
<p class="maodian"><a name="_label2"></a></p><h2>2. Redis 简介</h2>
<ul><li><strong>定义</strong>:开源、C 语言编写、基于内存、支持持久化的键值数据库。</li><li><strong>优势</strong>:<ul><li>高性能:读取可达 11 万次/s,写入 8 万次/s。</li><li>支持多种数据结构:String、List、Hash、Set、Sorted Set。</li><li>支持持久化:RDB、AOF。</li><li>主从复制,方便数据备份。</li></ul></li><li><strong>为什么快?</strong><ul><li>纯内存操作,避免磁盘 IO。</li><li>单线程,避免锁开销。</li><li>I/O 多路复用,高并发。</li></ul></li></ul>
<p><strong>应用示例</strong>:</p>
<ul><li>秒杀库存扣减、订单写入放在 Redis,减轻数据库压力。</li><li>抖音热搜榜:用 Sorted Set 存储关键词和热度,实时排序。</li></ul>
<p class="maodian"><a name="_label3"></a></p><h2>3. Redis 安装与部署</h2>
<ul><li>停防火墙、关闭 SELinux。</li><li>安装依赖:<code>yum install -y gcc gcc-c++ make</code>。</li><li>下载并解压 Redis 源码,执行 <code>make &amp;&amp; make PREFIX=/usr/local/redis install</code>。</li><li>使用 <code>cd utils/install_server.sh</code> 配置服务,按提示输入路径。</li><li>建立软链接 <code>ln -s /usr/local/redis/bin/* /usr/local/bin/</code> 方便全局使用。</li><li>常用控制命令:</li></ul>
<div class="jb51code"><pre class="brush:bash;">/etc/init.d/redis_6379 start|stop|restart|status</pre></div>
<ul><li>修改 <code>/etc/redis/6379.conf</code>:
<ul><li><code>bind 127.0.0.1 192.168.x.x</code>:监听地址。</li><li><code>port 6379</code>:默认端口。</li><li><code>daemonize yes</code>:守护进程。</li><li><code>logfile /var/log/redis_6379.log</code>:日志文件。</li></ul></li></ul>
<p class="maodian"><a name="_label4"></a></p><h2>4. Redis 常用命令</h2>
<ul><li><strong>客户端工具</strong>:</li><li><code>redis-cli -h host -p port -a password</code></li><li><strong>压力测试</strong>:</li><li><code>redis-benchmark -c 100 -n 100000</code></li><li><strong>数据操作</strong>:</li></ul>
<div class="jb51code"><pre class="brush:bash;">set key value
get key
exists key
del key
keys pattern
rename oldkey newkey</pre></div>
<ul><li><strong>多数据库</strong>:</li><li>默认 0~15 共 16 个库。</li><li><code>select n</code> 切换库,<code>move key n</code> 移动数据。</li><li><code>flushdb</code> 清空当前库,<code>flushall</code> 清空所有库(慎用)。</li></ul>
<p class="maodian"><a name="_label5"></a></p><h2>5. Redis 高可用</h2>
<ul><li><strong>持久化</strong>:RDB/AOF 将内存数据保存到磁盘,防止进程退出后丢失。</li><li><strong>主从复制</strong>:一主多从,主写从读,实现负载均衡。</li><li><strong>哨兵(Sentinel)</strong>:主机宕机自动切换到从机。</li><li><strong>集群(Cluster)</strong>:多节点分片存储,解决单机容量限制和写入瓶颈。</li></ul>
<p class="maodian"><a name="_label6"></a></p><h2>6. 持久化机制</h2>
<p class="maodian"><a name="_lab2_6_2"></a></p><h3>6.1 RDB 持久化</h3>
<p class="maodian"><a name="_label3_6_2_0"></a></p><p class="maodian"><a name="_label3_6_3_5"></a></p><h4>① 原理</h4>
<p>RDB 是将 Redis <strong>某一时刻的内存数据</strong>快照(Snapshot)保存到磁盘的二进制文件 <code>dump.rdb</code> 中。 Redis 通过 <code>fork</code> 一个子进程把内存数据写入临时 RDB 文件,完成后再替换旧文件。</p>
<p class="maodian"><a name="_label3_6_2_1"></a></p><h4>② 触发条件</h4>
<ul><li><strong>手动触发</strong>:
<ul><li><code>save</code>:阻塞主进程直到完成,不推荐在线上使用。</li><li><code>bgsave</code>:<code>fork</code> 子进程执行保存,主进程继续处理请求(推荐)。</li></ul></li><li><strong>自动触发</strong>: 在 <code>redis.conf</code> 里通过 <code>save m n</code> 配置:</li></ul>
<div class="jb51code"><pre class="brush:plain;">save 900 1
save 300 10
save 60 10000</pre></div>
<ul><li>其他触发:<ul><li>从节点全量复制时,主节点会自动执行 <code>bgsave</code>。</li><li>执行 <code>shutdown</code> 时如果没开启 AOF,会自动做一次 RDB。</li></ul></li></ul>
<p class="maodian"><a name="_label3_6_2_2"></a></p><p class="maodian"><a name="_label3_6_3_7"></a></p><h4>③ 执行流程</h4>
<ul><li>主进程检查是否已有持久化子进程在运行,若有则直接返回。</li><li><code>fork</code> 子进程(此过程主进程短暂阻塞)。</li><li>子进程把内存数据写入临时 RDB 文件。</li><li>写完后原子替换旧文件,发送完成信号给主进程。</li><li>主进程更新状态。</li></ul>
<p class="maodian"><a name="_label3_6_2_3"></a></p><p class="maodian"><a name="_label3_6_3_8"></a></p><h4>④ 启动加载</h4>
<p>Redis 启动时若开启 AOF 优先加载 AOF,否则加载 RDB 文件。载入期间 Redis 会阻塞直至完成。</p>
<p class="maodian"><a name="_label3_6_2_4"></a></p><p class="maodian"><a name="_label3_6_3_9"></a></p><h4>⑤ 优缺点</h4>
<ul><li><strong>优点</strong>:文件紧凑、体积小、适合全量备份和传输;恢复速度快;对性能影响小。</li><li><strong>缺点</strong>:无法做到实时持久化,可能丢失几分钟数据;<code>fork</code> 阻塞和磁盘 IO 压力。</li></ul>
<p class="maodian"><a name="_lab2_6_3"></a></p><h3>6.2 AOF 持久化</h3>
<h4>① 原理</h4>
<p>AOF(Append Only File)是把 Redis <strong>执行过的写/删除命令</strong>按 Redis 协议格式追加到日志文件中。重启时 Redis 重新执行 AOF 文件中的命令恢复数据。查询类命令不会写入 AOF。</p>
<p class="maodian"><a name="_label3_6_3_6"></a></p><h4>② 开启 AOF</h4>
<p>默认关闭,需要在 <code>redis.conf</code> 开启:</p>
<div class="jb51code"><pre class="brush:plain;">appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec</pre></div>
<h4>③ 执行流程</h4>
<ul><li><strong>命令追加 (append)</strong>:Redis 先将命令追加到 AOF 缓冲区 <code>aof_buf</code>。</li><li><strong>文件写入/同步 (write &amp; fsync)</strong>:<ul><li><code>appendfsync always</code>:每条命令都 fsync,同步最安全但最慢。</li><li><code>appendfsync no</code>:仅 write,由 OS 决定何时刷盘,不安全但最快。</li><li><code>appendfsync everysec</code>:每秒 fsync 一次(默认,性能与安全折中)。</li></ul></li><li><strong>文件重写 (rewrite)</strong>:<ul><li>AOF 文件越来越大时 Redis 通过 <code>BGREWRITEAOF</code> 重写文件。</li><li>重写并不是读取旧 AOF,而是把当前内存状态重新生成最少命令集写入新文件。</li><li>过期数据、无效命令不写入;多条命令可合并成一条,大幅压缩文件。</li></ul></li><li>触发:<ul><li>手动:<code>bgrewriteaof</code>。</li><li>自动:满足 <code>auto-aof-rewrite-min-size</code> 和 <code>auto-aof-rewrite-percentage</code>。</li><li><strong>重写期间缓冲</strong>:Redis 把新写命令同时追加到旧缓冲区和 <code>aof_rewrite_buf</code>,确保新文件与当前状态一致。</li></ul></li></ul>
<h4>④ 启动加载</h4>
<p>Redis 启动时若 AOF 开启则优先加载 AOF;AOF 文件不存在时才加载 RDB。 若 AOF 文件尾部不完整(如宕机),且 <code>aof-load-truncated yes</code>,则忽略尾部继续启动。</p>
<h4>⑤ 优缺点</h4>
<ul><li><strong>优点</strong>:实时性更好(秒级持久化)、可读性强、兼容性好。</li><li><strong>缺点</strong>:文件大、恢复速度慢、写磁盘频率高对性能影响更大,重写过程也有 fork 阻塞与 IO 压力。</li></ul>
<p class="maodian"><a name="_lab2_6_4"></a></p><h3>6.3 对比总结</h3>
<table><thead><tr><th>特性</th><th>RDB</th><th>AOF</th></tr></thead><tbody><tr><td>持久化方式</td><td>周期性快照</td><td>逐条命令日志</td></tr><tr><td>文件大小</td><td>小</td><td>大</td></tr><tr><td>恢复速度</td><td>快</td><td>慢</td></tr><tr><td>数据安全</td><td>可能丢几分钟</td><td>丢失不超过 1 秒(默认)</td></tr><tr><td>性能影响</td><td>小</td><td>大</td></tr></tbody></table>
<p><strong>实践建议</strong>:</p>
<ul><li>对数据安全要求不高:仅 RDB。</li><li>对实时性要求高:开启 AOF(默认 everysec)+定期 RDB 做全量备份。</li><li>Redis 4.0 以后支持混合持久化,结合两者优点。</li></ul>
<p class="maodian"><a name="_label7"></a></p><h2>7. 性能管理与优化</h2>
<p class="maodian"><a name="_lab2_7_5"></a></p><h3>内存指标与碎片率</h3>
<ul><li><code>used_memory</code>:实际用来存储数据的内存。</li><li><code>used_memory_rss</code>:进程占用的物理内存。</li><li><strong>内存碎片率</strong> = <code>used_memory_rss / used_memory</code>:<ul><li>&asymp;1:正常。</li><li><p>1.5:碎片较高,低峰期重启 Redis 释放碎片。</p></li><li>&lt;1:内存不足可能触发 swap。</li></ul></li></ul>
<p>查看命令:</p>
<div class="jb51code"><pre class="brush:bash;">redis-cli info memory</pre></div>
<p class="maodian"><a name="_lab2_7_6"></a></p><h3>优化建议</h3>
<ul><li>合理规划实例内存(单实例不超过物理内存 70%~80%)。</li><li>多用 Hash 结构存储减少碎片。</li><li>给 Key 设置过期时间:</li></ul>
<div class="jb51code"><pre class="brush:bash;">set session:123 abcdef EX 3600</pre></div>
<ul><li>设置最大内存与淘汰策略:</li></ul>
<div class="jb51code"><pre class="brush:bash;">maxmemory 2gb
maxmemory-policy allkeys-lru</pre></div>
<ul><li>关闭或限制 swap。</li></ul>
<p class="maodian"><a name="_lab2_7_7"></a></p><h3>内存淘汰策略</h3>
<p>当数据量超过 <code>maxmemory</code> 时,Redis 按策略回收空间:</p>
<table><thead><tr><th>策略</th><th>描述</th></tr></thead><tbody><tr><td>volatile-lru</td><td>从有 TTL 的 Key 中淘汰最少使用的</td></tr><tr><td>volatile-ttl</td><td>从有 TTL 的 Key 中淘汰最快过期的</td></tr><tr><td>volatile-random</td><td>从有 TTL 的 Key 中随机淘汰</td></tr><tr><td>allkeys-lru</td><td>从所有 Key 中淘汰最少使用的(最常用)</td></tr><tr><td>allkeys-random</td><td>从所有 Key 中随机淘汰</td></tr><tr><td>noeviction</td><td>不淘汰,内存不足时报错</td></tr></tbody></table>
<p><strong>实践建议</strong>:</p>
<ul><li>缓存场景:<code>allkeys-lru</code>。</li><li>需要保留核心数据但允许部分丢失:<code>volatile-lru</code>。</li><li>严格要求数据不丢失:<code>noeviction</code>。</li></ul>
<p class="maodian"><a name="_label8"></a></p><h2>8. 常见缓存问题与解决方案</h2>
<p class="maodian"><a name="_lab2_8_8"></a></p><h3>8.1 缓存穿透</h3>
<p><strong>现象</strong>:请求的 Key 在缓存和数据库都不存在,大量请求直达数据库,造成压力。 <strong>原因</strong>:恶意攻击或查询不存在数据。</p>
<p><strong>解决方案</strong>:</p>
<ul><li><strong>缓存空值</strong>:把不存在的数据也缓存一份空对象并设置较短 TTL。</li><li><strong>布隆过滤器(Bloom Filter)</strong>:在缓存前加过滤器,请求 Key 不在过滤器中直接返回空,减少 DB 查询。</li><li><strong>参数校验</strong>:对明显非法参数直接拦截。</li></ul>
<p class="maodian"><a name="_lab2_8_9"></a></p><h3>8.2 缓存击穿</h3>
<p><strong>现象</strong>:某个热点 Key 正好过期瞬间,大量请求同时穿透到数据库。 <strong>原因</strong>:缓存数据过期瞬间并发请求落到 DB。</p>
<p><strong>解决方案</strong>:</p>
<ul><li><strong>热点数据不过期</strong>:为热点 Key 设置长 TTL 或永不过期。</li><li><strong>加互斥锁(Mutex)</strong>:第一个请求获得锁去 DB,其余请求等待。</li><li><strong>预加载/异步刷新</strong>:在数据快过期前提前刷新缓存。</li><li><strong>过期时间随机化</strong>:在 TTL 上加随机值避免集中过期。</li></ul>
<p class="maodian"><a name="_lab2_8_10"></a></p><h3>8.3 缓存雪崩</h3>
<p><strong>现象</strong>:大量缓存同时失效或 Redis 宕机,所有请求涌入数据库。 <strong>原因</strong>:集中过期、缓存不可用、没有熔断限流。</p>
<p><strong>解决方案</strong>:</p>
<ul><li><strong>过期时间分散</strong>:设置 TTL 时加上随机数,避免同一时刻大面积过期。</li><li><strong>双缓存机制</strong>:在缓存失效前提前准备备用缓存,主缓存宕机时快速切换。</li><li><strong>限流与熔断</strong>:在应用层限制请求速率,避免瞬时打爆数据库。</li><li><strong>Redis 高可用</strong>:主从+哨兵或集群,减少缓存整体不可用风险。</li></ul>
<p class="maodian"><a name="_lab2_8_11"></a></p><h3>8.4 综合实践建议</h3>
<ul><li><strong>穿透</strong> &rarr; 布隆过滤器 + 缓存空值。</li><li><strong>击穿</strong> &rarr; 热点 Key 不过期 + 加锁或提前刷新。</li><li><strong>雪崩</strong> &rarr; TTL 随机 + 限流熔断 + 高可用部署。</li></ul>
<p class="maodian"><a name="_label9"></a></p><h2>结语</h2>
<p>掌握 Redis 的 <strong>RDB/AOF 持久化原理</strong>、<strong>缓存问题与解决方案</strong>,不仅能保证数据安全,也能让你的系统在高并发场景下稳定运行。</p>
頁: [1]
查看完整版本: Redis 配置与优化完全指南