Redis基础
一、简介
Redis是一个完全开源免费的高性能key-value数据库
- Redis支持将数据持久化到硬盘上,在重启时可以再次加载使用,不像Memcached断电后数据丢失;
- Redis的数据类型丰富,包括:String、list、set、zset(有序集合)、hash;
- Redis支持master-slave(主从备份)模式的备份;
- Redis单机使用单线程模式运行,所有的命令都在队列中等待执行
二、数据类型
Redis支持五中数据类型:String(字符串)、list(列表)、set(集合)、zset(有序集合)、hash(哈希)
1. String(字符串)
字符串是Redis最基本的数据类型,且是二进制安全的,所以可以存储任何数据,一个键值对最大存储512MB;
redis 127.0.0.1:6379> SET name "rambo"
OK
redis 127.0.0.1:6379> GET name
"rambo"
大部分情况在使用Redis时,都是将对象序列化String,进行存储。
2. Hash(哈希)
Redis的Hash是一个键值对的集合,将对象存储在Redis中十分简单。
127.0.0.1:6379> HMSET user username runoob password runoob points 200
OK
127.0.0.1:6379> HGETALL user
1) "username"
2) "runoob"
3) "password"
4) "runoob"
5) "points"
6) "200"
“user”是这个hash的name,通过这个name来获取该hash的value。
3. List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(lpush)或者尾部(rpush);从头部移除并获取列表的第一个元素(lpop)。
4. Set(集合)
Redis的Set是string类型的无序集合。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
5. ZSET(有序集合)
zadd 命令:zadd key score member
添加元素到集合,元素在集合中存在则更新对应score
三、Redis命令
参见Redis 命令
高级特性
一、持久化&&主从复制
持久化
Redis的持久化有两种方式:RDB(内存快照)和AOF(文件追加)
1. RDB
该持久化方式能够在指定的时间间隔对数据进行快照存储,默认情况下,存储在”dump.rdb”的二进制文件中。
触发方式有两种:
- 自动保存:设置触发条件”N秒内数据集至少有M个改动”,如
save 60 1000
,即表示 满足60 秒内有至少有 1000 个键被改动
,这一条件时, 自动保存一次数据集 - 手动保存:客户端调用SAVE或BGSAVE进行同步/异步保存。
工作方式:
当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:
- Redis 调用forks. 同时拥有父进程和子进程。
- 子进程将数据集写入到一个临时 RDB 文件中。
- 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
这种工作方式使得Redis可以从写时复制(copy-on-write)机制中获益。
RDB的优缺点如下:
- 优点
- RDB文件紧凑,非常适用于数据集的备份,指定的时间间隔进行备份,可以有不同时间版本的数据集用于数据恢复;
- RDB文件是单一的,方便进行多端传输,进行灾备;
- 备份文件的工作由父进程fork的子进程来进行,可以最大化性能;
- 相比AOF,RDB在恢复大的数据集时,速度更快。
- 缺点
- 由于RDB是在指定的时间间隔进行快照,所以在Redis意外停止工作的时候,会丢失几分钟的数据
- RDB需要经常fork子进程来对内存进行快照存储,当数据集较大的时候,fork的过程是非常耗时的,同时,fork的子进程需要和父进程一样的内存来存储相应的数据集。所以,耗时导致父进程对客户端的响应延时,内存消耗导致成本提高。
这种持久化方式被称为快照 snapshotting。
2. AOF
该方式记录每次对服务端写的操作,以Redis协议将写操作追加到AOF文件末尾,由于每次写命令都会被记录,所以AOF的文件的体积通常较大,可以使用
BGREWRITEAOF
命令重写AOF文件,去除重复无用的命令。
开启AOF的方式:appendonly yes
,在配置文件redis.conf中。
追加的频次:
- 每次有新命令追加到AOF文件时都进行一次fsync:非常慢&安全;
- 每秒进行一次fsync:足够快,发生故障时只丢失1S的数据,推荐用法;
- 从不fsync:将数据交给操作系统来处理,更快、更不安全。
工作方式:
AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:
- Redis 执行 fork() ,现在同时拥有父进程和子进程。
- 子进程开始将新 AOF 文件的内容写入到临时文件。
- 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
- 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
- 搞定!现在 Redis原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。
优缺点:
- 优点
- 不同的fsync策略使Redis更加耐久;
- AOF文件可以使用
redis-check-aof
工具来修复某些原因导致的文件问题; - Redis可以自动地调用
BGREWRITEAOF
命令来重写AOF文件以减少其体积,在重写过程中文件是绝对安全的; - AOF文件简单易懂。
- 缺点
- 相同数据集的AOF文件大于RDB文件;
- 根据所选择的fsync策略,AOF的速度可能慢于RDB。
主从复制、读写分离
Redis复制很简单易用,它通过配置
slaveof ip port
将一台Redis实例设置成某台实例的从服务器
特点如下:
- 一个Master可以有多个Slaves。
- Slaves能过接口其他slave的链接,除了可以接受同一个master下面slaves的链接以外,还可以接受同一个结构图中的其他slaves的链接。
- redis复制是在master段是非阻塞的,这就意味着master在同一个或多个slave端执行同步的时候还可以接受查询。
- 复制在slave端也是非阻塞的,假设你在redis.conf中配置redis这个功能,当slave在执行的新的同步时,它仍可以用旧的数据信息来提供查询,否则,你可以配置当redis slaves去master失去联系是,slave会给发送一个客户端错误。
- 为了有多个slaves可以做只读查询,复制可以重复2次,甚至多次,具有可扩展性(例如:slaves对话与重复的排序操作,有多份数据冗余就相对简单了)。
- 通过复制可以避免master全量写硬盘的消耗:只要配置 master的配置文件redis.conf来“避免保存”(注释掉所有”save”命令),然后连接一个用来持久化数据的slave即可。
配置方式
- 在配置文件或启动时:
slaveof ip port
- 密码验证:
masterauth <password>
工作方式
- Slave在连接到Master上时,会发送一个Sync命令,然后Master开始后台保存,收集所有对修改数据的命令;
- 当后台保存完成,Master会将这个数据文件(
AOF?RDB?
)传送到Slave,然后Slave保存在磁盘,加载到内存中; - Master接着发送给Slave收集到的所有的修改数据的命令(
缓存在缓冲区
),这好比一个流命令,是Redis协议本身来实现的。
当配置了从节点后,可以使从节点负责客户端的读服务,主节点专注于写服务,从而提高实例的响应性能。
二、Redis集群&&哨兵
三、事务&&分布式锁
Redis事务
事务的四大特性:ACID,原子性,一致性,隔离性,持久性。
Redis事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
Redis原子性:
- Redis单机服务是单进程运行,所有的命令都需要入队列排队等待执行,所以同一时刻只有一个命令在执行;
- Redis的基础命令都是原子性的;
- Redis可以使用
MULTI
和EXEC
命令来组装一组原子性操作的命令,MULTI
用来开启一个事务,EXEC
用来执行该事务。
用法:
- MULTI 命令用于开启一个事务,它总是返回 OK 。
- MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC命令被调用时, 所有队列中的命令才会被执行。
- 另一方面, 通过调用 DISCARD , 客户端可以清空事务队列, 并放弃执行事务。
Redis的事务不支持错误回滚,事务队列中失败的命令会返回错误信息,只执行成功的命令。
利用Redis实现分布式锁
我们可以使用Redis实现分布式锁,利用原子操作SETNX
实现自旋锁,参见SETNX key value
因为Redis的
SETNX
命令是原子性的,可以根据此命令设置一个公共的key,所以节点在操作临界区数据前先自旋地调用该命令,如果返回成功则进入临界区,否则自旋。
问题和优化:
- 获得锁的进程挂掉了,没有释放锁,导致其他进程不断自旋:设置key的超时时间,超时后自动释放锁
SETNX
和EXPIRE
非原子性操作:LUA脚本将其原子化
目前并没有更加优雅的处理方式去解决进程挂掉的问题。
四、其他
- 管道
参见:Redis 管道技术 - 发布&订阅
参见发布&订阅