目录
关系数据库与非关系型数据库
数据库按照数据库的结构可以分为关系型数据库与其他数据库,而这些其他数据库我们将其统称为非关系型数据库
关系型数据库核心概念
关系型数据库(Relational Database,RDB)是一种基于关系模型来组织和管理数据的数据库系统,以下从其核心概念、特点、组成、数据操作方式以及应用场景几个方面展开介绍:
关系模型由埃德加·科德(E.F.Codd)在1970年提出,它将数据组织成二维表格的形式,每个表格被称为一个关系(或表),表中的每一行代表一条记录(或元组),每一列代表一个属性(或字段)。不同表之间可以通过公共字段建立关联,从而形成一个有机的整体,以表示现实世界中各种实体及其之间的联系。
特点
- 数据结构化:关系型数据库将数据组织成具有固定结构的表,每个表有明确的列定义,规定了列的数据类型、约束等。这种结构化的组织方式使得数据存储和查询更加规范、有序,便于进行数据的统一管理和维护。
- 数据一致性高:通过事务(Transaction)机制来保证数据的完整性和一致性。事务是一组操作的集合,这些操作要么全部成功执行,要么全部不执行,从而确保数据在并发操作等情况下不会出现不一致的情况。例如,银行转账业务中,从A账户扣款和向B账户入款这两个操作必须作为一个事务来处理,只有两者都成功,转账才算完成。
- 支持复杂的查询:提供了强大的结构化查询语言(SQL),用户可以使用SQL语句进行各种复杂的数据查询操作,如多表连接查询、子查询、聚合函数查询等,能够方便地从大量数据中提取所需的信息。
- 数据独立性高:包括物理数据独立性和逻辑数据独立性。物理数据独立性是指应用程序与存储在磁盘上的数据库中数据是相互独立的,当数据的物理存储改变了,应用程序不用改变;逻辑数据独立性是指用户的应用程序与数据库的逻辑结构是相互独立的,数据的逻辑结构改变了,用户程序也可以不变。
组成
- 表(Table):是关系型数据库的基本存储单元,用于存储具有相同特征的数据集合。每个表由行和列组成,行代表记录,列代表属性。
- 字段(Field):也称为列(Column),是表中的一个属性,用于定义数据的类型和特征。例如,在一个学生表中,字段可以包括学号、姓名、年龄、性别等。
- 记录(Record):也称为行(Row),是表中的一条数据,包含了该记录在各个字段上的值。例如,在学生表中,一条记录可能表示一个学生的具体信息,如学号为“001”,姓名为“张三”,年龄为“20”,性别为“男”。
- 主键(Primary Key):是表中用于唯一标识每一条记录的字段或字段组合。主键的值不能重复,也不能为空。例如,在学生表中,学号可以作为主键,因为每个学生的学号是唯一的。
- 外键(Foreign Key):是表中的一个字段或字段组合,它引用了另一个表的主键。外键用于建立表与表之间的关联关系,实现数据的完整性约束。例如,在一个选课表中,学生学号可以作为外键,引用学生表的主键学号,表示该选课记录对应的学生。
数据操作方式
- 数据定义语言(DDL):用于定义数据库的结构,如创建、修改和删除表、视图、索引等数据库对象。常见的DDL语句有
CREATE
(创建)、ALTER
(修改)、DROP
(删除)等。例如,CREATE TABLE student(id INT PRIMARY KEY, name VARCHAR(20), age INT)
用于创建一个名为student
的表。 - 数据操作语言(DML):用于对数据库中的数据进行增、删、改、查等操作。常见的DML语句有
INSERT
(插入)、DELETE
(删除)、UPDATE
(更新)、SELECT
(查询)等。例如,INSERT INTO student(id, name, age) VALUES(1, '张三', 20)
用于向学生表中插入一条记录。 - 数据控制语言(DCL):用于控制对数据库的访问权限,如授予或撤销用户对数据库对象的操作权限。常见的DCL语句有
GRANT
(授予权限)和REVOKE
(撤销权限)等。例如,GRANT SELECT ON student TO user1
用于授予用户user1
对学生表的查询权限。
非关系型数据库核心概念
非关系型数据库(NoSQL,Not Only SQL)是一种不遵循传统关系型数据库模型的数据存储系统,它突破了关系型数据库在数据结构、扩展性等方面的限制,以适应不同应用场景下多样化的数据存储和管理需求。以下从核心特点、常见类型、优势、劣势以及应用场景几个方面展开介绍
核心特点
- 数据模型灵活:不像关系型数据库有固定的表结构,非关系型数据库的数据模型可以根据应用需求动态变化。例如,在存储用户信息时,不同用户的属性可能不同,非关系型数据库无需预先定义好固定的字段,可直接存储包含不同属性的数据。
- 可扩展性强:能够方便地进行水平扩展,通过增加服务器节点来提升数据库的处理能力和存储容量,以满足不断增长的数据量和用户访问需求。比如,随着电商平台用户量的激增,可以通过添加更多服务器来扩展数据库性能。
- 高并发性能好:设计上更注重处理高并发的读写操作,能够在大量用户同时访问的情况下保持较好的性能。像社交媒体平台在热门话题出现时,会面临海量的用户评论、点赞等并发操作,非关系型数据库可以较好地应对。
常见类型
类型 | 代表数据库 | 特点 | 适用场景 |
---|---|---|---|
键值数据库(Key-Value) | Redis、Memcached | 数据以键值对的形式存储,键是唯一的标识符,值可以是任意类型的数据。操作简单高效,通常只支持基本的增删改查操作。 | 缓存系统、会话存储、计数器等对数据一致性要求不是特别高,但需要快速读写的场景。 |
文档数据库(Document) | MongoDB、CouchDB | 数据以文档的形式存储,文档通常采用JSON、BSON等格式,可以包含复杂的嵌套结构。支持丰富的查询操作,能够灵活地处理半结构化数据。 | 内容管理系统、博客平台、电商网站等需要存储和处理大量半结构化数据的场景。 |
列族数据库(Column-Family) | Cassandra、HBase | 数据以列族的形式组织,每个列族包含多个列。适合存储海量的稀疏数据,具有高可扩展性和高可用性。 | 日志存储、时间序列数据分析、传感器数据存储等需要处理大规模稀疏数据的场景。 |
图数据库(Graph) | Neo4j、JanusGraph | 以图结构存储数据,节点表示实体,边表示实体之间的关系。擅长处理复杂的关系查询,能够高效地遍历图中的节点和边。 | 社交网络分析、推荐系统、知识图谱等需要处理复杂关系数据的场景。 |
优势
- 开发效率高:由于数据模型灵活,开发人员无需花费大量时间在设计复杂的表结构和维护数据一致性上,可以更快速地实现业务功能。例如,在开发一个初创的社交应用时,使用非关系型数据库可以快速搭建数据存储层,快速迭代产品。
- 成本较低:许多非关系型数据库是开源的,并且可以使用普通的服务器硬件进行部署,降低了硬件采购和维护成本。同时,其水平扩展的特性也使得在数据量增长时无需频繁更换昂贵的高性能服务器。
- 支持大数据量存储:通过分布式架构和水平扩展能力,能够轻松存储和处理PB级别甚至更大的数据量。这对于一些需要处理海量数据的企业来说,是非常重要的优势。
劣势
- 数据一致性保障相对较弱:部分非关系型数据库为了追求高性能和可扩展性,在数据一致性方面做出了妥协,通常采用最终一致性模型,即数据在更新后不会立即在所有节点上保持一致,而是在一段时间后才会达到一致状态。这对于一些对数据一致性要求极高的应用场景,如金融交易系统,可能不太适用。
- 缺乏标准化查询语言:不同类型甚至不同品牌的非关系型数据库可能使用不同的查询语言和API,这增加了开发人员的学习成本和开发难度,也不利于数据库的迁移和互操作性。
- 功能相对有限:与关系型数据库相比,非关系型数据库在事务处理、复杂查询、数据分析等方面的功能可能不够完善。例如,在需要进行多表关联查询和复杂聚合运算时,非关系型数据库的性能和功能可能无法满足需求。
Redis简介
Redis(Remote Dictionary Server)是一个开源的高性能键值对(Key-Value)内存数据库,以下从多个方面对其进行介绍:
核心特性
- 数据类型丰富:Redis支持多种数据结构,包括字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set),以及位图(Bitmap)、HyperLogLogs(基数统计)、地理空间索引(GEO)、流(Stream)等特殊数据类型。这些数据结构能够满足各种不同的业务需求。
- 内存存储与高速读写:数据存储在内存中,读写速度非常快,官方基准测试显示,其读的速度可达110000次/秒,写的速度是81000次/秒。这种特性使得Redis非常适合处理高并发的读写请求,能够有效减轻后端数据库的压力。
- 持久化机制:提供RDB和AOF两种持久化方式。RDB通过创建数据集的时间点快照来实现持久化,适合数据备份和灾难恢复;AOF记录每一个写操作命令到一个日志文件中,提供了更好的数据安全性。用户可以根据实际需求选择合适的持久化方式,或者同时开启两种方式以保证数据的安全性和可靠性。
- 高可用性与扩展性:支持主从复制、哨兵(Sentinel)和集群(Cluster)等高可用性方案。主从复制可以实现读写分离和数据备份;哨兵模式能够监控主节点状态,自动进行故障转移;集群模式则支持数据的自动分片和横向扩展,提高了系统的可用性和处理能力。
- 原子性操作:所有操作都是原子性的,这意味着操作要么完全执行,要么完全不执行。这种特性对于确保数据的一致性和完整性非常重要,尤其是在高并发环境下处理事务时。
- 单线程模型与I/O多路复用:采用单线程模型处理客户端请求,避免了多线程的上下文切换等开销。同时,利用I/O多路复用技术(如epoll、kqueue等)来监听多个套接字(socket),使得它可以同时处理多个客户端的连接请求,从而在处理大量并发连接时依然能够保持高性能。
应用场景
- 缓存:是最常见的应用场景之一。通过将热点数据存储在Redis中,可以大大提高数据的访问速度,减少数据库的查询压力。例如,在电商网站中,可以将商品信息、用户购物车内容等缓存到Redis中。
- 消息队列:Redis的列表(List)数据类型可以用于简单的消息队列实现。生产者将消息推送到列表的一端,消费者从另一端获取消息。虽然与专业的消息队列系统相比,Redis在消息持久化、消息顺序保证等方面可能稍逊一筹,但在一些简单的、对消息可靠性要求不是特别高的场景下,它可以提供轻量级的消息队列解决方案。
- 计数器与排行榜:利用Redis的原子操作(如INCR、ZADD等)可以方便地实现计数器和排行榜功能。例如,在社交媒体平台上,可以使用Redis来记录文章的点赞数、评论数等计数器;在游戏应用中,可以通过有序集合来维护玩家的得分排行榜。
- 分布式锁:在分布式系统中,Redis可以用于实现分布式锁。通过使用SET命令的NX(Not Exist)选项,可以确保只有一个客户端能够成功设置某个键,从而实现对共享资源的互斥访问。
- 会话存储:在Web应用中,Redis可以用来存储用户会话信息。它能够快速读写用户的会话数据,支持大量并发的访问。例如,在线购物平台可将用户的登录信息和购物车状态存储在Redis中,实现快速会话恢复。
优势与局限
- 优势
- 高性能:基于内存的存储和高效的I/O处理机制,使其能够快速响应客户端请求。
- 灵活性:丰富的数据结构和操作命令,使得开发者可以根据具体需求选择合适的数据结构来存储和处理数据。
- 社区支持:拥有一个活跃的开发者社区,提供了大量的文档、教程和第三方库,方便开发者学习和使用。
- 局限
- 内存限制:数据量受物理内存约束,不适合海量存储。
- 复杂查询不足:缺乏关系型数据库的多表关联和复杂查询能力。
Redis的主要配置参数
以下是一些重要的参数及其说明:
- bind:指定Redis服务器监听的网络接口,默认为127.0.0.1(本地回环地址)。如果需要远程访问Redis,应将其设置为服务器的IP地址或0.0.0.0(监听所有网络接口)。
- port:指定Redis服务器监听的端口号,默认为6379。
- daemonize:设置为yes表示Redis以守护进程的方式启动(后台运行),默认值为no。
- pidfile:配置PID文件路径,当Redis作为守护进程运行时,它会把进程ID写入指定的PID文件。
- loglevel:定义日志级别,可选值包括debug、verbose、notice、warning等。生产环境下一般使用notice级别。
- logfile:配置日志文件地址,默认使用标准输出(stdout)。可以通过该选项将日志输出到指定的文件中,便于日志的管理和分析。
- databases:设置数据库的数目,默认值为16。Redis默认有16个数据库,可以使用SELECT命令来切换数据库。
- save:配置触发Redis持久化的条件,即什么时候将内存中的数据保存到硬盘。可以配置多个save规则,每个规则由两个参数组成,分别表示持久化操作的时间间隔(单位为秒)和被修改的键的数量。例如,
save 900 1
表示900秒内如果至少有1个key的值变化,则保存。 - stop-writes-on-bgsave-error:当启用RDB持久化且最后一次后台保存数据失败时,Redis是否停止接收数据。默认值为yes,表示终止所有客户端的write请求。
- rdbcompression:是否对RDB文件进行压缩,默认为yes。压缩会消耗额外的CPU资源,但可以减小RDB文件的大小。
- rdbchecksum:是否对RDB文件使用CRC64校验和,默认为yes。这会增加大约10%的性能消耗,但可以提高数据的完整性。
- dbfilename:设置RDB文件的名称,默认值为dump.rdb。
- dir:设置RDB文件和AOF文件的存放路径,这个配置项必须是一个目录,而不能是文件名。
- appendonly:是否开启AOF(Append Only File)持久化模式。默认值为no,表示关闭AOF模式。设置为yes时,Redis将所有写操作追加到AOF文件中,以确保数据持久化。
- appendfilename:设置AOF文件的名称,默认值为appendonly.aof。
- appendfsync:设置AOF同步策略,可选值包括always、everysec、no。always表示每次写操作都同步到磁盘(最慢但最安全),everysec表示每秒同步一次(兼顾性能和安全性),no表示由操作系统决定何时同步(最快但可能丢失数据)。
- maxmemory:设置Redis服务器使用的最大内存量。当内存达到该阈值时,Redis会执行内存淘汰策略。
- maxmemory-policy:设置内存淘汰策略,即当达到最大内存限制时,Redis应该如何选择要淘汰的键。常见的策略包括volatile-lru、allkeys-lru、volatile-random、allkeys-random等。
- requirepass:设置Redis服务器的连接密码,用于保护Redis服务器免受未经授权的访问。
Redis命令
Redis 提供了多种命令工具,用于管理数据库、操作数据、监控性能等,以下是常见的命令工具及其分类介绍:
通用命令
这些命令适用于所有数据类型,用于基础的数据操作和管理。
命令 | 语法 | 示例 | 说明 |
---|---|---|---|
KEYS | KEYS pattern | KEYS user:* | 查找符合给定模式 pattern 的所有键。在生产环境中慎用,因为它会阻塞 Redis 服务器,影响性能。 |
TYPE | TYPE key | TYPE mykey | 返回键 key 存储的值的类型。 |
TTL | TTL key | TTL mykey | 返回键 key 的剩余生存时间(以秒为单位)。如果键不存在或没有设置生存时间,则返回不同的值。 |
EXPIRE | EXPIRE key seconds | EXPIRE mykey 60 | 为键 key 设置生存时间,当生存时间到期时,键会被自动删除。 |
DEL | DEL key [key ...] | DEL key1 key2 | 删除指定的一个或多个键。 |
EXISTS | EXISTS key | EXISTS mykey | 检查键 key 是否存在,存在返回 1,不存在返回 0。 |
RENAME | RENAME oldkey newkey | RENAME oldname newname | 将键 oldkey 改名为 newkey 。 |
DBSIZE | DBSIZE | 返回当前数据库中键的数量。 |
字符串(String)常用相关命令
字符串是 Redis 最基本的数据类型,以下命令用于操作字符串数据。
命令 | 语法 | 示例 | 说明 |
---|---|---|---|
SET | `SET key value [EX seconds] [PX milliseconds] [NX | XX]` | SET name "John" EX 60 |
GET | GET key | GET name | 获取键 key 存储的字符串值。 |
INCR | INCR key | INCR counter | 将键 key 存储的整数值加 1。如果键不存在,则初始化为 0 再加 1。 |
DECR | DECR key | DECR counter | 将键 key 存储的整数值减 1。如果键不存在,则初始化为 0 再减 1。 |
INCRBY | INCRBY key increment | INCRBY score 10 | 将键 key 存储的整数值加上 increment 。 |
DECRBY | DECRBY key decrement | DECRBY score 5 | 将键 key 存储的整数值减去 decrement 。 |
APPEND | APPEND key value | APPEND message " Hello" | 如果键 key 已经存在并且是一个字符串,则将 value 追加到该键原来的值后面。如果键不存在,则创建一个新的字符串键并设置其值为 value 。 |
GETRANGE | GETRANGE key start end | GETRANGE message 0 4 | 返回键 key 存储的字符串值的子字符串,子字符串由 start 和 end 偏移量决定(包含两端)。 |
哈希(Hash)相关命令
哈希用于存储对象,每个哈希可以包含多个字段和值。
命令 | 语法 | 示例 | 说明 |
---|---|---|---|
HSET | HSET key field value [field value ...] | HSET user:1000 name "Alice" age 25 | 将哈希表 key 中的字段 field 的值设置为 value 。可以同时设置多个字段和值。 |
HGET | HGET key field | HGET user:1000 name | 获取哈希表 key 中给定字段 field 的值。 |
HGETALL | HGETALL key | HGETALL user:1000 | 获取哈希表 key 中的所有字段和值。 |
HDEL | HDEL key field [field ...] | HDEL user:1000 age | 删除哈希表 key 中的一个或多个指定字段。 |
HEXISTS | HEXISTS key field | HEXISTS user:1000 name | 检查哈希表 key 中,指定的字段是否存在。存在返回 1,不存在返回 0。 |
HLEN | HLEN key | HLEN user:1000 | 获取哈希表 key 中字段的数量。 |
HKEYS | HKEYS key | HKEYS user:1000 | 获取哈希表 key 中的所有字段。 |
HVALS | HVALS key | HVALS user:1000 | 获取哈希表 key 中的所有值。 |
HINCRBY | HINCRBY key field increment | HINCRBY user:1000 score 10 | 为哈希表 key 中的指定字段 field 的整数值加上增量 increment 。 |
列表(List)相关命令
列表是一个简单的字符串列表,按照插入顺序排序。
命令 | 语法 | 示例 | 说明 |
---|---|---|---|
LPUSH | LPUSH key value [value ...] | LPUSH mylist "a" "b" "c" | 将一个或多个值 value 插入到列表 key 的表头。 |
RPUSH | RPUSH key value [value ...] | RPUSH mylist "x" "y" "z" | 将一个或多个值 value 插入到列表 key 的表尾。 |
LPOP | LPOP key | LPOP mylist | 移除并返回列表 key 的头元素。 |
RPOP | RPOP key | RPOP mylist | 移除并返回列表 key 的尾元素。 |
LRANGE | LRANGE key start stop | LRANGE mylist 0 2 | 获取列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定(包含两端)。 |
LINDEX | LINDEX key index | LINDEX mylist 1 | 获取列表 key 中下标为 index 的元素。 |
LLEN | LLEN key | LLEN mylist | 获取列表 key 的长度。 |
LTRIM | LTRIM key start stop | LTRIM mylist 0 1 | 对一个列表进行修剪,只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 |
集合(Set)相关命令
集合是无序且不重复的字符串集合。
命令 | 语法 | 示例 | 说明 |
---|---|---|---|
SADD | SADD key member [member ...] | SADD myset "a" "b" "c" | 将一个或多个成员元素 member 添加到集合 key 中。 |
SMEMBERS | SMEMBERS key | SMEMBERS myset | 返回集合 key 中的所有成员。 |
SREM | SREM key member [member ...] | SREM myset "a" "b" | 移除集合 key 中的一个或多个成员元素。 |
SCARD | SCARD key | SCARD myset | 获取集合 key 的成员数。 |
SISMEMBER | SISMEMBER key member | SISMEMBER myset "a" | 判断成员元素 member 是否是集合 key 的成员。存在返回 1,不存在返回 0。 |
SINTER | SINTER key [key ...] | SINTER set1 set2 | 返回给定所有集合的交集。 |
SUNION | SUNION key [key ...] | SUNION set1 set2 | 返回给定所有集合的并集。 |
SDIFF | SDIFF key [key ...] | SDIFF set1 set2 | 返回给定所有集合的差集。 |
有序集合(Sorted Set)相关命令
有序集合和集合类似,但每个元素都关联一个分数(score),用于排序。
命令 | 语法 | 示例 | 说明 |
---|---|---|---|
ZADD | ZADD key score1 member1 [score2 member2 ...] | ZADD myzset 1 "a" 2 "b" 3 "c" | 将一个或多个成员元素 member 及其分数 score 添加到有序集合 key 中。 |
ZRANGE | ZRANGE key start stop [WITHSCORES] | ZRANGE myzset 0 2 WITHSCORES | 返回有序集合 key 中指定区间内的成员,按分数从小到大排序。WITHSCORES 选项表示同时返回成员的分数。 |
ZREVRANGE | ZREVRANGE key start stop [WITHSCORES] | ZREVRANGE myzset 0 2 WITHSCORES | 返回有序集合 key 中指定区间内的成员,按分数从大到小排序。 |
ZCARD | ZCARD key | ZCARD myzset | 获取有序集合 key 的成员数。 |
ZSCORE | ZSCORE key member | ZSCORE myzset "a" | 返回有序集合 key 中成员 member 的分数。 |
ZRANK | ZRANK key member | ZRANK myzset "b" | 返回有序集合 key 中成员 member 的排名(按分数从小到大排序,从 0 开始)。 |
ZREVRANK | ZREVRANK key member | ZREVRANK myzset "b" | 返回有序集合 key 中成员 member 的排名(按分数从大到小排序,从 0 开始)。 |
ZREM | ZREM key member [member ...] | ZREM myzset "a" "b" | 移除有序集合 key 中的一个或多个成员元素。 |
发布与订阅(Pub/Sub)相关命令
Redis 的发布与订阅功能允许客户端订阅频道,并接收发布到该频道的消息。
命令 | 语法 | 示例 | 说明 |
---|---|---|---|
SUBSCRIBE | SUBSCRIBE channel [channel ...] | SUBSCRIBE news.sport news.music | 订阅给定的一个或多个频道。 |
PUBLISH | PUBLISH channel message | PUBLISH news.sport "Hello world!" | 将消息 message 发布到指定的频道 channel 。 |
UNSUBSCRIBE | UNSUBSCRIBE [channel [channel ...]] | UNSUBSCRIBE news.sport | 取消订阅给定的一个或多个频道。如果不指定频道,则取消订阅所有频道。 |
PSUBSCRIBE | PSUBSCRIBE pattern [pattern ...] | PSUBSCRIBE news.* | 订阅与给定模式匹配的所有频道。 |
PUNSUBSCRIBE | PUNSUBSCRIBE [pattern [pattern ...]] | PUNSUBSCRIBE news.* | 取消订阅与给定模式匹配的所有频道。如果不指定模式,则取消订阅所有通过 PSUBSCRIBE 订阅的模式。 |
事务(Transaction)相关命令
Redis 事务允许将多个命令打包,然后一次性、按顺序地执行这些命令,且不会被其他客户端的命令打断。
命令 | 语法 | 示例 | 说明 |
---|---|---|---|
MULTI | MULTI | 标记一个事务块的开始。后续的命令将进入一个队列中,直到执行 EXEC 命令。 | |
EXEC | EXEC | 执行所有事务块内的命令。 | |
DISCARD | DISCARD | 取消事务,放弃执行事务块内的所有命令。 | |
WATCH | WATCH key [key ...] | WATCH mykey | 监视一个(或多个)键,如果在执行事务之前,被监视的键被其他客户端修改了,则整个事务将不会被执行。 |
UNWATCH | UNWATCH | 取消 WATCH 命令对所有键的监视。 |
持久化相关命令
Redis 提供了 RDB 和 AOF 两种持久化方式,以下是一些相关的命令。
命令 | 语法 | 示例 | 说明 |
---|---|---|---|
BGSAVE | BGSAVE | 在后台异步保存当前数据库的数据到磁盘(RDB 持久化)。 | |
SAVE | SAVE | 同步保存当前数据库的数据到磁盘(RDB 持久化)。在保存过程中会阻塞 Redis 服务器,直到保存完成。 | |
LASTSAVE | LASTSAVE | 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示。 | |
BGREWRITEAOF | BGREWRITEAOF | 在后台异步重写 AOF 文件。当 AOF 文件过大时,可以使用该命令来优化 AOF 文件的大小。 |
redis-benchmark测试工具
redis-benchmark 是官方自带的 Redis 性能测试工具,可以有效的测试Redis 服务的性能。基本的测试语法为 redis-benchmark [option] [optionvalue]。常用选项如下所示:
- -h:指定服务器主机名;
- -p:指定服务器端口;
- -s:指定服务器 socket;
- -c:指定并发连接数;
- -n:指定请求数;
- -d:以字节的形式指定SET/GET值的数据大小;
- -k:1=keep alive 0=reconnect;
- -r:SET/GET/INCR 使用随机 key,SADD 使用随机值;
- -P:通过管道传输<numreq>请求;
- -q:强制退出 redis。仅显示 query/sec 值;
- --csv:以 CSV 格式输出;
- -L(小写l 方便区分下面的i):生成循环,永久执行测试;
- -t:仅运行以逗号分隔的测试命令列表;
- -I:Idle 模式。仅打开 N个idle 连接并等待。
多数据库常用命令
Redis 支持多数据库,默认情况下包含 16 个数据库,数据库名称用数字 0 - 15 依次命名,多数据库相互独立、互不干扰。使用 redis-cli
连接 Redis 数据库后,默认使用序号为 0 的数据库,以下是一些多数据库常用命令:
数据库切换
SELECT <index>
:切换到指定索引的数据库。例如,SELECT 2
切换至序号为 2 的数据库;SELECT 15
切换至序号为 15 的数据库;SELECT 0
切换回序号为 0 的数据库。
多数据库间移动数据
MOVE key db
:将当前数据库的key
移动到数据库db
当中。若当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定key
,或者key
不存在于当前数据库,那么MOVE
没有任何效果。移动成功返回 1,失败则返回 0。
清除数据库内数据
FLUSHDB
:清空当前数据库数据。例如,在执行完相关操作后,使用该命令可清除当前所在数据库中的所有数据,但不会影响其他数据库。FLUSHALL
:清空所有数据库的数据,此命令需谨慎使用,因为它会删除 Redis 实例中所有数据库的数据。
Redis持久化
Redis持久化机制用于将内存中的数据保存到磁盘,以便在重启后恢复数据,主要包括RDB、AOF和混合持久化三种方式,以下为详细介绍:
RDB(Redis Database)持久化
-
原理:RDB是一种快照持久化方式,它通过定期将Redis内存中的数据集保存到磁盘上的一个二进制文件中(通常命名为dump.rdb)。这个文件是一个紧凑的二进制文件,包含了某个时间点的完整数据快照。当Redis重新启动时,它可以加载这个RDB文件,恢复到上次保存的时间点。
-
触发方式:
- 手动触发:通过SAVE和BGSAVE命令来实现。SAVE命令会阻塞主进程直到持久化操作完成,而BGSAVE命令则会创建一个子进程来执行持久化操作,主进程继续处理客户端请求。
- 自动触发:在配置文件中,可以通过save指令设置触发RDB持久化的条件,例如“save 900 1”“save 300 10”“save 60 10000”,分别表示在900秒内至少有1个键发生变化、300秒内至少有10个键发生变化或60秒内至少有10000个键发生变化时,Redis将生成一个新的RDB文件。
-
优点:
- 性能高效:RDB持久化是通过fork一个子进程来完成的,子进程负责将数据写入磁盘,而主进程继续处理客户端请求,因此对Redis的性能影响相对较小。
- 恢复速度快:由于RDB文件是二进制格式且包含完整的数据快照,因此在Redis重启时,加载RDB文件的速度非常快。
- 适合备份:RDB文件是紧凑的二进制文件,节省磁盘空间,非常适合用于备份和灾难恢复。
-
缺点:
- 数据丢失风险:如果Redis在两次生成RDB文件之间发生故障,这段时间内的数据将会丢失。
- CPU和I/O开销:生成RDB文件时,Redis需要进行大量数据的序列化和I/O操作,会对CPU和I/O资源造成一定的压力。
AOF(Append Only File)持久化
-
原理:AOF是一种日志持久化方式,它记录了服务器执行的所有写操作命令。这些命令会以追加的方式写入到AOF文件中,当Redis需要恢复数据时,只需执行AOF文件中的命令就可以恢复到原来的状态。
-
实现步骤:
- 命令追加:将Redis写操作命令追加到AOF缓冲区。
- 文件写入:周期性地将AOF缓冲区的命令写入AOF文件的内核缓冲区。
- 文件同步:根据配置的同步策略,将AOF文件缓冲区的内容同步到磁盘。Redis提供了三种文件同步策略:always(每次有命令写入时都立即同步)、everysec(每秒同步一次)、no(让操作系统决定最佳的同步时间)。
-
优点:
- 数据安全性高:AOF持久化记录了所有的写操作命令,因此可以提供更高的数据安全性,最多只丢失最后一次写操作的数据。
- 可读性强:AOF文件是文本格式,具有很好的可读性,方便查看和修改。
-
缺点:
- 文件体积大:由于AOF文件记录了所有的写操作命令,因此文件体积可能会比较大。
- 恢复速度慢:相比于RDB文件,AOF文件的恢复速度较慢,因为需要逐个执行文件中的命令。
混合持久化
- 原理:Redis 4.0之后支持RDB和AOF两种持久化机制混合使用。混合持久化结合了RDB和AOF的优点,既能够提供较快的恢复速度,又能够保证较高的数据安全性。在混合持久化模式下,Redis会生成一个包含RDB头和AOF尾的文件。当Redis重启时,会先加载RDB部分的数据,然后再执行AOF部分的命令来恢复数据。
- 优点:兼顾了RDB和AOF的优点,提高了数据的安全性和恢复速度。
- 缺点:配置相对复杂,需要合理设置相关参数。
AOF重写概述
AOF(Append Only File)重写是Redis中用于优化AOF持久化文件大小和性能的一种机制。随着Redis服务器不断运行,AOF文件会逐渐增大,因为文件记录了服务器处理的所有写操作命令。AOF重写通过创建一个新的AOF文件来替代原有的AOF文件,新文件包含恢复当前数据集所需的最少命令集合,从而减小文件体积,提高数据恢复效率。
AOF重写触发方式
1. 手动触发
使用BGREWRITEAOF
命令可以手动触发AOF重写操作。执行该命令后,Redis会fork一个子进程来执行重写任务,主进程继续处理客户端请求,不会阻塞Redis服务。例如,在Redis客户端中输入BGREWRITEAOF
并回车,即可启动AOF重写。
2. 自动触发
通过在Redis配置文件中设置相关参数,可以让Redis自动触发AOF重写。以下是两个关键参数:
auto-aof-rewrite-percentage
:该参数指定了触发AOF重写的AOF文件体积增长率阈值。默认值为100,表示当AOF文件当前体积比上次重写后的体积增长超过100%时,就会触发重写。例如,上次重写后AOF文件大小为100MB,当文件大小增长到200MB(100MB + 100% * 100MB)时,就可能触发重写。auto-aof-rewrite-min-size
:该参数指定了触发AOF重写的AOF文件最小体积阈值。默认值为64MB,表示只有当AOF文件体积大于64MB时,才会考虑触发重写。即使AOF文件体积增长率达到了auto-aof-rewrite-percentage
设定的阈值,但如果文件体积小于64MB,也不会触发重写。
AOF重写过程
- 子进程创建:Redis主进程接收到AOF重写请求后,会fork一个子进程。fork操作会创建一个与主进程内存状态相同的子进程,但子进程拥有独立的内存空间。
- 扫描数据并生成新AOF文件:子进程开始扫描Redis内存中的数据,并根据当前数据集生成一个新的AOF文件。在生成过程中,子进程会分析数据,将恢复当前数据集所需的最少命令写入新文件。例如,对于连续的多个
SET
命令设置同一个键的值,子进程只会保留最后一个SET
命令,因为前面的命令会被后面的命令覆盖。 - 信号通知与文件替换:子进程完成新AOF文件的生成后,会向主进程发送一个信号,通知主进程重写操作完成。主进程接收到信号后,会将一个临时文件重命名为最终的AOF文件,替换原有的AOF文件。
- 原子性写入:在重命名文件的过程中,Redis会使用原子性的操作来确保文件替换的安全性。这样可以避免在替换过程中出现数据丢失或损坏的情况。
AOF重写优点
- 减小文件体积:通过去除冗余命令,AOF重写可以显著减小AOF文件的体积,节省磁盘空间。例如,原本体积庞大的AOF文件经过重写后,可能只有原来的几分之一大小。
- 提高恢复速度:较小的AOF文件在Redis重启时加载速度更快,能够提高数据恢复的效率,减少系统停机时间。
- 降低I/O开销:由于AOF文件体积减小,在进行数据持久化和同步时,所需的I/O操作也会减少,从而降低了服务器的I/O开销,提高了整体性能。
AOF重写注意事项
- 资源消耗:AOF重写过程会消耗一定的CPU和内存资源,因为子进程需要扫描内存数据并生成新的AOF文件。在重写期间,Redis服务器的性能可能会受到一定影响,尤其是在数据量较大的情况下。因此,建议在系统负载较低的时候进行AOF重写,例如在业务低峰期。
- 数据一致性:虽然AOF重写过程中主进程仍然可以正常处理客户端请求,但在极端情况下(如服务器突然宕机),可能会存在少量的数据丢失风险。为了进一步提高数据安全性,可以结合RDB持久化方式使用。
- 配置优化:根据实际业务需求和数据增长情况,合理设置
auto-aof-rewrite-percentage
和auto-aof-rewrite-min-size
参数。如果参数设置不合理,可能会导致AOF重写过于频繁或不够及时,影响系统性能和数据安全性。
性能管理
在 Redis 的使用过程中,性能管理至关重要,它直接影响着系统的响应速度、吞吐量和稳定性。以下是 Redis 性能管理的主要方面及具体措施:
资源监控
- 监控指标
- 内存使用:监控 Redis 实例占用的内存大小,可使用
INFO memory
命令查看内存相关信息,如used_memory
(已用内存)、used_memory_peak
(峰值内存)等。若内存使用接近系统限制,可能导致数据被逐出或服务崩溃。 - CPU 使用率:通过系统工具(如
top
、htop
或vmstat
)或 Redis 的监控工具(如 RedisInsight)监控 CPU 使用率。高 CPU 使用率可能意味着 Redis 正在处理大量请求或执行复杂操作,影响性能。 - 网络带宽:监控 Redis 实例的网络流量,确保网络带宽足够支持数据的传输。可使用网络监控工具(如
iftop
、nload
)查看网络带宽使用情况。
- 内存使用:监控 Redis 实例占用的内存大小,可使用
- 监控工具
- Redis 内置命令:如
INFO
命令可获取 Redis 实例的全面信息,包括服务器状态、内存使用、客户端连接等;MONITOR
命令可实时查看 Redis 接收到的命令,用于调试和分析性能问题,但会对性能有一定影响,不建议在生产环境长期使用。 - 第三方监控工具:RedisInsight 提供图形化界面,可直观查看 Redis 的各项指标和性能数据;Prometheus + Grafana 组合可实现对 Redis 的全面监控和可视化展示,通过配置 Prometheus 的 exporter 采集 Redis 数据,再使用 Grafana 进行数据展示和告警设置。
- Redis 内置命令:如
性能调优
- 内存优化
- 选择合适的数据结构:根据业务需求选择最合适的数据结构。例如,使用
Hash
存储对象信息,比使用多个String
键值对更节省内存;使用Set
或ZSet
进行集合操作,可提高查询和排序效率。 - 合理设置内存淘汰策略:当内存不足时,Redis 会根据配置的淘汰策略选择要删除的键。常见的淘汰策略有
volatile-lru
(淘汰最近最少使用的设置了过期时间的键)、allkeys-lru
(淘汰最近最少使用的键)、volatile-ttl
(淘汰剩余生存时间最短的设置了过期时间的键)等。根据业务特点选择合适的淘汰策略,避免重要数据被误删。
- 选择合适的数据结构:根据业务需求选择最合适的数据结构。例如,使用
- 持久化配置
- RDB 持久化:调整
save
指令的参数,平衡数据安全性和性能。例如,减少保存频率可降低对性能的影响,但会增加数据丢失的风险。同时,合理设置rdbcompression
(是否对 RDB 文件进行压缩)和rdbchecksum
(是否对 RDB 文件进行校验),压缩可节省磁盘空间但会增加 CPU 开销,校验可保证数据完整性但也会增加一定的性能开销。 - AOF 持久化:选择合适的文件同步策略。
always
策略数据安全性最高,但性能影响最大;everysec
策略在性能和数据安全性之间取得了较好的平衡;no
策略性能最好,但数据安全性最低。此外,开启 AOF 重写功能,并合理设置auto-aof-rewrite-percentage
和auto-aof-rewrite-min-size
参数,可避免 AOF 文件过大影响性能。
- RDB 持久化:调整
- 网络优化
- 使用连接池:在客户端应用程序中使用连接池管理 Redis 连接,避免频繁创建和销毁连接带来的性能开销。连接池可以复用连接,提高连接的使用效率。
- 优化网络拓扑:将 Redis 实例部署在靠近客户端的位置,减少网络延迟。例如,对于分布式系统,可将 Redis 实例部署在与应用程序相同的机房或区域。
容量规划
- 数据增长预测:根据业务发展趋势和数据增长规律,预测 Redis 实例未来的数据增长情况。例如,分析历史数据,了解数据量的增长速度和趋势,为后续的容量规划提供依据。
- 资源扩容策略
- 垂直扩容:增加 Redis 实例所在服务器的 CPU、内存等资源。这种方式简单直接,但受限于单台服务器的硬件资源上限。
- 水平扩容:采用 Redis 集群的方式,将数据分散到多个节点上。Redis 集群提供了数据分片和自动故障转移等功能,可提高系统的可用性和性能。当数据量增长到一定程度时,水平扩容是更有效的解决方案。
性能测试与评估
- 测试工具
- redis-benchmark:Redis 自带的性能测试工具,可模拟多个客户端同时向 Redis 发送请求,测试 Redis 的性能指标,如每秒处理的请求数(QPS)、平均响应时间等。例如,使用
redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000
命令,模拟 100 个客户端并发发送 100000 个请求,测试 Redis 的性能。 - JMeter:一款功能强大的性能测试工具,支持多种协议和场景。可通过编写 JMeter 脚本,模拟复杂的业务场景对 Redis 进行性能测试。
- redis-benchmark:Redis 自带的性能测试工具,可模拟多个客户端同时向 Redis 发送请求,测试 Redis 的性能指标,如每秒处理的请求数(QPS)、平均响应时间等。例如,使用
- 评估指标
- 吞吐量:即每秒处理的请求数(QPS),反映了 Redis 的处理能力。通过性能测试,获取不同场景下的 QPS 值,评估 Redis 的性能是否满足业务需求。
- 响应时间:包括平均响应时间、最大响应时间和最小响应时间等。较短的响应时间意味着更好的用户体验。分析响应时间的分布情况,找出性能瓶颈。
- 错误率:统计测试过程中出现的错误请求数量和比例。高错误率可能表示 Redis 存在性能问题或配置不当。
故障排查与应急处理
- 常见故障排查
- 性能下降:检查内存使用、CPU 使用率、网络带宽等指标,分析是否存在资源瓶颈;查看 Redis 日志,寻找可能的错误信息和警告信息;使用
MONITOR
命令或慢查询日志(通过slowlog-log-slower-than
和slowlog-max-len
参数配置)查看是否有耗时较长的命令。 - 连接问题:检查客户端连接数是否达到上限(通过
maxclients
参数配置);查看网络连接状态,是否存在网络中断或延迟过高的情况。
- 性能下降:检查内存使用、CPU 使用率、网络带宽等指标,分析是否存在资源瓶颈;查看 Redis 日志,寻找可能的错误信息和警告信息;使用
- 应急处理措施
- 快速恢复服务:当 Redis 出现故障时,优先采取措施恢复服务,如重启 Redis 实例、切换到备用实例等。
- 数据恢复:如果数据丢失或损坏,根据持久化配置和备份策略进行数据恢复。例如,使用 RDB 文件或 AOF 文件进行数据恢复。
- 问题定位与解决:在恢复服务后,深入排查故障原因,采取相应的措施解决问题,避免类似故障再次发生。例如,优化性能配置、修复代码漏洞等。