Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。

Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。

Redis官网:
https://redis.io/

Redis特点总结:

  • Redis和Memcached类似,也属于k-v数据存储
  • 支持更多value类型,除了和string外,还支持hash、lists(链表)、sets(集合)和sorted sets(有序集合)
  • redis使用了两种文件格式:全量数据(RDB)和增量请求(aof)。全量数据格式是把内存中的数据写入磁盘,便于下次读取文件进行加载。增量请求文件则是把内存中的数据序列化为操作请求,用于读取文件进行replay得到数据,这种类似于mysql binlog。
  • redis的存储分为内存存储、磁盘存储和log文件三部分

redis安装

下载、解包、编译安装,素质三连:

[root@localhost ~]# cd /usr/local/src/
[root@localhost /usr/local/src]# wget http://download.redis.io/releases/redis-4.0.1.tar.gz
[root@localhost /usr/local/src]# tar -zxvf redis-4.0.1.tar.gz
[root@localhost /usr/local/src]# cd redis-4.0.1/
[root@localhost /usr/local/src/redis-4.0.1]# make && make install
[root@localhost /usr/local/src/redis-4.0.1]# echo $?
0
[root@localhost /usr/local/src/redis-4.0.1]# redis-   # 按两下tap键,出来以下命令代表安装成功
redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli        redis-sentinel   redis-server     
[root@localhost /usr/local/src/redis-4.0.1]#

拷贝配置文件:

[root@localhost /usr/local/src/redis-4.0.1]# cp redis.conf /etc/redis.conf

编辑配置文件内容:

[root@localhost /usr/local/src/redis-4.0.1]# vim /etc/redis.conf   # 修改如下配置
daemonize yes   # 设置Redis为后台启动
logfile "/var/log/redis.log"   # 定义日志文件的存储路径
dir /data/redis_data/  # 定义数据存储文件的路径
appendonly yes  # 开启aof存储日志

创建数据存储文件的目录:

mkdir /data/redis_data/

启动redis服务:

[root@localhost ~]# redis-server /etc/redis.conf 
[root@localhost ~]# ps aux |grep redis
root       6208  0.1  0.4 145244  7524 ?        Ssl  17:12   0:00 redis-server 127.0.0.1:6379
root       6213  0.0  0.0 112668   972 pts/0    S+   17:12   0:00 grep --color=auto redis
[root@localhost ~]# netstat -lntp |grep redis
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      6208/redis-server 1 
[root@localhost ~]# 

查看redis日志:

[root@localhost ~]# less /var/log/redis.log
6208:M 29 Dec 17:12:21.918 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
6208:M 29 Dec 17:12:21.918 # Server initialized
6208:M 29 Dec 17:12:21.918 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit
_memory=1' for this to take effect.
6208:M 29 Dec 17:12:21.918 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create
 latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hug
epage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be resta
rted after THP is disabled.
6208:M 29 Dec 17:12:21.918 * Ready to accept connections

可以看到日志文件中有两个警告:

WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.
这个警告意思是背景保存可能在低内存条件下失败
WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis.
意思是“您的内核中启用了透明的大型页面(THP)支持。这将导致Redis的延迟和内存使用问题。”

所以我们需要修改一下这两个内核参数:

[root@localhost ~]# sysctl vm.overcommit_memory=1
vm.overcommit_memory = 1
[root@localhost ~]# echo never > /sys/kernel/mm/transparent_hugepage/enabled
[root@localhost ~]#

最后把这两条命令放到 /etc/rc.local 里,让服务器一启动就执行这两条命令:

[root@localhost ~]# vim /etc/rc.local
sysctl vm.overcommit_memory=1
echo never > /sys/kernel/mm/transparent_hugepage/enabled

redis持久化

Redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File),如果关闭持久化,数据就完全存在内存中。如果你没有数据持久化的需求,也完全可以关闭RDB和AOF方式,这样的话,redis将变成一个纯内存数据库,就像memcache一样。

  • RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上。
  • AOF,则是换了一个角度来实现持久化,那就是将redis执行过的所有写指令记录下来,在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。

其实RDB和AOF两种方式也可以同时使用,在这种情况下,如果redis重启的话,则会优先采用AOF方式来进行数据恢复,这是因为AOF方式的数据恢复完整度更高。有一点要注意的是:由于AOF会记录全部的指令,没有去做优化的话指令就会随着日积月累越积越多,甚至达到上百G,而且那些数据已经过期的也会被记录着,所以最好是定时就去删除一些过期的数据的写入指令,以达到优化的目的。

