Redis简明教程

关于Redis

Redis是一个开源的高性能key-value内存数据库,主要有以下三个特点:

安装Redis

CentOS7.5下安装Redis

下载redis并解压,这里最新稳定版为5.0.0:

# wget http://download.redis.io/releases/redis-5.0.0.tar.gz
# tar xzf redis-5.0.0.tar.gz
# cd redis-5.0.0

安装gcc:

# yum install gcc

编译安装:

# make MALLOC=libc
# cd src && make install

测试是否安装成功:

# ./redis-server

出现Redis启动信息表示安装成功,Ctrl + C退出测试。

设置Redis开机自启动,在/etc目录下新建redis目录:

# mkdir -p /etc/redis

redis.conf文件复制一份到/etc/redis目录下,并命名为6379.conf

# cp redis.conf /etc/redis/6379.conf

修改6379.conf,找到daemonize no一行,设置Redis为后台启动:

daemonize yes

将Redis的启动脚本复制一份到/etc/init.d目录下:

# cp utils/redis_init_script /etc/init.d/redisd

设置Redis开机自启动:

# cd /etc/init.d
# chkconfig redisd on

启动Redis:

# service redisd start

使用Docker安装Redis

如果会使用Docker的话,可以更方便快速地安装和体验Redis,只要下载一个Redis的镜像即可:

$ docker pull redis

启动容器,映射6379端口:

$ docker run -d --name redis -p 6379:6379 redis

Redis数据结构

Redis提供的5种基本结构:

字符串(String)

字符串的基本命令:

使用redis-cli与Redis进行交互:

$ redis-cli
127.0.0.1:6379> 

将键hello的值设置为world:

127.0.0.1:6379> set hello world
OK

获取存储在键hello中的值:

127.0.0.1:6379> get hello
"world"

删除键值对:

127.0.0.1:6379> del hello
(integer) 1

再次获取存储在键hello中的值:

127.0.0.1:6379> get hello
(nil)

列表(List)

列表的基本命令:

假设列表key为my-list,向列表分别推入值abc

127.0.0.1:6379> rpush my-list a
(integer) 1
127.0.0.1:6379> rpush my-list b
(integer) 2
127.0.0.1:6379> rpush my-list c
(integer) 3

获取列表所有值(0 -1 0为起始索引,-1为结束索引,表示取出所有值):

127.0.0.1:6379> lrange my-list 0 -1
1) "a"
2) "b"
3) "c"

获取列表中索引为1的值:

127.0.0.1:6379> lindex my-list 1
"b"

从列表中弹出一个元素,弹出的元素将不再存在于列表:

127.0.0.1:6379> lpop my-list
"a"
127.0.0.1:6379> lrange my-list 0 -1
1) "b"
2) "c"

哈希(Hash)

哈希的基本命令:

假设哈希表key为my-hash,分别向哈希表添加键值对:

127.0.0.1:6379> hset my-hash a 1
(integer) 1
127.0.0.1:6379> hset my-hash b 2
(integer) 1
127.0.0.1:6379> hset my-hash c 3
(integer) 1

获取键为a的值:

127.0.0.1:6379> hget my-hash a
"1"

获取哈希表所有键值对:

127.0.0.1:6379> hgetall my-hash
1) "a"
2) "1"
3) "b"
4) "2"
5) "c"
6) "3"

根据键删除键值对:

127.0.0.1:6379> hdel my-hash a
(integer) 1
127.0.0.1:6379> hgetall my-hash
1) "b"
2) "2"
3) "c"
4) "3"

集合(Set)

集合的基本命令:

集合和列表都可以存储多个字符串,区别在于:

假设集合key为my-set,向集合添加值:

127.0.0.1:6379> sadd my-set a
(integer) 1
127.0.0.1:6379> sadd my-set b
(integer) 2
127.0.0.1:6379> sadd my-set c
(integer) 3

重复添加值a

127.0.0.1:6379> sadd my-set a
(integer) 0

返回0表示这个元素已经存在于集合中,获取所有元素可以看到只有一个a

127.0.0.1:6379> smembers my-set
1) "a"
2) "b"
3) "c"

检查元素是否存在于集合中:

127.0.0.1:6379> sismember my-set d
(integer) 0
127.0.0.1:6379> sismember my-set a
(integer) 1

移除集合中的元素:

