首页
直播
壁纸
友链
搜索
1
微信小程序支付全链路实战:JSAPI 下单、调起支付、回调验签与退款
266 阅读
2
微信小程序云开发实战:云函数、云数据库与云存储的正确使用姿势
256 阅读
3
微信小程序自定义 tabBar 实战:custom-tab-bar 从适配到深色模式
255 阅读
4
微信小程序 Skyline 渲染引擎实战:worklet 动画从原理到落地
253 阅读
5
微信小程序分包进阶:独立分包、预下载与分包异步化实战
246 阅读
服务器运维
后端技术
前端技术
梯子
数据库
小程序
登录
搜索
标签搜索
fastadmin
Redis
微信小程序
前端开发
RabbitMQ
Go
服务器
codex
buildadmin
小程序
mysql
Nginx
Docker
Vue3
Node.js
MySQL优化
Linux
TypeScript
JWT
PHP
沿途的风景
累计撰写
74
篇文章
累计收到
0
条评论
首页
栏目
服务器运维
后端技术
前端技术
梯子
数据库
小程序
页面
直播
壁纸
友链
搜索到
8
篇与
» 数据库
的结果
2026-05-09
Redis 数据类型与核心命令详解:从 String 到 ZSet
前言Redis 是目前最流行的内存数据库,凭借极高的读写性能和丰富的数据结构,被广泛应用于缓存、消息队列、分布式锁等场景。本文将系统讲解 Redis 的五大核心数据类型及其常用命令,帮助你快速上手。一、Redis 数据类型总览数据类型底层结构典型应用场景StringSDS(简单动态字符串)缓存、计数器、分布式锁Hashziplist / hashtable对象存储、用户信息Listquicklist(ziplist + 链表)消息队列、文章列表Setintset / hashtable标签、共同好友、去重ZSetziplist / skiplist + hashtable排行榜、延迟队列二、String(字符串)String 是 Redis 最基础的类型,一个 key 对应一个 value,最大支持 512MB。2.1 基本命令# 设置值 SET name "redis" SET name "redis" EX 30 # 30秒过期 SET name "redis" PX 30000 # 30000毫秒过期 SET name "redis" NX # 仅当key不存在时设置 SET name "redis" XX # 仅当key存在时设置 # 获取值 GET name # "redis" # 批量操作 MSET k1 "v1" k2 "v2" k3 "v3" MGET k1 k2 k3 # 1) "v1" 2) "v2" 3) "v3" # 追加 APPEND name " tutorial" # "redis tutorial" # 长度 STRLEN name # 14 # 自增自减(值必须是数字) SET counter 100 INCR counter # 101 INCRBY counter 10 # 111 DECR counter # 110 DECRBY counter 20 # 902.2 实战:页面访问计数器# 每次访问页面自增 INCR page:home:views # 1 INCR page:home:views # 2 INCR page:home:views # 3 # 获取今日访问量(按日期分key) INCR page:home:views:20260724 # 1 # 设置过期时间,自动清理历史数据 EXPIRE page:home:views:20260724 864002.3 实战:分布式锁(简单版)# 加锁:SET NX 保证原子性 SET lock:order:1001 "uuid-xxx" NX EX 30 # 释放锁(需要Lua脚本保证原子性) # eval "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock:order:1001 uuid-xxx三、Hash(哈希)Hash 是一个键值对集合,特别适合存储对象。3.1 基本命令# 设置字段 HSET user:1001 name "张三" HSET user:1001 age 25 HSET user:1001 email "zhangsan@example.com" # 批量设置 HMSET user:1002 name "李四" age 30 email "lisi@example.com" # 获取字段 HGET user:1001 name # "张三" HMGET user:1001 name age # 1) "张三" 2) "25" # 获取所有字段 HGETALL user:1001 # 1) "name" # 2) "张三" # 3) "age" # 4) "25" # 5) "email" # 6) "zhangsan@example.com" # 获取所有字段名/值 HKEYS user:1001 # name, age, email HVALS user:1001 # 张三, 25, zhangsan@example.com # 字段数量 HLEN user:1001 # 3 # 删除字段 HDEL user:1001 email # 字段自增 HINCRBY user:1001 age 1 # 263.2 实战:购物车# 添加商品到购物车(user:1001 的购物车) HSET cart:1001 product:2001 2 # 商品2001,数量2 HSET cart:1001 product:2002 1 # 商品2002,数量1 # 修改数量 HINCRBY cart:1001 product:2001 1 # 数量+1 → 3 # 查看购物车 HGETALL cart:1001 # 移除商品 HDEL cart:1001 product:2002 # 清空购物车 DEL cart:1001四、List(列表)List 是有序的字符串列表,支持在头部或尾部插入/弹出元素。4.1 基本命令# 左/右推入 LPUSH messages "msg1" "msg2" # 列表: msg2, msg1 RPUSH messages "msg3" # 列表: msg2, msg1, msg3 # 左/右弹出 LPOP messages # "msg2" RPOP messages # "msg3" # 查看范围 LRANGE messages 0 -1 # 所有元素 LRANGE messages 0 2 # 前3个 # 长度 LLEN messages # 按索引获取 LINDEX messages 0 # 第一个元素 # 按索引设置 LSET messages 0 "new_msg" # 阻塞弹出(消息队列核心命令) BLPOP queue:task 30 # 阻塞最多30秒 BRPOP queue:task 304.2 实战:简单消息队列# 生产者:推入任务 LPUSH queue:email '{"to":"a@b.com","subject":"Hello"}' # 消费者:阻塞式弹出任务 BRPOP queue:email 0 # 0表示永久阻塞 # 优点:简单、原子性 # 缺点:无ACK机制,消息丢失需自行处理五、Set(集合)Set 是无序的、不重复的字符串集合。5.1 基本命令# 添加成员 SADD tags:article:1 "redis" "database" "cache" # 查看所有成员 SMEMBERS tags:article:1 # redis, database, cache # 是否是成员 SISMEMBER tags:article:1 "redis" # 1(true) # 成员数量 SCARD tags:article:1 # 3 # 移除成员 SREM tags:article:1 "cache" # 随机弹出 SPOP tags:article:1 # 随机移除并返回一个 SRANDMEMBER tags:article:1 2 # 随机返回2个(不移除)5.2 集合运算SADD set:a "1" "2" "3" "4" SADD set:b "3" "4" "5" "6" # 交集 SINTER set:a set:b # 3, 4 # 并集 SUNION set:a set:b # 1, 2, 3, 4, 5, 6 # 差集(a有但b没有) SDIFF set:a set:b # 1, 25.3 实战:共同关注# 用户A关注了 SADD follows:user:A "redis" "mysql" "docker" # 用户B关注了 SADD follows:user:B "redis" "nginx" "docker" # 共同关注 SINTER follows:user:A follows:user:B # redis, docker # A关注但B没关注 SDIFF follows:user:A follows:user:B # mysql # 推荐关注(B关注但A没关注) SDIFF follows:user:B follows:user:A # nginx六、ZSet(有序集合)ZSet 每个成员关联一个分数(score),按分数排序,是 Redis 最强大的数据结构之一。6.1 基本命令# 添加成员(带分数) ZADD ranking 100 "player1" ZADD ranking 200 "player2" ZADD ranking 150 "player3" ZADD ranking 300 "player4" # 按分数升序排名(0开始) ZRANGE ranking 0 -1 # player1, player3, player2, player4 ZRANGE ranking 0 -1 WITHSCORES # 带分数 # 按分数降序排名 ZREVRANGE ranking 0 -1 # player4, player2, player3, player1 ZREVRANGE ranking 0 -1 WITHSCORES # 按分数范围查询 ZRANGEBYSCORE ranking 100 200 # 100~200分之间 ZRANGEBYSCORE ranking "(100" 200 # 不包含100 # 获取成员分数 ZSCORE ranking "player2" # 200 # 获取成员排名 ZRANK ranking "player2" # 2(升序第3名,0开始) ZREVRANK ranking "player2" # 1(降序第2名) # 增加分数 ZINCRBY ranking 50 "player1" # player1分数变为150 # 成员数量 ZCARD ranking # 4 # 分数范围内的成员数 ZCOUNT ranking 100 200 # 36.2 实战:游戏排行榜# 玩家得分 ZADD game_rank 1500 "Alice" ZADD game_rank 2300 "Bob" ZADD game_rank 1800 "Charlie" ZADD game_rank 2100 "David" ZADD game_rank 1900 "Eve" # Top 3 ZREVRANGE game_rank 0 2 WITHSCORES # 1) "Bob" 2) "2300" # 3) "David" 4) "2100" # 5) "Eve" 6) "1900" # 查看某玩家排名 ZREVRANK game_rank "Alice" # 4(第5名) # 玩家加分 ZINCRBY game_rank 100 "Alice" # Alice: 1600 # 分数段统计 ZCOUNT game_rank 1500 2000 # 3人(Alice, Charlie, Eve)6.3 实战:延迟队列# 将任务加入延迟队列(score为执行时间戳) ZADD delay_queue 1721800500 "task1" # 5秒后执行 ZADD delay_queue 1721800600 "task2" # 15秒后执行 ZADD delay_queue 1721800700 "task3" # 25秒后执行 # 消费者轮询:取出已到期的任务 # 用 Lua 脚本保证原子性 # eval "local items = redis.call('ZRANGEBYSCORE', KEYS[1], 0, ARGV[1]) # if #items > 0 then # redis.call('ZREMRANGEBYSCORE', KEYS[1], 0, ARGV[1]) # end # return items" 1 delay_queue <当前时间戳>七、其他常用命令7.1 Key 管理# 查找key(生产环境慎用 KEYS,用 SCAN) KEYS user:* # 所有以user:开头的key SCAN 0 MATCH user:* COUNT 100 # 渐进式扫描 # 过期时间 EXPIRE name 30 # 30秒后过期 EXPIREAT name 1721800000 # 在指定时间戳过期 TTL name # 查看剩余秒数(-1永久,-2已过期) PERSIST name # 移除过期时间 # 类型判断 TYPE name # string TYPE user:1001 # hash7.2 通用操作# 删除 DEL name # 删除单个 DEL name1 name2 # 删除多个 # 判断存在 EXISTS name # 1(存在) # 重命名 RENAME name newname总结类型核心特点一句话记忆String一对一万能缓存Hash一对多对象存储List有序可重复消息队列Set无序不重复去重与运算ZSet有序不重复排行榜掌握这五大类型和核心命令,就能应对 90% 以上的 Redis 使用场景。后续文章将深入持久化、缓存策略和集群部署。
2026年05月09日
17 阅读
0 评论
0 点赞
2026-04-29
Redis 持久化机制深度对比:RDB、AOF 与混合持久化
前言Redis 作为内存数据库,数据存储在 RAM 中,一旦服务器重启数据就会丢失。为了解决这个问题,Redis 提供了两种持久化机制:RDB(快照)和 AOF(追加日志)。本文将深入对比这两种机制的原理、配置和选择策略。一、RDB(Redis Database)1.1 工作原理RDB 是将 Redis 内存中的数据以二进制快照的形式写入磁盘。触发方式有三种:┌─────────────────────────────────────┐ │ Redis 内存数据 │ │ │ │ ┌───────┐ ┌───────┐ │ │ │ Key1 │ │ Key2 │ ... │ │ └───────┘ └───────┘ │ │ │ │ ▼ fork() 子进程 │ │ │ │ ┌─────────────────────┐ │ │ │ BGSAVE 子进程 │ │ │ │ 写入 dump.rdb │ │ │ └─────────────────────┘ │ └─────────────────────────────────────┘1.2 触发方式手动触发:# 阻塞式(生产环境禁用) SAVE # 后台异步执行(推荐) BGSAVE自动触发(配置文件):# redis.conf # 900秒内至少1个key变化 → 触发RDB save 900 1 # 300秒内至少10个key变化 → 触发RDB save 300 10 # 60秒内至少10000个key变化 → 触发RDB save 60 10000 # 禁用自动RDB # save ""其他触发场景:主从复制时,主节点自动触发 BGSAVE执行 SHUTDOWN 命令时执行 FLUSHALL 命令时(生成空快照)1.3 RDB 文件配置# redis.conf # RDB 文件名 dbfilename dump.rdb # 存储目录 dir /var/lib/redis # 压缩(默认开启,用 LZF 压缩) rdbcompression yes # 校验和(默认开启) rdbchecksum yes # BGSAVE 出错时停止写入(默认yes,推荐开启) stop-writes-on-bgsave-error yes1.4 RDB 优缺点优点:文件紧凑,体积小,适合备份和传输恢复速度快(直接加载二进制数据)对性能影响小(子进程异步执行)适合做冷备和灾难恢复缺点:宕机时会丢失最后一次快照后的所有数据fork 子进程时,如果数据量大,可能造成短暂阻塞不适合对数据完整性要求高的场景二、AOF(Append Only File)2.1 工作原理AOF 以追加的方式将每条写命令记录到日志文件中,重启时按顺序回放命令恢复数据。┌─────────────────────────────────────┐ │ Redis 内存数据 │ │ │ │ 客户端写入命令 │ │ │ │ │ ▼ │ │ ┌──────────┐ ┌──────────────┐ │ │ │ Redis执行 │ → │ 追加到AOF缓冲 │ │ │ │ 命令 │ │ 区 │ │ │ └──────────┘ └──────┬───────┘ │ │ │ │ │ ▼ fsync │ │ ┌──────┴───────┐ │ │ │ appendonly.aof│ │ │ └──────────────┘ │ └─────────────────────────────────────┘2.2 开启 AOF# redis.conf appendonly yes appendfilename "appendonly.aof"2.3 刷盘策略# 三种 fsync 策略 # always: 每条命令都fsync(最安全,性能最差) # everysec: 每秒fsync一次(推荐,最多丢1秒数据) # no: 由OS决定何时fsync(性能最好,可能丢较多数据) appendfsync everysec策略数据安全性性能适用场景always最高(不丢数据)最差对数据极其敏感everysec高(最多丢1秒)好推荐默认no低最好纯缓存场景2.4 AOF 重写随着时间推移,AOF 文件会越来越大。Redis 通过"重写"机制压缩文件:分析当前内存数据,用最少的命令重新生成 AOF 文件。# 手动触发重写 BGREWRITEAOF# redis.conf # AOF 文件大小比上次重写后增长 100% 时自动重写 auto-aof-rewrite-percentage 100 # AOF 文件最小重写体积(64MB) auto-aof-rewrite-min-size 64mb # 重写期间不执行 fsync(减少磁盘 IO) no-appendfsync-on-rewrite yes重写过程:原始 AOF: SET key1 "v1" SET key1 "v2" ← 覆盖 DEL key1 ← 删除 SET key1 "v3" ← 最终值 重写后: SET key1 "v3" ← 只保留最终状态2.5 AOF 优缺点优点:数据安全性高(最多丢 1 秒数据)日志格式可读,可手动修复支持实时持久化,适合对数据完整性要求高的场景缺点:文件体积比 RDB 大恢复速度比 RDB 慢(需要回放命令)重写时会 fork 子进程,大数据量时可能阻塞三、RDB + AOF 混合持久化Redis 4.0 引入混合持久化,结合两者的优点:# redis.conf aof-use-rdb-preamble yes工作原理:AOF 重写时,先以 RDB 格式写入当前内存快照重写期间的增量写命令以 AOF 格式追加在 RDB 数据之后┌────────────────────────────────────┐ │ 混合 AOF 文件 │ │ │ │ ┌──────────────────────────────┐ │ │ │ RDB 二进制数据(全量快照) │ │ │ │ - 恢复速度快 │ │ │ │ - 文件体积小 │ │ │ └──────────────────────────────┘ │ │ ┌──────────────────────────────┐ │ │ │ AOF 增量命令(重写期间) │ │ │ │ - 保证数据不丢 │ │ │ └──────────────────────────────┘ │ └────────────────────────────────────┘恢复流程:先加载 RDB 部分(快速恢复大部分数据)再回放 AOF 增量命令(补全重写期间的数据)四、完整配置示例# redis.conf 生产环境推荐配置 # ===== RDB 配置 ===== save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.rdb dir /var/lib/redis # ===== AOF 配置 ===== appendonly yes appendfilename "appendonly.aof" appendfsync everysec # 混合持久化(Redis 4.0+) aof-use-rdb-preamble yes # AOF 重写 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb no-appendfsync-on-rewrite yes五、持久化方案选择场景推荐方案理由纯缓存,可接受数据丢失仅 RDB性能最优,恢复快数据库,不可丢数据仅 AOF数据安全性高综合场景(推荐)混合持久化兼顾性能和安全灾备备份RDB + 定时备份文件小,传输快备份策略建议#!/bin/bash # 每日凌晨2点备份 RDB 文件 BACKUP_DIR="/backup/redis/$(date +%Y%m%d)" mkdir -p $BACKUP_DIR # 触发 BGSAVE redis-cli BGSAVE # 等待完成 while [ $(redis-cli INFO persistence | grep rdb_bgsave_in_progress | tr -d '\r') != "0" ]; do sleep 1 done # 复制文件 cp /var/lib/redis/dump.rdb $BACKUP_DIR/ # 保留最近7天 find /backup/redis/ -type d -mtime +7 -exec rm -rf {} \; echo "Backup completed: $BACKUP_DIR/dump.rdb"六、故障恢复AOF 文件损坏修复# 如果 AOF 文件损坏,Redis 无法启动 redis-check-aof --fix appendonly.aof # 检查 RDB 文件 redis-check-rdb dump.rdb从备份恢复# 1. 停止 Redis systemctl stop redis # 2. 替换 RDB 文件 cp /backup/redis/20260724/dump.rdb /var/lib/redis/ # 3. 如果不想用 AOF,临时关闭 # 修改 redis.conf: appendonly no # 4. 启动 Redis systemctl start redis # 5. 验证数据 redis-cli DBSIZE总结对比项RDBAOF混合持久化数据安全可能丢分钟级数据最多丢1秒最多丢1秒文件大小小大中恢复速度快慢快性能影响小(fork时短暂)中(每秒fsync)中推荐场景备份/缓存数据库生产推荐生产环境推荐开启混合持久化,同时定期备份 RDB 文件做异地灾备。
2026年04月29日
7 阅读
0 评论
0 点赞
2026-04-22
Redis 集群方案详解:主从复制、哨兵与 Cluster
前言当单机 Redis 无法满足业务需求时,就需要引入集群方案。Redis 提供了三种主要的集群模式:主从复制、哨兵模式和 Cluster 集群。本文将系统讲解三种方案的原理、搭建和适用场景。一、主从复制1.1 架构 ┌──────────────┐ │ Master │ │ (读+写) │ └──────┬───────┘ │ 复制 ┌──────────┼──────────┐ │ │ │ ┌──────▼───┐ ┌───▼────┐ ┌──▼─────┐ │ Slave 1 │ │Slave 2 │ │Slave 3 │ │ (只读) │ │(只读) │ │(只读) │ └──────────┘ └────────┘ └────────┘1.2 工作原理全量同步:Slave 首次连接 Master 时,Master 执行 BGSAVE 生成 RDB 文件,发送给 Slave增量同步:全量同步完成后,Master 将新的写命令实时同步给 Slave断线重连:Slave 断线后重连,通过 replid + offset 判断是否可以增量同步1.3 搭建配置# slave1.conf port 6380 # 配置主节点 slaveof 192.168.1.10 6379 # 从节点只读 slave-read-only yes # 主节点密码 masterauth your_password# 启动从节点 redis-server slave1.conf # 验证主从关系 redis-cli -p 6380 INFO replication # role:slave # master_host:192.168.1.10 # master_port:63791.4 优缺点优点缺点配置简单Master 宕机需手动切换读写分离,提升读性能不具备自动故障转移数据有副本全量同步时可能阻塞 Master二、哨兵模式(Sentinel)2.1 架构┌──────────┐ ┌──────────┐ ┌──────────┐ │Sentinel 1│ │Sentinel 2│ │Sentinel 3│ │ (监控) │ │ (监控) │ │ (监控) │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ └──────┬───────┴──────┬──────┘ │ │ ┌──────▼──────┐ ┌────▼─────┐ │ Master │ │ Slave │ │ (读+写) │ │ (只读) │ └─────────────┘ └──────────┘2.2 工作原理监控:Sentinel 不断向 Master/Slave 发送 PING 命令主观下线:某个 Sentinel 发现节点无响应,标记为主观下线客观下线:超过半数 Sentinel 都报告节点下线,标记为客观下线选举 Leader:Sentinel 之间选举一个 Leader 执行故障转移故障转移:Leader 选一个 Slave 提升为新 Master,通知其他 Slave 和客户端2.3 搭建配置# sentinel1.conf port 26379 # 监控的 Master(名称 IP 端口 仲裁人数) sentinel monitor mymaster 192.168.1.10 6379 2 # Master 无响应 30 秒判定下线 sentinel down-after-milliseconds mymaster 30000 # 故障转移超时时间 sentinel failover-timeout mymaster 180000 # 同时只允许1个Slave做同步 sentinel parallel-syncs mymaster 1 # Master 密码 sentinel auth-pass mymaster your_password# 启动3个Sentinel redis-sentinel sentinel1.conf redis-sentinel sentinel2.conf redis-sentinel sentinel3.conf2.4 故障转移过程1. Master宕机 │ 2. Sentinels检测到Master无响应 │ 3. 超过quorum(2)个Sentinel标记为客观下线 │ 4. 选举Leader Sentinel │ 5. Leader选择最优Slave提升为Master: - 排除故障Slave - 选择offset最大的Slave(数据最新) - 优先级高的Slave优先 │ 6. 其他Slave指向新Master │ 7. 通知客户端新Master地址 │ 8. 旧Master恢复后变为Slave2.5 客户端连接// PHP 客户端连接 Sentinel $sentinels = [ 'tcp://192.168.1.10:26379', 'tcp://192.168.1.11:26379', 'tcp://192.168.1.12:26379', ]; $redis = new RedisSentinel($sentinels, [ 'name' => 'mymaster', 'password' => 'your_password', ]); // 自动路由到当前 Master $redis->set('key', 'value');三、Cluster 集群3.1 架构┌─────────────────────────────────────────────────────┐ │ Redis Cluster │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ Node A │ │ Node B │ │ Node C │ │ │ │Master │ │Master │ │Master │ │ │ │槽0-5460 │ │槽5461- │ │槽10923- │ │ │ │ │ │ 10922 │ │ 16383 │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ │ │ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │ │ │ Node A' │ │ Node B' │ │ Node C' │ │ │ │ Slave │ │ Slave │ │ Slave │ │ │ └─────────┘ └─────────┘ └─────────┘ │ └─────────────────────────────────────────────────────┘3.2 核心概念哈希槽(Hash Slot)Redis Cluster 有 16384 个哈希槽,分布在所有 Master 节点上:# 计算key属于哪个槽 slot = CRC16(key) % 16384 # 示例 # key="user:1001" → CRC16 → slot=12345 # slot 12345 属于 Node C (10923-16383)节点通信(Gossip协议)每个节点定期向其他节点发送 PING 消息,交换集群状态信息。3.3 搭建 Cluster方式一:手动搭建(6节点,3主3从)# 创建6个配置文件 for port in 7001 7002 7003 7004 7005 7006; do mkdir -p /redis/cluster/$port cat > /redis/cluster/$port/redis.conf << EOF port $port cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes dir /redis/cluster/$port EOF done # 启动6个节点 for port in 7001 7002 7003 7004 7005 7006; do redis-server /redis/cluster/$port/redis.conf & done # 创建集群 redis-cli --cluster create \ 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 \ 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 \ --cluster-replicas 1方式二:Docker Compose 搭建version: '3.8' services: redis-node-1: image: redis:7 command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7001 ports: - "7001:7001" networks: - redis-cluster redis-node-2: image: redis:7 command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7002 ports: - "7002:7002" networks: - redis-cluster # ... node-3 到 node-6 同理 redis-cluster-init: image: redis:7 command: > bash -c "sleep 10 && echo yes | redis-cli --cluster create redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005 redis-node-6:7006 --cluster-replicas 1" depends_on: - redis-node-1 - redis-node-2 - redis-node-3 - redis-node-4 - redis-node-5 - redis-node-6 networks: - redis-cluster networks: redis-cluster: driver: bridge3.4 客户端使用// PHP 使用 Redis Cluster $redis = new RedisCluster( null, // null 表示自动发现节点 [ '127.0.0.1:7001', '127.0.0.1:7002', '127.0.0.1:7003', ], 2, // 连接超时 2, // 读写超时 true, // 持久化连接 'password' ); // 使用方式与单机一致,客户端自动路由 $redis->set('user:1001', 'Alice'); $redis->set('user:1002', 'Bob'); $redis->set('user:1003', 'Charlie'); // 不同的key可能落在不同节点 // user:1001 → slot 12345 → Node C // user:1002 → slot 6789 → Node B // user:1003 → slot 456 → Node A3.5 Hash Tag如果需要让多个 key 落在同一个槽,使用 Hash Tag:# 用 {} 指定hash计算的部分 SET {user:1001}:profile "Alice's profile" SET {user:1001}:settings '{"theme":"dark"}' SET {user:1001}:cart "[]" # 三个key都计算 user:1001 的CRC16,落在同一个槽 # 可以在同一节点执行批量操作 MGET {user:1001}:profile {user:1001}:settings {user:1001}:cart四、三种方案对比特性主从复制Sentinel 哨兵Cluster 集群数据分片否否是(16384槽)自动故障转移否是是读写分离是是是Master单点瓶颈是是否最少节点数23+Sentinel6复杂度低中高适用场景读多写少中小规模大规模五、选型建议数据量 < 10GB? ├── 是 → 单机Redis够用 │ └── 需要高可用? │ ├── 是 → Sentinel(3节点+3哨兵) │ └── 否 → 单机 │ └── 否 → 数据量大/并发高 └── Redis Cluster(3主3从起步)生产环境推荐中小项目:Sentinel 哨兵(1主2从+3哨兵)大型项目:Redis Cluster(3主3从起步,按需扩展)极大规模:Cluster + 多机房部署 + 代理层六、运维注意事项6.1 内存监控# 查看各节点内存使用 redis-cli -p 7001 INFO memory | grep used_memory_human redis-cli -p 7002 INFO memory | grep used_memory_human redis-cli -p 7003 INFO memory | grep used_memory_human # 集群整体状态 redis-cli -p 7001 CLUSTER INFO redis-cli -p 7001 CLUSTER NODES6.2 扩容(Cluster)# 新增节点 redis-server /redis/cluster/7007/redis.conf # 加入集群 redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001 # 分配槽位(从现有节点迁移部分槽到新节点) redis-cli --cluster reshard 127.0.0.1:7001 \ --cluster-from <现有节点ID> \ --cluster-to <新节点ID> \ --cluster-slots 1000 \ --cluster-yes6.3 数据迁移# 在线迁移(不停服) redis-cli --cluster rebalance 127.0.0.1:7001 \ --cluster-use-empty-masters \ --cluster-threshold 1总结方案核心价值关键限制主从复制读写分离、数据备份无自动故障转移Sentinel自动故障转移、高可用单Master写入瓶颈Cluster数据分片、水平扩展不支持跨槽事务、复杂度高选择原则:先评估数据量和并发量,小规模用 Sentinel,大规模用 Cluster,不要过度设计。
2026年04月22日
15 阅读
0 评论
0 点赞
2026-03-15
Elasticsearch 入门指南:从索引到全文搜索实战
前言Elasticsearch 是基于 Lucene 的分布式搜索和分析引擎,支持全文检索、结构化搜索、聚合分析等。本文将带你从零开始掌握 ES 的核心概念和实战操作。一、核心概念Elasticsearch关系型数据库说明IndexDatabase索引(数据库)DocumentRow文档(一行记录)FieldColumn字段MappingSchema字段类型定义ShardPartition分片,数据水平拆分二、Docker 部署docker run -d --name es \ -p 9200:9200 -p 9300:9300 \ -e "discovery.type=single-node" \ -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \ -e "xpack.security.enabled=false" \ elasticsearch:8.13.0验证:curl http://localhost:9200三、索引操作3.1 创建索引与 MappingPUT /articles { "settings": { "number_of_shards": 1, "number_of_replicas": 0 }, "mappings": { "properties": { "title": { "type": "text", "analyzer": "ik_max_word" }, "content": { "type": "text", "analyzer": "ik_max_word" }, "author": { "type": "keyword" }, "tags": { "type": "keyword" }, "view_count": { "type": "integer" }, "publish_date": { "type": "date", "format": "yyyy-MM-dd" } } } }text 类型:会被分词,适合全文搜索keyword 类型:不分词,适合精确匹配和聚合ik_max_word:中文分词器,最细粒度切分3.2 新增文档POST /articles/_doc/1 { "title": "Elasticsearch 入门指南", "content": "Elasticsearch 是基于 Lucene 的分布式搜索引擎", "author": "admin", "tags": ["搜索", "ES"], "view_count": 100, "publish_date": "2026-07-24" }3.3 批量操作POST /_bulk {"index": {"_index": "articles", "_id": "2"}} {"title": "文章2", "content": "内容2", "author": "admin", "tags": ["测试"], "view_count": 50, "publish_date": "2026-07-24"} {"index": {"_index": "articles", "_id": "3"}} {"title": "文章3", "content": "内容3", "author": "user", "tags": ["搜索"], "view_count": 200, "publish_date": "2026-07-23"}四、搜索查询4.1 全文搜索GET /articles/_search { "query": { "match": { "content": "分布式搜索引擎" } } }4.2 多字段搜索GET /articles/_search { "query": { "multi_match": { "query": "Elasticsearch 分布式", "fields": ["title^3", "content"] } } }title^3 表示 title 字段权重是 content 的 3 倍。4.3 精确匹配GET /articles/_search { "query": { "term": { "author": "admin" } } }4.4 组合查询(bool)GET /articles/_search { "query": { "bool": { "must": [ { "match": { "content": "搜索引擎" } } ], "filter": [ { "term": { "author": "admin" } }, { "range": { "view_count": { "gte": 50 } } } ], "must_not": [ { "term": { "tags": "测试" } } ] } } }must:必须匹配(参与算分)filter:必须匹配(不算分,走缓存,性能更好)must_not:必须不匹配should:应该匹配(满足则加分)4.5 高亮搜索结果GET /articles/_search { "query": { "match": { "content": "搜索引擎" } }, "highlight": { "fields": { "content": { "pre_tags": ["<em>"], "post_tags": ["</em>"] } } } }4.6 聚合查询GET /articles/_search { "size": 0, "aggs": { "by_author": { "terms": { "field": "author", "size": 10 }, "aggs": { "avg_views": { "avg": { "field": "view_count" } } } } } }五、中文分词5.1 安装 IK 分词器./bin/elasticsearch-plugin install \ https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.13.0/elasticsearch-analysis-ik-8.13.0.zip5.2 两种分词模式GET /_analyze { "analyzer": "ik_smart", "text": "Elasticsearch是分布式搜索引擎" } // 结果: Elasticsearch / 是 / 分布式 / 搜索引擎 GET /_analyze { "analyzer": "ik_max_word", "text": "Elasticsearch是分布式搜索引擎" } // 结果: Elasticsearch / 是 / 分布 / 式 / 分布式 / 搜索 / 引擎 / 搜索引擎ik_smart:粗粒度,适合索引时分词ik_max_word:细粒度,适合搜索时分词六、性能优化要点索引字段合理选型:不需要搜索的字段不建索引filter 代替 query:不需要算分的场景用 filter,走缓存分页用 search_after:避免深度分页的 from + size控制分片数量:单分片建议 10-50GB使用批量操作:bulk 比单条操作快 10 倍以上总结Elasticsearch 在全文搜索、日志分析、数据可视化等场景中几乎是标配。掌握 Mapping 设计、查询 DSL 和分词器配置是使用 ES 的基本功。生产环境中注意合理设置分片副本、映射字段类型和查询优化策略。
2026年03月15日
10 阅读
0 评论
0 点赞
2026-03-02
MySQL 慢查询优化实战:从 EXPLAIN 到索引调优
前言MySQL 慢查询是影响应用性能的常见瓶颈。本文从慢查询日志分析入手,结合 EXPLAIN 执行计划解读,系统讲解索引优化和 SQL 调优方法。一、慢查询日志1.1 开启慢查询日志-- 查看慢查询配置 SHOW VARIABLES LIKE "%slow_query%"; -- 开启慢查询日志 SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 1; -- 超过 1 秒的查询 SET GLOBAL slow_query_log_file = "/var/log/mysql/slow.log"; -- 记录未使用索引的查询 SET GLOBAL log_queries_not_using_indexes = ON;1.2 使用 mysqldumpslow 分析# 按平均查询时间排序,取前 10 mysqldumpslow -s t -t 10 /var/log/mysql/slow.log # 按总耗时排序 mysqldumpslow -s at -t 10 /var/log/mysql/slow.log # 按次数排序 mysqldumpslow -s c -t 10 /var/log/mysql/slow.log二、EXPLAIN 执行计划2.1 基本用法EXPLAIN SELECT * FROM orders WHERE user_id = 10086 AND status = "paid";2.2 关键字段解读字段说明重点关注type访问类型至少达到 range 级别,避免 ALLkey实际使用的索引不为 NULLrows预估扫描行数越小越好Extra附加信息避免 Using filesort 和 Using temporary2.3 type 类型(从好到差)system > const > eq_ref > ref > range > index > ALLconst:主键或唯一索引等值查询eq_ref:JOIN 时使用主键或唯一索引ref:非唯一索引等值查询range:索引范围查询(BETWEEN、>、<、IN)index:扫描整个索引树ALL:全表扫描,必须优化三、索引优化3.1 创建合适的索引-- 单列索引 CREATE INDEX idx_user_id ON orders(user_id); -- 联合索引(注意最左前缀原则) CREATE INDEX idx_user_status ON orders(user_id, status, created_at); -- 覆盖索引(查询字段都在索引中) CREATE INDEX idx_cover ON orders(user_id, status, amount);3.2 最左前缀原则-- 联合索引 (a, b, c) -- 能命中索引: SELECT * FROM t WHERE a = 1; SELECT * FROM t WHERE a = 1 AND b = 2; SELECT * FROM t WHERE a = 1 AND b = 2 AND c = 3; -- 不能命中索引: SELECT * FROM t WHERE b = 2; SELECT * FROM t WHERE c = 3; SELECT * FROM t WHERE b = 2 AND c = 3;3.3 避免索引失效-- 函数操作导致索引失效 SELECT * FROM orders WHERE YEAR(created_at) = 2026; -- 优化: SELECT * FROM orders WHERE created_at >= "2026-01-01" AND created_at < "2027-01-01"; -- 隐式类型转换 SELECT * FROM orders WHERE order_no = 10086; -- order_no 是 varchar -- 优化: SELECT * FROM orders WHERE order_no = "10086"; -- LIKE 前导通配符 SELECT * FROM users WHERE name LIKE "%张"; -- 优化:使用全文索引或调整业务逻辑 SELECT * FROM users WHERE name LIKE "张%"; -- OR 导致索引失效 SELECT * FROM orders WHERE user_id = 1 OR status = "paid"; -- 优化:使用 UNION ALL SELECT * FROM orders WHERE user_id = 1 UNION ALL SELECT * FROM orders WHERE status = "paid" AND user_id != 1;四、SQL 调优实战4.1 分页优化-- 慢:OFFSET 大时性能差 SELECT * FROM orders ORDER BY id LIMIT 1000000, 20; -- 优化方案 1:延迟关联 SELECT * FROM orders o INNER JOIN (SELECT id FROM orders ORDER BY id LIMIT 1000000, 20) t ON o.id = t.id; -- 优化方案 2:游标分页(记住上一页最后一条 ID) SELECT * FROM orders WHERE id > 1000000 ORDER BY id LIMIT 20;4.2 批量插入-- 慢:循环单条插入 INSERT INTO logs (msg) VALUES ("log1"); INSERT INTO logs (msg) VALUES ("log2"); -- 优化:批量插入 INSERT INTO logs (msg) VALUES ("log1"), ("log2"), ("log3");4.3 使用 Redis 缓存热点数据import redis import json r = redis.Redis(host="localhost", port=6379, db=0) def get_user(user_id): # 先查缓存 cache_key = f"user:{user_id}" cached = r.get(cache_key) if cached: return json.loads(cached) # 查数据库 user = db.query("SELECT * FROM users WHERE id = %s", user_id) if user: r.setex(cache_key, 3600, json.dumps(user)) # 缓存 1 小时 return user五、总结MySQL 慢查询优化的核心思路:先通过慢查询日志找到问题 SQL,再用 EXPLAIN 分析执行计划,最后通过添加索引、调整 SQL 写法、引入缓存等方式优化。记住:不是所有慢查询都需要加索引,有时调整业务逻辑比优化 SQL 更有效。
2026年03月02日
15 阅读
0 评论
0 点赞
1
2
0:00