以下是Redis持久化相关参数,在 /etc/redis.conf 里可以修改这些参数,一般默认即可:

  • save 900 1 #表示每15分钟(900秒)且至少有1个key改变,就触发一次持久化
  • save 300 10 #表示每5分钟(300秒)且至少有10个key改变,就触发一次持久化
  • save 60 10000 #表示每60秒至少有10000个key改变,就触发一次持久
  • save "" #这样可以禁用rdb持久化
  • appendonly yes #如果是yes,则开启aof持久化
  • appendfilename “appendonly.aof” # 指定aof文件名字
  • appendfsync everysec #指定fsync()调用模式,有三种no(不调用fsync),always(每次写都会调用fsync),everysec(每秒钟调用一次fsync)。第一种最快,第二种数据最安全,但性能会差一些,第三种为这种方案,默认为第三种。

redis数据类型

1.string类型:
string为最简单的类型,与Memcached一样的类型,一个key对应一个value,其支持的操作与Memcached的操作类似,它的功能更丰富。设置可以存二进制的对象。
进入redis命令行的命令如下:

[root@localhost ~]# redis-cli
127.0.0.1:6379>

string类型使用示例:

[root@localhost ~]# redis-cli
127.0.0.1:6379> set mykey "hello world"  # 使用双引号来表示这个value是string类型的
OK
127.0.0.1:6379> get mykey  # 得到键的值
"hello world"
127.0.0.1:6379> mset k1 1 k2 2 k3 3  # 使用mset可以设置多个键/值
OK
127.0.0.1:6379> mget k1 k2 k3   # 相对的使用mget可以得到多个键的值
1) "1"
2) "2"
3) "3"
127.0.0.1:6379>

提示:在redis命令行中也可以使用tap键来补全命令,而且redis的命令并不区分大小写,和mysql一样。

2.list类型:
list是一个链表结构,主要功能是push、pop、获取一个范围的所有值等等,如果有学习过编程语言的话就会很好理解这种数据类型。操作中key理解为链表的名字。使用 list 结构,我们可以轻松地实现最新消息排行等功能(比如新浪微博的 TimeLine )。list 的另一个应用就是消息队列,可以利用 list 的 push操作,将任务存在 list 中,然后工作线程再用pop操作将任务取出进行执行。这个链表和堆栈一样,存在先进后出,后进先出的概念。

list类型使用示例:

127.0.0.1:6379> lpush list1 "hello world"  # list1是链表的名字,可以把它当做是一个集合或数组
(integer) 1
127.0.0.1:6379> lpush list1 "data"   # 链表中可以存储多个元素
(integer) 2
127.0.0.1:6379> lpush list1 "emmmm..."
(integer) 3
127.0.0.1:6379> lrange list1 0 -1  # lrange可以显示链表的值域,0表示一个元素,-1表示最后一个元素,结合起来就是第一个到最后一个的范围,所以通过这两个下标或者说索引,就可以显示出链表中的全部数据
1) "emmmm..."  # 因为有堆栈的先进后出概念,所以"hello world"会在排在最后面显示
2) "data"
3) "hello world"
127.0.0.1:6379> lrange list1 0 2  # 因为下标是从0开始,而链表中的元素只有三个,所以0-2这个范围就可以显示出链表中的全部数据
1) "emmmm..."
2) "data"
3) "hello world"
127.0.0.1:6379> lrange list1 0 1  # 同理0-1就只能显示两个元素
1) "emmmm..."
2) "data"
127.0.0.1:6379> lpop list1    # lpop是拿出链表中的元素,注意是拿出,拿出之后链表中就不会有这个元素了
"emmmm..."
127.0.0.1:6379> lrange list1 0 -1  # 元素被拿出后,就不会再存储在链表中
1) "data"
2) "hello world"
127.0.0.1:6379>

3.set类型:
set是集合,和我们数学中的集合概念相似,对集合的操作有添加删除元素,有对多个集合求交并差等操作。操作中key理解为集合的名字。比如在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。因为 Redis 非常人性化的为集合提供了求交集、并集、差集等操作,那么就可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端或者是存集到一个新的集合中。

set类型使用示例:

