0%

Redis 配置详解(基于 6.0.10 版本)

Redis 的配置文件(redis.conf)是控制 Redis 行为的核心,包含了从基础运行参数到高级特性(如持久化、集群、安全)的所有设置。本文基于 6.0.10 版本,按模块解析关键配置项的作用、默认值及实际应用建议。

INCLUDES 模块:配置文件引入

1
2
# include /path/to/local.conf
# include /path/to/other.conf
  • 作用:通过 include 指令引入其他配置文件,便于拆分配置(如将环境特定配置与通用配置分离)。
  • 使用场景:多环境部署(开发 / 测试 / 生产)时,可共享基础配置,仅在环境专属文件中修改差异项。

GENERAL 模块:基础运行参数

核心配置

配置项 作用 默认值 建议设置
daemonize 是否以守护进程(后台)模式运行。 no 生产环境设为 yes
pidfile 进程 ID 文件路径(守护模式下必填)。 redis_6379.pid 按端口区分(如 redis_6380.pid
port 监听端口。 6379 多实例需修改(如 6380、6381)
loglevel 日志级别(debug/verbose/notice/warning)。 notice 生产环境用 warning(减少日志量)
logfile 日志文件路径(空表示输出到控制台)。 "" 设为具体路径(如 ./logs/redis.log
databases 数据库数量(通过 select <dbid> 切换)。 16 无需修改(默认足够)

NETWORK 模块:网络与连接设置

阅读全文 »

Redis 集群详解(基于 6.0.10 版本)

Redis 集群(Redis Cluster)是 Redis 3.0 引入的分布式解决方案,旨在解决单机 Redis 的容量和性能瓶颈,支持水平扩展、自动分片和故障转移。本文基于 6.0.10 版本,详细解析集群的核心原理、搭建方法、命令操作及可用性保障。

集群核心原理:虚拟槽(Virtual Slot)分片

Redis 集群采用虚拟槽分片策略,将数据分散到多个节点,平衡负载并支持动态扩展。

虚拟槽的工作机制

  • 槽范围:集群将数据划分为 0~1638316384 个虚拟槽(固定值,由 2^14 计算而来)。
  • 键与槽的映射:存储键值对时,Redis 通过以下步骤定位槽:
    1. 对键执行 CRC16 哈希算法,得到哈希值。
    2. 哈希值对 16384 取余,结果即为该键所属的槽(slot = CRC16(key) % 16384)。
  • 槽与节点的映射:集群中的每个主节点负责一部分槽(如节点 A 负责 0~5000,节点 B 负责 5001~10000 等),集群自动维护槽与节点的对应关系。

为什么选择虚拟槽?

对比传统分片策略,虚拟槽的优势显著:

分片策略 原理 缺点 虚拟槽的改进
取模(如 key%N 键对节点数取模定位节点 节点增减时,大量键需重新映射(命中率骤降) 槽与节点解耦,节点增减仅需迁移部分槽
一致性哈希 键和节点映射到 2^32 哈希环 节点少时易分布不均,负载失衡 16384 个槽均匀分布,负载更均衡

集群架构与通信

节点类型与角色

阅读全文 »

NoSQL 简介:非关系型数据库的崛起与分类

NoSQL(全称为 “Not Only SQL”,也常被解释为 “non-relational”)是一类非关系型数据库的统称,旨在解决大规模数据存储、高并发访问和灵活数据结构等传统关系型数据库难以应对的挑战。它并非要取代关系型数据库,而是作为补充,在特定场景中发挥优势。

NoSQL 的核心特点

与传统关系型数据库(如 MySQL、Oracle)相比,NoSQL 具有以下显著特征:

  • 无固定 schema(模式自由):无需预先定义表结构,数据格式可动态调整,适合半结构化或非结构化数据(如日志、文档、社交关系)。
  • 分布式架构:天然支持水平扩展,可通过增加节点应对数据量和访问量的增长,适合大数据场景。
  • 高吞吐量:优化了读写性能,尤其擅长处理高并发的简单查询(如键值查询)。
  • 灵活的数据模型:根据业务场景提供多种数据结构(如键值对、文档、列族、图),而非单一的二维表。

NoSQL 的四大分类及代表产品

根据数据模型和应用场景,NoSQL 可分为四大类:

1. 键值存储数据库(Key-Value Store)

核心特点:
  • 以键值对(Key-Value)形式存储数据,Key 唯一,Value 为任意格式(字符串、二进制等)。
  • 读写性能极高,适合简单的查询场景。
代表产品:
  • Redis:支持字符串、哈希、列表等多种数据结构,提供持久化、过期策略和分布式锁,广泛用于缓存、会话存储。
  • Tokyo Cabinet/Tyrant:轻量级键值数据库,适合嵌入式场景。
  • Voldemort:分布式键值存储,强调高可用性和分区容错性。
应用场景:
  • 缓存系统(如热点数据缓存)。
  • 会话管理(存储用户登录状态)。
  • 计数器、排行榜等简单高频操作。

2. 列存储数据库(Column-Family Store)

阅读全文 »

Redis 事务详解(基于 6.0.10 版本)

Redis 事务是一组命令的集合,通过序列化执行机制保证命令的原子性执行(非传统 ACID 原子性),适用于需要批量执行命令且不被中断的场景。本文将深入解析 Redis 事务的特性、命令流程及实际应用。

事务的核心特性

Redis 事务基于单线程架构设计,与传统数据库事务(如 MySQL)有显著区别:

  1. 串行化执行
    事务中的所有命令会按顺序排队,在 EXEC 执行期间,Redis 不会插入其他客户端的命令,保证事务的独占性。
  2. 无隔离级别
    事务提交前,所有命令仅入队不执行,因此:
    • 事务内的查询无法看到事务内其他命令的修改(未执行)。
    • 事务外的查询也无法看到事务内的未执行命令,不存在 “脏读”“不可重复读” 等问题。
  3. 不保证原子性
    • 若事务内存在语法错误(如命令拼写错误),EXEC 会拒绝执行所有命令。
    • 若事务内存在运行时错误(如对字符串执行 INCR),Redis 会继续执行其他命令,仅返回该命令的错误,不支持回滚。

事务命令详解

命令 作用
MULTI 标记事务开始,后续命令进入队列(返回 QUEUED)。
EXEC 执行队列中的所有命令,返回结果列表(若事务被中断,返回 nil)。
DISCARD 取消事务,清空队列(需在 EXEC 前执行)。
WATCH key [key...] 监视键,若事务执行前键被修改,事务会被中断(乐观锁机制)。
UNWATCH 取消所有监视的键(EXECDISCARD 后会自动执行)。

事务执行流程

1. 正常执行

阅读全文 »

Redis 数据结构详解(基于 6.0.10 版本)

Redis 作为高性能键值数据库,支持多种丰富的数据结构,每种结构都有独特的底层实现和适用场景。本文从底层编码、核心命令到应用场景,全面解析 Redis 的 8 种核心数据结构:String、List、Set、Hash、Zset、Bitmaps、HyperLogLogs 和 GEO。

Redis 对象模型(redisObject)

Redis 中所有值都会被包装为 redisObject 结构体,通过 type 标识数据类型,encoding 指定底层存储方式,实现灵活的内存优化:

1
2
3
4
5
6
7
typedef struct redisObject {
unsigned type:4; // 数据类型(String/List/Set等)
unsigned encoding:4; // 编码方式(如int/ziplist/skiplist等)
unsigned lru:LRU_BITS; // 最后访问时间(用于LRU淘汰)
int refcount; // 引用计数(内存回收)
void *ptr; // 指向底层数据结构的指针
} robj;
  • type:通过 type key 命令查看,如 stringlist 等。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // string
    #define OBJ_STRING 0 /* String object. */
    // list
    #define OBJ_LIST 1 /* List object. */
    // set
    #define OBJ_SET 2 /* Set object. */
    //zset
    #define OBJ_ZSET 3 /* Sorted set object. */
    //hash
    #define OBJ_HASH 4 /* Hash object. */
    // module
    #define OBJ_MODULE 5 /* Module object. */
    // stream
    #define OBJ_STREAM 6 /* Stream object. */
  • encoding:通过 object encoding key 命令查看,决定底层实现(如 String 的 int 编码 vs raw 编码)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // 简单动态字符串  raw
    #define OBJ_ENCODING_RAW 0 /* Raw representation */
    // long类型的整数 int
    #define OBJ_ENCODING_INT 1 /* Encoded as integer */
    // 哈希表 hashtable
    #define OBJ_ENCODING_HT 2 /* Encoded as hash table */
    // 压缩 不再使用
    #define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
    // 双向链表 不再使用该结构
    #define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
    // 压缩列表 ziplist
    #define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
    // 整数集合 intset
    #define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
    // 跳表 skiplist
    #define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
    // embstr编码的简单动态字符串 embstr
    #define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
    // 快表 quicklist
    #define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
    // 流 stream
    #define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */

核心数据结构详解

1. String(字符串)

特点:单键单值,可变字节数组,支持字符串、整数、二进制数据(最大 512MB)。
底层编码

  • int:存储 64 位整数(如 set num 123)。
  • embstr:存储短字符串(≤44 字节),连续内存分配(redisObject + SDS 同块内存)。
  • raw:存储长字符串(>44 字节),独立内存分配(redisObject 和 SDS 分开)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
127.0.0.1:6379> set test_int 1
OK
127.0.0.1:6379> object encoding test_int
"int"
127.0.0.1:6379> set test_raw zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
OK
127.0.0.1:6379> strlen test_raw
(integer) 44
127.0.0.1:6379> object encoding test_raw
"embstr"
127.0.0.1:6379> set test_raw zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
OK
127.0.0.1:6379> object encoding test_raw
"raw"
127.0.0.1:6379> strlen test_raw
(integer) 45

# 查看key的内部结构和编码等信息
>debug object k4
Value at:0x7ffc97c044f0 refcount:1 encoding:embstr serializedlength:3 lru:11351195 lru_seconds_idle:5363

embstr和raw两种编码的区别

embstr编码用于保存短字符串,与raw编码一样,都是使用redisObject结构和sdshdr结构来表示字符串对象,但是raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,两个对象在内存地址上是不连续的;而embstr编码则通过调用一次内存分配函数来分配一块连续的内存空间,空间中依次包含redisObject和sdshdr两个结构

底层实现:基于 SDS(简单动态字符串),记录长度(len)和容量(alloc),避免 C 字符串的缺陷(如 O (n) 长度计算):

1
2
3
4
5
6
struct sdshdr8 {  // 8位长度示例
uint8_t len; // 已使用长度
uint8_t alloc; // 总容量(不含头部和终止符)
unsigned char flags; // 类型标识
char buf[]; // 字符串数据
};

扩容:当字符串长度小于1M时,扩容是现有空间进行加倍;当字符串长度超过1M,扩容只会多扩1M的空间。且字符串最长为512M

核心命令

  • 设值:set key valuesetex key 3600 val(过期时间)、setnx key val(不存在时设值)。
  • 取值:get keymget key1 key2(批量获取)。
  • 修改:append key suffix(追加)、setrange key 0 "new"(替换部分字符)。
  • 计数:incr key(自增)、decrby key 5(减 5)。
阅读全文 »