127.0.0.1:6379> srem my-set a
(integer) 1
127.0.0.1:6379> srem my-set a
(integer) 0
127.0.0.1:6379> smembers my-set
1) "b"
2) "c"

有序集合(Sorted set也叫Zset)

有序集合的基本命令:

有序集合与集合区别在于:

假设有序集合key为my-zset,向有序集合添加值,其中,1、2、3分别是a、b、c的分值:

127.0.0.1:6379> zadd my-zset 1 a
(integer) 1
127.0.0.1:6379> zadd my-zset 2 b
(integer) 1
127.0.0.1:6379> zadd my-zset 3 c
(integer) 1

获取有序集合的所有元素:

127.0.0.1:6379> zrange my-zset 0 -1
1) "a"
2) "b"
3) "c"

获取有序集合的所有元素,附上分值:

127.0.0.1:6379> zrange my-zset 0 -1 withscores
1) "a"
2) "1"
3) "b"
4) "2"
5) "c"
6) "3"

根据分值范围获取有序集合的元素,分值范围为0-10:

127.0.0.1:6379> zrangebyscore my-zset 0 10
1) "a"
2) "b"
3) "c"

同样可以附上分值:

127.0.0.1:6379> zrangebyscore my-zset 0 10 withscores
1) "a"
2) "1"
3) "b"
4) "2"
5) "c"
6) "3"

移除指定成员:

127.0.0.1:6379> zrem my-zset a
(integer) 1
127.0.0.1:6379> zrange my-zset 0 -1
1) "b"
2) "c"

HyperLogLog

HyperLogLog的基本命令:

Redis在2.8.9版本添加了HyperLogLog结构,用于做基数统计,即估算不重复元素的数量。

优点是只需要花费12KB内存,就可以计算接近2的64次方个不同元素的基数。

缺点是由于是估算,因此存在一定误差,而且不会存储元素本身,无法返回输入的各个元素。

HyperLogLog可以用在对精确性要求不是很高的场景,比如统计在线人数等等。

示例:

127.0.0.1:6379> pfadd my-hll a
(integer) 1
127.0.0.1:6379> pfadd my-hll b
(integer) 1
127.0.0.1:6379> pfcount my-hll
(integer) 2

设置数据过期时间

Redis支持为数据设置过期时间(单位:秒),并在过期后自动销毁数据.

示例,添加数据,并设置保留5秒:

127.0.0.1:6379> set my-key my-value
OK
127.0.0.1:6379> expire my-key 5
(integer) 1

5秒内获取:

127.0.0.1:6379> get my-key
"my-value"

5秒后获取:

127.0.0.1:6379> get my-key
(nil)

更多的命令

除了上面介绍的基本命令外,Redis还提供了许多命令来支持不同场景下的需求,详情可以查阅官方文档:

https://redis.io/commands

发布订阅

发布订阅的基本命令:

Redis发布订阅通过建立一个频道(channel),发布者(pub)发送消息,订阅者(sub)接收消息,实现发布者与订阅者之间的消息通信。

示例:

订阅频道my-channel :

127.0.0.1:6379> subscribe my-channel
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "my-channel"
3) (integer) 1

然后重新打开一个客户端,向频道my-channel发布一条消息:

127.0.0.1:6379> publish my-channel "hello"
(integer) 1

前面订阅者的客户端就会收到这条消息,如下:

127.0.0.1:6379> subscribe my-channel
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "my-channel"
3) (integer) 1
1) "message"
2) "my-channel"
3) "hello"

事务

事务的基本命令:

示例:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> sadd my-set a
QUEUED
127.0.0.1:6379> sadd my-set b
QUEUED
127.0.0.1:6379> smembers my-set
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
3) 1) "a"
   2) "b"

注意:

Redis的事务与关系型数据库事务有所不同,单条Redis命令是原子操作,但是Redis事务并不是原子操作,并且Redis事务没有回滚,只是批量执行命令而已。

因为Redis的设计目标是高性能,如果和关系型数据库一样,通过加锁来实现事务的原子操作,性能势必大打折扣,而通过WATCH命令,如果监视的key发生改变则事务执行失败,需要重新执行事务,这是乐观锁的做法,在实际使用中也能解决问题。

备份与恢复

使用save命令创建备份,会在Redis的安装目录下生成备份文件dump.rdb

127.0.0.1:6379> save
OK