127.0.0.1:6379> sadd set1 a  # 添加一个集合,集合的名称是set1,a是该集合的元素
(integer) 1
127.0.0.1:6379> sadd set1 b  # 添加一个元素b到set1集合中,注意是添加,不会覆盖原有的元素
(integer) 1
127.0.0.1:6379> sadd set1 c
(integer) 1
127.0.0.1:6379> sadd set1 d e f g h  # 可以一次添加多个元素
(integer) 5
127.0.0.1:6379> SMEMBERS set1  # 显示set1里的全部元素
1) "f"
2) "c"
3) "h"
4) "d"
5) "b"
6) "g"
7) "e"
8) "a"
127.0.0.1:6379>

以上介绍set时,提到了该类型与数学中的集合概念类似,也可以求交集、差集、并集等。
下面示例演示如何求并集,求并集就是去掉两个集合中相同的元素,简单来说就是去重:

127.0.0.1:6379> sadd set2 a b c 1 2 3  # 添加一个集合,该集合中有与set1集合相同的元素
(integer) 6
127.0.0.1:6379> SUNION set1 set2  # 使用SUNION命令求两个集合中的并集
 1) "a"
 2) "1"
 3) "2"
 4) "h"
 5) "3"
 6) "f"
 7) "c"
 8) "d"
 9) "b"
10) "g"
11) "e"
127.0.0.1:6379>

求交集示例:
求交集就是把两个集合中相同的元素打印出来

127.0.0.1:6379> SINTER set1 set2  # 使用SINTER命令求两个集合中的交集
1) "c"
2) "a"
3) "b"
127.0.0.1:6379>

求差集示例:
求差集就是打印集合A中有的元素,而集合B中没有的元素

127.0.0.1:6379> SDIFF set1 set2
1) "f"
2) "g"
3) "d"
4) "h"
5) "e"
127.0.0.1:6379>

删除元素示例:

127.0.0.1:6379> SREM set1 a  # 删除set集合中的元素a
(integer) 1
127.0.0.1:6379> SMEMBERS set1
1) "f"
2) "c"
3) "h"
4) "d"
5) "b"
6) "g"
7) "e"
127.0.0.1:6379> SREM set1 b c d e  # 可以删除多个元素
(integer) 4
127.0.0.1:6379> SMEMBERS set1
1) "f"
2) "h"
3) "g"
127.0.0.1:6379>

4.sort set类型:
sorted set是有序集合,它比set多了一个权重参数score,使得集合中的元素能够按 score 进行有序排列,比如一个存储全班同学成绩的 Sorted Sets,其集合 value 可以是同学的学号,而 score 就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序

sorted set类型使用示例:

127.0.0.1:6379> zadd set3 12 "twelve" # 添加一个名称为set3的一个有序集合,名称后面跟的是权重参数score,"twelve"则是元素
(integer) 1
127.0.0.1:6379> zadd set3 1 "one"
(integer) 1
127.0.0.1:6379> zadd set3 5 "five five2"
(integer) 1
127.0.0.1:6379> ZRANGE set3 0 -1  # 可以看到打印出来的结果有按照权重参数排序
1) "one"
2) "five five2"
3) "twelve"
127.0.0.1:6379> ZREVRANGE set3 0 -1  # ZREVRANGE 命令可以进行倒序排序
1) "twelve"
2) "five five2"
3) "one"
127.0.0.1:6379>

5.hash类型:
在 Memcached 中,我们会经常将一些结构化的信息打包成 hashmap,这是一种键/值对结构的集合,在客户端序列化后存储为一个字符串的值(一般是 JSON 格式),比如用户的昵称、年龄、性别、积分等。

hash类型使用示例:

127.0.0.1:6379> HSET hash1 name zero  # 添加一个名称为hash1的hash集合,name是键,zero是值
(integer) 1
127.0.0.1:6379> HSET hash1 age 30
(integer) 1
127.0.0.1:6379> HSET hash1 job it
(integer) 1
127.0.0.1:6379> HGET hash1 name  # 按键来拿值
"zero"
127.0.0.1:6379> HGET hash1 age
"30"
127.0.0.1:6379> HGET hash1 job
"it"
127.0.0.1:6379> HGETALL hash1  # 打印集合中所有的元素,奇数行是key,偶数行是value
1) "name"
2) "zero"
3) "age"
4) "30"
5) "job"
6) "it"
127.0.0.1:6379>