Redis的安装目录可以通过以下命令获取到:

127.0.0.1:6379> config get dir
1) "dir"
2) "/data"

但是save命令会阻止所有其他客户端,所以通常使用另一个命令bgsave

27.0.0.1:6379> bgsave
Background saving started

使用bgsave备份会在后台执行,并且Redis会进行fork,父进程继续提供数据库服务,子进程将数据库保存到磁盘上。要检查备份是否完成,可以使用lastsave命令:

127.0.0.1:6379> lastsave
(integer) 1541486211

返回的是上次备份成功的UNIX时间戳。

性能测试

Redis提供了一个性能测试工具redis-benchmark用来检测性能:

模拟同时执行10000个请求:

$ redis-benchmark -n 10000 -q

PING_INLINE: 13698.63 requests per second
PING_BULK: 12870.01 requests per second
SET: 13333.33 requests per second
GET: 15220.70 requests per second
INCR: 11286.68 requests per second
LPUSH: 11614.40 requests per second
RPUSH: 11415.53 requests per second
LPOP: 13037.81 requests per second
RPOP: 15649.45 requests per second
SADD: 13054.83 requests per second
HSET: 13550.14 requests per second
SPOP: 13333.33 requests per second
LPUSH (needed to benchmark LRANGE): 13531.80 requests per second
LRANGE_100 (first 100 elements): 10162.60 requests per second
LRANGE_300 (first 300 elements): 5672.15 requests per second
LRANGE_500 (first 450 elements): 3952.57 requests per second
LRANGE_600 (first 600 elements): 3271.18 requests per second
MSET (10 keys): 9891.20 requests per second

仅测试GETRPUSH命令的性能:

$ redis-benchmark -h 127.0.0.1 -p 6379 -t get,rpush -n 10000 -q

GET: 16666.67 requests per second
RPUSH: 15337.42 requests per second
127.0.0.1:6379> save
OK

搭建主从复制

假设,主服务器的地址为172.17.0.3:6379,从服务器的地址为172.17.0.4:6379

首先,需要保证主从服务器可以互联对方,至少应检查以下配置:

  1. 检查防火墙,如果影响主从互联则关闭。

  2. 检查Redis配置,确保绑定IP配置不为bind 127.0.0.1,否则只能从本地访问Redis,我们可以:
    • 注释掉该配置,默认为可任意访问
    • 或者配置为bind 0.0.0.0(可任意访问)
    • 或者配置绑定一个可访问的IP地址。
  3. 检查Redis配置,确保protected-mode不会被启用,否则只能从本地访问Redis,protected-mode的启用条件有两个,1)没有绑定IP 2)没有设置访问密码,我们可以:
    • 编辑该配置为protected-mode no
    • 或者配置绑定一个可访问的IP地址
    • 或者设置一个Redis访问密码

确认主从服务器可以互联后,我们在从服务器上建立主从复制关系,有3种方式:

3种方式任选其一,即可完成主从复制的搭建。

Redis从5.0.0版本起,改用replicaof,但salveof仍向后兼容。

查看主从复制状态:

127.0.0.1:6379> info replication

断开复制:

127.0.0.1:6379> slaveof no one

主从自动切换(哨兵机制)

Redis的Sentinel系统用于管理多个Redis服务器(instance),该系统执行以下三个任务:

创建并编辑配置文件sentinel.conf

port 26379
sentinel monitor mymaster 172.17.0.3 6379 1
sentinel auth-pass mymaster password

第二行配置表示监控一个名为mymaster的主服务器,IP地址为172.17.0.3,端口号为6379,而将这个主服务器判断为失效至少需要1个Sentinel同意(本示例从简,只使用了一个Sentinel,所以设置成1,一般使用3个Sentinel至少需要2个同意,5个至少3个同意,以此类推)。

Sentinel会根据主服务器配置找到从服务器,因此只需要配置主服务器即可。

第三行配置的password是访问172.17.0.3的Redis密码。

启动sentinel服务:

$ redis-server sentinel.conf --sentinel

之后,如果主服务器发生故障,Sentinel就会监控到,并自动进行主从切换。

参考文档

《Redis实战》

http://www.runoob.com/redis/redis-tutorial.html

https://www.cnblogs.com/zuidongfeng/p/8032505.html

http://redis.cn/documentation.html

Table of Contents