Redis基础与持久化

Redis介绍

软件说明

Redis是一款开源的,ANSI C语言编写的,高级键值(key-value)缓存和支持永久存储NoSQL数据库产品。
Redis采用内存(In-Memory)数据集(DataSet) 。
支持多种数据类型。
运行于大多数POSIX系统,如Linux、*BSD、OS X等。
做者: Salvatore Sanfilipporedis

软件特性

1)透明性:分布式系统对用户来讲是透明的,一个分布式系统在用户面前的表现就像一个传统的单处理机分时系统,可以让用户没必要了解内部结构就可使用。
2)扩展性:分布式系统的最大特色就是可扩展性,他能够根据需求的增长而扩展,能够经过横向扩展使集群的总体性能获得线性提高,也能够经过纵向扩展单台服务器的性能使服务器集群的性能获得提高。
3)可靠性:分布式系统不容许单点失效的问题存在,它的基本思想是:若是一台服务器坏了,其余服务器接替它的工做,具备持续服务的特性。
4)高性能:高性能是人们设计分布式系统的一个初衷,若是创建了一个透明,灵活,可靠的分布式系统,但他运行起来像蜗牛同样慢,那这个系统就是失败的。数据库

软件功能

1)高速读写
2)数据类型丰富
3)支持持久化
4)多种内存分配及回收策略
5)支持事物
6)消息队列、消息订阅
7)支持高可用
8)支持分布式分片集群vim

Redis安装部署

#下载
[root@db01 src]# wget http://download.redis.io/releases/redis-3.2.12.tar.gz
#解压
[root@db01 src]# tar xf redis-3.2.12.tar.gz
#移动到指定目录
[root@db01 src]# mv redis-3.2.12 /application/
#作软连接
[root@db01 src]# ln -s /application/redis-3.2.12 /application/redis
#进入redis目录
[root@db01 src]# cd /application/redis
#编译
[root@db01 redis]# make
#添加环境变量
[root@db01 redis]# vim /etc/profile.d/redis.sh
export PATH="/application/redis/src:$PATH"
#启动redis
[root@db01 redis]# src/redis-server &
#链接redis
[root@db01 redis]# redis-cli
#退出redis
127.0.0.1:6379> quit
#关闭redis链接
[root@db01 redis]# redis-cli
127.0.0.1:6379> shutdown

基本配置

#建立redis工做目录
[root@db01 redis]# mkdir -p /etc/redis/6379
#建立redis配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
daemonize yes   //守护进程模式启动
port 6379       //端口
logfile /etc/redis/6379/redis.log   //日志文件位置
dir /etc/redis/6379     //持久化数据文件存储位置
dbfilename dump.rdb     //RDB持久化数据文件名称
#指定配置文件启动redis
[root@db01 redis]# redis-server /etc/redis/6379/redis.conf

基本操做

#链接redis
[root@db01 redis]# redis-cli
#设置键值对
127.0.0.1:6379> set foo bar
OK
#取出值
127.0.0.1:6379> get foo
"bar"

安全配置

protected-mode: 禁止protected-mode yes/no(保护模式,是否只运行本地访问)
bind: 指定监听缓存

# 添加到配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
bind 127.0.0.1 10.0.0.51
requirepass  123

auth {password}: 在redis-cli中使用,进行认证安全

#不加认证,报错
[root@db01 redis]# redis-cli
127.0.0.1:6379> set name zhangsan
(error) NOAUTH Authentication required.
#链接方式1
[root@db01 redis]# redis-cli
127.0.0.1:6379> AUTH zls
127.0.0.1:6379> set name zhangsan
OK
#链接方式2
[root@db01 redis]# redis-cli -a zls
127.0.0.1:6379> set name lisi
OK

在线查看和修改配置

#查看配置文件中的监听地址
127.0.0.1:6379> CONFIG GET bind
1) "bind"
2) "127.0.0.1 10.0.0.51"

#查看dir
127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/etc/redis/6379"

#查看全部配置
127.0.0.1:6379> CONFIG GET *

#修改配置,即时生效
127.0.0.1:6379> CONFIG SET requirepass 123
OK

#测试修改后链接
[root@db01 redis]# redis-cli -a 123
127.0.0.1:6379> set age 18
OK

#查看配置文件
[root@db01 redis]# cat /etc/redis/6379/redis.conf
daemonize yes
port 6379
logfile /etc/redis/6379/redis.log
dir /etc/redis/6379
dbfilename dump.rdb
bind 127.0.0.1 10.0.0.51
requirepass  zls        //能够看出,配置文件中是没有改变的,只要redis不重启,密码就是新改的

Redis持久化

什么是持久化?
持久化::就是将内存中的数据,写入到磁盘上,并永久存在的.bash

RDB持久化介绍

能够在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)
RDB持久化优势:
1) RDB是一种表示某个即时点的Redis数据的紧凑文件.RDB文件适合用于备份.例如,能够每小时归档最近24小时的RDB文件,天天保存近30天的RDB快照.
这容许你很容易的恢复不一样版本的数据集以容灾.
2) RDB很是适合用于灾难恢复,做为一个紧凑的单一文件,能够被传输到远程的数据中心.
3) RDB最大化了Redis的性能,由于Redis父进程持久化是惟一须要作的是启动(fork)一个子进程,因为子进程完成全部剩余工做.父进程实例不须要执行像磁盘IO这样的操做.
RDB持久化缺点:
1) 当你须要Redis中止工做,(例如停电)是最小化数据丢失,RDB可能不太好.你能够配置不经过的保存点(save point)来保存RDB文件(例如, 至少5分钟和对数进行100次后,可是你能够有多个保存点.然而,你一般每隔5分钟或更久建立一个RDB快照,因此一旦Redis由于任何缘由没有正确关闭或中止工做,你就得作好最近几分钟数据丢失的准备了.
2) RDB须要进程调用fork()子进程来持久化到磁盘. 若是数据集很大的haul,fork()比较好使, 结果就是, 当数据集很是大而且CPU性能不够强大的化,Redis会中止服务客户端几毫秒甚至一秒. AOF也须要fork(),可是你能够调整多久评率重写日志而不会有损(trade-off)持久(durability).
RDB持久化优缺点总结
优势:速度快,适合于用做备份,主从复制也是基于RDB持久化功能实现的。
缺点:会有数据丢失、致使服务中止几秒
服务器

RDB持久化核心配置参数

#编辑配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
#持久化数据文件存储位置
dir /etc/redis/6379
#rdb持久化数据文件名
dbfilename dump.rdb
#900秒(15分钟)内有1个更改
save 900 1
#300秒(5分钟)内有10个更改
save 300 10
#60秒(1分钟)内有10000个更改
save 60 10000

AOF 持久化介绍

AOF(append only file)只追加文件,记录服务器执行的全部写操做命令,并在服务器启动时,经过从新执行这些命令来还原数据集。 AOF 文件中的命令所有以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。
AOF 持久化优势:
1)使用AOF Redis会更具备可持久性(durable):你能够有不少不一样的fsync策略:没有fsync,每秒fsync,每次请求时fsync。使用默认的每秒fsync策略,写性能也仍然很不错(fsync是由后台线程完成的,主线程继续努力地执行写请求),即使你也就仅仅只损失一秒钟的写数据。
2)AOF日志是一个追加文件,因此不须要定位,在断电时也没有损坏问题。即便因为某种缘由文件末尾是一个写到一半的命令(磁盘满或者其余缘由),redis-check-aof工具也能够很轻易的修复。
3)当AOF文件变得很大时,Redis会自动在后台进行重写。重写是绝对安全的,由于Redis继续往旧的文件中追加,使用建立当前数据集所需的最小操做集合来建立一个全新的文件,一旦第二个文件建立完毕,Redis就会切换这两个文件,并开始往新文件追加。
4)AOF文件里面包含一个接一个的操做,以易于理解和解析的格式存储。你也能够轻易的导出一个AOF文件。例如,即便你不当心错误地使用FLUSHALL命令清空一切,若是此时并无执行重写,你仍然能够保存你的数据集,你只要中止服务器,删除最后一条命令,而后重启Redis就能够。
AOF 持久化缺点
1)对一样的数据集,AOF文件一般要大于等价的RDB文件。
2)AOF可能比RDB慢,这取决于准确的fsync策略。一般fsync设置为每秒一次的话性能仍然很高,若是关闭fsync,即便在很高的负载下也和RDB同样的快。不过,即便在很大的写负载状况下,RDB仍是能提供能好的最大延迟保证。
3)在过去,咱们经历了一些针对特殊命令(例如,像BRPOPLPUSH这样的阻塞命令)的罕见bug,致使在数据加载时没法恢复到保存时的样子。这些bug很罕见,咱们也在测试套件中进行了测试,自动随机创造复杂的数据集,而后加载它们以检查一切是否正常,可是,这类bug几乎不可能出如今RDB持久化中。为了说得更清楚一点:Redis AOF是经过递增地更新一个已经存在的状态,像MySQL或者MongoDB同样,而RDB快照是一次又一次地从头开始创造一切,概念上更健壮。可是,1)要注意Redis每次重写AOF时都是以当前数据集中的真实数据从头开始,相对于一直追加的AOF文件(或者一次重写读取老的AOF文件而不是读内存中的数据)对bug的免疫力更强。2)咱们尚未收到一份用户在真实世界中检测到崩溃的报告。
AOF持久化优缺点总结
优势:能够最大程度保证数据不丢失
缺点:日志记录量级比较大微信

AOF持久化核心配置参数

#修改配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
#是否打开AOF日志功能
appendonly yes/no

#每一条命令都当即同步到AOF
appendfsync always
#每秒写一次
appendfsync everysec
#写入工做交给操做系统,由操做系统判断缓冲区大小,统一写入到AOF
appendfsync no

RDB 和 AOF,应该用哪个?
1)通常来讲,若是想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。app

2)若是你很是关心你的数据,但仍然能够承受数分钟之内的数据丢失, 那么你能够只使用 RDB 持久化。运维

3)有不少用户单独使用AOF,可是咱们并不鼓励这样,由于时常进行RDB快照很是方便于数据库备份,启动速度也较之快,还避免了AOF引擎的bug。

4)我的感触:在企业中,一般都使用RDB来作持久化,由于通常redis是在作MySQL的缓存,就算缓存数据丢失,真实的数据仍是在MySQL中,之因此用缓存是为了速度,性能而考虑,因此仍是建议使用RDB持久化,相对来讲会好一些,除非专门用redis来作一个key:value的数据库,并且数据很重要,那么能够考虑使用AOF

注意:基于这些缘由,未来咱们可能会统一AOF和RDB为一种单一的持久化模型(长远计划)。

RDB快照的工做方式

1)默认状况下,Redis保存数据集快照到磁盘,名为dump.rdb的二进制文件。你能够设置让Redis在N秒内至少有M次数据集改动时保存数据集,或者你也能够手动调用SAVE或者BGSAVE命令。

2)在上文中咱们已经在配置文件中作过对应的配置:
例如,这个配置会让Redis在每一个60秒内至少有1000次键改动时自动转储数据集到磁盘:
save 60 1000

3)当 Redis 须要保存 dump.rdb 文件时,服务器执行如下操做:

Redis 调用 fork() ,同时拥有父进程和子进程。
子进程将数据集写入到一个临时的 RDB 文件中。当子进程完成对新 RDB 文件的写入时, Redis 用新RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
4)这种方式使得 Redis 能够从写时复制机制中获益。

AOF重写功能介绍

1)由于 AOF 的运做方式是不断地将命令追加到文件的末尾,因此随着写入命令的不断增长, AOF 文件的体积也变得愈来愈大。举个例子,若是你对一个计数器调用了 100 次 INCR ,那么仅仅是为了保存这个计数器的当前值, AOF 文件就须要使用 100 条记录。然而在实际上,只使用一条 SET 命令已经足以保存计数器的当前值了,其他 99 条记录实际上都是多余的。

2)为了处理这种状况, Redis 支持一种有趣的特性:能够在不断服务客户端的状况下,对 AOF 文件进行重建。执行 BGREWRITEAOF 命令, Redis 将生产一个新的 AOF 文件,这个文件包含重建当前数据集所需的最少命令。

AOF 有多持久

你能够配置 Redis 多久才将数据 fsync 到磁盘一次。
有三个选项:

每次有新命令追加到 AOF 文件时就执行一次 fsync :很是慢,也很是安全。
每秒 fsync 一次:足够快(和使用 RDB 持久化差很少,)而且在故障时只会丢失1秒钟的数据。
从不 fsync :将数据交给操做系统来处理。更快,也更不安全的选择。
推荐(而且也是默认)的措施为每秒 fsync 一次,这种 fsync 策略能够兼顾速度和安全性。

老是 fsync 的策略在实际使用中很是慢,即便在 Redis2.0 对相关的程序进行了改进以后还是如此。频繁调用 fsync 注定了这种策略不可能快得起来。

RDB 和 AOF 之间的相互做用

1)在版本号大于等于 2.4 的 Redis 中, BGSAVE 执行的过程当中,不能够执行 BGRWRITEAOF 。 反过来讲,在 BGRWRITEAOF 执行的过程当中,也不能够执行 BGSAVE 。
2)这能够防止两个 Redis 后台进程同时对磁盘进行大量的 I/O 操做。若是 BGSAVE 正在执行,而且用户显示地调用 BGRWRITEAOF 命令,那么服务器将向用户回复一个 OK 状态,并告知用户, BGRWRITEAOF 已经被预约执行; 一旦 BGSAVE 执行完毕, BGRWRITEAOF 就会正式开始。
3)当 Redis 启动时,若是 RDB 持久化和 AOF 持久化都被打开了,那么程序会优先使用 AOF 文件来恢复数据集,由于 AOF 文件所保存的数据一般是最完整的。

备份Redis数据

1)Redis 对于数据备份是很是友好的,由于你能够在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被建立,就不会进行任何修改。

2)当服务器要建立一个新的 RDB 文件时,它先将文件的内容保存在一个临时文件里面,当临时文件写入完毕时,程序才使用临时文件替换原来的 RDB 文件。

3)这也就是说,不管什么时候, 复制 RDB 文件都是绝对安全的。

如下是咱们的建议:
1)建立一个按期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 而且天天将一个 RDB 文件备份到另外一个文件夹。

2)确保快照的备份都带有相应的日期和时间信息, 每次执行按期任务脚本时, 使用 find 命令来删除过时的快照: 好比说, 你能够保留最近 48 小时内的每小时快照, 还能够保留最近一两个月的每日快照。

3)至少天天一次, 将 RDB 备份到你的数据中心以外, 或者至少是备份到你运行 Redis 服务器的物理机器以外。

RDB持久化高级配置

#编辑配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
#后台备份进程出错时,主进程停不中止写入? 主进程不中止容易形成数据不一致
stop-writes-on-bgsave-error yes
#导出的rdb文件是否压缩 若是rdb的大小很大的话建议这么作
rdbcompression yes 
#导入rbd恢复时数据时,要不要检验rdb的完整性 验证版本是否是一致
rdbchecksum yes

AOF持久化高级配置

#编辑配置文件
[root@db01 redis]# vim /etc/redis/6379/redis.conf
#正在导出rdb快照的过程当中,要不要中止同步aof
no-appendfsync-on-rewrite yes/no
#aof文件大小比起上次重写时的大小,增加率100%时重写,缺点:业务开始的时候,会重复重写屡次
auto-aof-rewrite-percentage 100
#aof文件,至少超过64M时,重写
auto-aof-rewrite-min-size 64mb

Redis数据类型

String: 字符串类型
Hash: 哈希类型
List: 列表类型
Set: 集合类型
Sorted set: 顺序集合类型

通用操做

#查看全部的key
127.0.0.1:6379> KEYS *
1) "age"
2) "name"
#判断key是否存在
127.0.0.1:6379> EXISTS name
(integer) 1
#变动key名
127.0.0.1:6379> RENAME age nianling
#查看key的类型
127.0.0.1:6379> type name
string
#删除key
127.0.0.1:6379> del name
(integer) 1
#以秒为单位设置生存时间
127.0.0.1:6379> EXPIRE name 10
(integer) 1
#以毫秒为单位设置生存时间
127.0.0.1:6379> PEXPIRE name 10000
(integer) 1
#取消剩余生存时间
127.0.0.1:6379> PERSIST name
(integer) 1

strings(字符)类型操做

应用场景:
常规计数:微博数、粉丝数、直播平台

#设置key
127.0.0.1:6379> set name zls
OK
#设置多个key
127.0.0.1:6379> mset name zls age 18 sex m
OK
#设置值、取值同时进行
127.0.0.1:6379> GETSET name zls
(nil)
127.0.0.1:6379> GETSET name zls
"zls"
#设置值同时设置生存时间
127.0.0.1:6379> set name zls ex 10
OK
#数量递归增长
127.0.0.1:6379> incr num
(integer) 1
#指定增长数值
127.0.0.1:6379> incrby num 2
(integer) 8
#数量递减
127.0.0.1:6379> DECR num
(integer) -1
#指定递减数
127.0.0.1:6379> DECRBY num 2
(integer) -3
#浮点增长
127.0.0.1:6379> incrbyfloat float 0.6
"0.6"

#删除已有key
127.0.0.1:6379> DEL num

#追加(若该键不存在,则建立)
127.0.0.1:6379> APPEND name bgx
(integer) 6
#查看追加内容
127.0.0.1:6379> get name
"zlsbgx"
#修改第N个字符串
127.0.0.1:6379> SETRANGE name 3 a
(integer) 6
#查看结果
127.0.0.1:6379> get name
"zlsagx"

#获取key值
127.0.0.1:6379> get name
"zls"
#查看string类型的长度
127.0.0.1:6379> STRLEN name
(integer) 6
#查看指定长度的string类型
127.0.0.1:6379> GETRANGE name  0 4
"zlsag"
#以秒查询key剩余生存时间
127.0.0.1:6379> ttl name
(integer) 8
#以毫秒查询key剩余生存时间
127.0.0.1:6379> pttl name
(integer) 44016
#获取多个key值
127.0.0.1:6379> mget name age sex
1) "zls"
2) "18"
3) "m"

应用场景实现

#粉丝数量增长,每点一次关注,都执行如下命令一次
127.0.0.1:6379> incr num
(integer) 1
#取消关注则执行如下命令一次
127.0.0.1:6379> DECR num
(integer) -1
#显示粉丝数量
127.0.0.1:6379> get num
"6"
#暗箱操做,刷粉丝
127.0.0.1:6379> incrby num 10000
(integer) 10006

hash(字典)类型操做

应用场景:
存储部分变动的数据,如用户信息,商品信息等。
最接近表结构的一种类型。
增:

#建立car的price值
127.0.0.1:6379> hset car price 500
(integer) 1
#建立car的name值
127.0.0.1:6379> hset car name BMW
(integer) 1
#建立car的date值
127.0.0.1:6379> hset car date 1982
(integer) 1
#设置多个哈希key(相似于MySQL的一个表中的一行数据)
127.0.0.1:6379> hmset teacher name zls age 18 sex m
OK
127.0.0.1:6379> hmset teacher name bgx age 80 sex f
OK

删:

#删除hash类型中的一个值
127.0.0.1:6379> HDEL teacher name
(integer) 1
#删除整个hash类型key
127.0.0.1:6379> DEL teacher
(integer) 1

#修改hash类型值 增长1
127.0.0.1:6379> hincrby myhash num 1
(integer) 1

#获取car的name值
127.0.0.1:6379> hget car name
"BMW"
#获取key的所有value和值(运维经常使用)
127.0.0.1:6379> hgetall car
1) "price"
2) "500"
3) "name"
4) "BMW"
5) "date"
6) "1982"
#获取key中部分值
127.0.0.1:6379> HMGET teacher name sex
1) "zls"
2) "m"

List(列表)类型操做

应用场景:

消息队列系统

好比sina微博:在redis中咱们的最新微博ID使用了常驻缓存,这是一直更新的。
可是作了限制不能超过5000个ID,所以获取ID的函数会一只询问redis。
系统不会像传统方式那样“刷新”缓存,redis实例中的信息永远是一致的。
SQL数据库(或是硬盘上的其余类型数据)只是在用户须要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
增:

#将一个值或者多个值插入列表的表头(若key不存在,则添加key并依次添加)
127.0.0.1:6379> lpush list zls
(integer) 1
127.0.0.1:6379> lpush list bgx
(integer) 2
127.0.0.1:6379> lpush list oldboy
(integer) 3
127.0.0.1:6379> lpush list alex
(integer) 4
#一行添加
127.0.0.1:6379> lpush teacher zls bgx oldboy alex
(integer) 4
#追加一个value值,若key不存在,则不建立
127.0.0.1:6379> LPUSHX teacher1 zls
(integer) 0
#在bgx前面添加zls
127.0.0.1:6379> linsert teacher before bgx zls
(integer) 6
#在尾部添加key
127.0.0.1:6379> rpush teacher wang5
(integer) 7
#将teacher的尾部元素弹出,再插入到teacher1的头部
127.0.0.1:6379> rpoplpush teacher teacher1
"wang5"
#查看一个列表内有多少行
127.0.0.1:6379> llen list
(integer) 4

删:

#删除key
127.0.0.1:6379> del teacher
(integer) 1
#从头部开始找,按前后顺序,值为a的元素,删除数量为2个,若存在第3个,则不删除
127.0.0.1:6379> lrem teacher 2 zls
(integer) 2
#从头开始,索引为0,1,2的3个元素,其他所有删除改
127.0.0.1:6379> ltrim teacher 0 2
OK

改:

#从头开始, 将索引为1的元素值,设置为新值 e,若索引越界,则返回错误信息
127.0.0.1:6379> lset teacher 1 test
OK
#将 teacher 中的尾部元素移到其头部
127.0.0.1:6379> rpoplpush teacher teacher
"oldboy"

#列表头部弹出,弹一行少一行
127.0.0.1:6379> lpop teacher
"zls"
#列表尾部
127.0.0.1:6379> rpop teacher
"wang5"
#查询索引(头部开始)
127.0.0.1:6379> lindex list 0
"bgx"
#查询索引(尾部第一个)
127.0.0.1:6379> lindex list -1
"alex"
#范围查询索引
127.0.0.1:6379> lrange list 0 1
1) "bgx"
2) "oldboy"

微博 微信朋友圈的场景实现:

#发朋友圈
127.0.0.1:6379> LPUSH wechat "monday,bgx is a bad man"
(integer) 1
127.0.0.1:6379> LPUSH wechat "Tuesday,zls is a nice boy"
(integer) 2
127.0.0.1:6379> LPUSH wechat "Wednesday,alex is a loser"
(integer) 3

#查看朋友圈内容
127.0.0.1:6379> LRANGE wechat 0 -1
1) "Wednesday,zls is a nice boy"
2) "Tuesday,zls is a nice boy"
3) "monday,zls is a nice boy"

Set(集合) 类型操做

应用场景:
在微博应用中,能够将一个用户全部的关注人存在一个集合中,将其全部粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操做,能够很是方便的实现如共同关注、共同喜爱、二度好友等功能,对上面的全部集合操做,你还可使用不一样的命令选择将结果返回给客户端仍是存集到一个新的集合中。

增:

#若key不存在,建立该键及与其关联的set,依次插入bgx、lidao、xiaomimei若key存在,则插入value中,若bgx在zls_fans中已经存在,则插入了lidao和xiaomimei两个新成员。
127.0.0.1:6379> sadd zls_fans bgx lidao xiaomimei
(integer) 3

#尾部的b被移出,事实上b并非以前插入的第一个或最后一个成员
127.0.0.1:6379> spop zls_fans
"bgx"
#若值不存在, 移出存在的值,并返回剩余值得数量
127.0.0.1:6379> SREM zls_fans lidao oldboy alex
(integer) 1

#将小迷妹从 zls_fans 移到 bgx_fans
127.0.0.1:6379> SMOVE zls_fans bgx_fans xiaomimei
(integer) 1

#判断xiaomimei是否已经存在,返回值为 1 表示存在
127.0.0.1:6379> SISMEMBER zls_fans xiaomimei
(integer) 0
127.0.0.1:6379> SISMEMBER bgx_fans xiaomimei
(integer) 1
#查看set中的内容
127.0.0.1:6379> SMEMBERS zls_fans
1) "xiaomimei"
2) "bgx"
3) "lidao"
#获取Set 集合中元素的数量
127.0.0.1:6379> scard zls_fans
(integer) 0
127.0.0.1:6379> scard bgx_fans
(integer) 1
#随机的返回某一成员
127.0.0.1:6379> srandmember bgx_fans
"xiaomimei"

#建立三个集合
127.0.0.1:6379> sadd zls_fans bgx lidao xiaomimei
(integer) 3
127.0.0.1:6379> sadd bgx_fans zls lidao xiaomimei
(integer) 2
127.0.0.1:6379> sadd lidao_fans 0
(integer) 1

#1和2获得一个结果,拿这个集合和3比较,得到每一个独有的值
127.0.0.1:6379> sdiff zls_fans bgx_fans lidao_fans
1) "bgx"
#3个集和比较,获取独有的元素,并存入diffkey 关联的Set中
127.0.0.1:6379> sdiffstore diffkey zls_fans bgx_fans lidao_fans
(integer) 1
#得到3个集合中都有的元素
127.0.0.1:6379> sinter zls_fans bgx_fans lidao_fans
(empty list or set)    //由于这里没有交集,因此返回一个空集合
#把交集存入interkey 关联的Set中
127.0.0.1:6379> sinterstore interkey bgx_fans lidao_fans
(integer) 0  // 由于这里没有交集,因此存入的值为0
#获取3个集合中的成员的并集
127.0.0.1:6379> sunion zls_fans bgx_fans lidao_fans
1) "bgx"
2) "xiaomimei"
3) "zls"
4) "lidao"
5) "0"
#把并集存入unionkey 关联的Set中
127.0.0.1:6379> sunionstore unionkey zls_fans bgx_fans lidao_fans
(integer) 5

Sorted-Set(有序集合)类型操做

应用场景:

排行榜应用,取TOP N操做
这个需求与上面需求的不一样之处在于,前面操做以时间为权重,这个是以某个条件为权重,好比按顶的次数排序,这时候就须要咱们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只须要执行一条ZADD命令便可。

增:

#添加两个分数分别是 2 和 3 的两个成员
127.0.0.1:6379> zadd myzset 2 "two" 3 "three"
(integer) 2

#删除多个成员变量,返回删除的数量
127.0.0.1:6379> zrem myzset one two
(integer) 1

#将成员 one 的分数增长 2,并返回该成员更新后的分数
127.0.0.1:6379> zincrby myzset 2 one
"2"

#返回全部成员和分数,不加WITHSCORES,只返回成员
127.0.0.1:6379> zrange myzset 0 -1 WITHSCORES
1) "one"
2) "2"
3) "three"
4) "3"
#获取成员one在Sorted-Set中的位置索引值。0表示第一个位置
127.0.0.1:6379> zrank myzset one
(integer) 0
#获取 myzset 键中成员的数量
127.0.0.1:6379> zcard myzset
(integer) 2
#获取分数知足表达式 1 <= score <= 2 的成员的数量
127.0.0.1:6379> zcount myzset 1 2
(integer) 1  
#获取成员 three 的分数 
127.0.0.1:6379> zscore myzset three
"3"
#获取分数知足表达式 1 < score <= 2 的成员
127.0.0.1:6379> zrangebyscore myzset  1 2
1) "one"
#-inf 表示第一个成员,+inf最后一个成员
#limit限制关键字
#2  3  是索引号
zrangebyscore myzset -inf +inf limit 2 3  返回索引是2和3的成员
#删除分数 1<= score <= 2 的成员,并返回实际删除的数量
127.0.0.1:6379> zremrangebyscore myzset 1 2
(integer) 1
#删除位置索引知足表达式 0 <= rank <= 1 的成员
127.0.0.1:6379> zremrangebyrank myzset 0 1
(integer) 1
#按位置索引从高到低,获取全部成员和分数
127.0.0.1:6379> zrevrange myzset 0 -1 WITHSCORES
#原始成员:位置索引从小到大
      one  0
      two  1
#执行顺序:把索引反转
      位置索引:从大到小
      one 1
      two 0
#输出结果: 
       two
       one
#获取位置索引,为1,2,3的成员
127.0.0.1:6379> zrevrange myzset 1 3
(empty list or set)
#相反的顺序:从高到低的顺序
#获取分数 3>=score>=0的成员并以相反的顺序输出
127.0.0.1:6379> zrevrangebyscore myzset 3 0
(empty list or set)
#获取索引是1和2的成员,并反转位置索引
127.0.0.1:6379> zrevrangebyscore myzset 4 0 limit 1 2
(empty list or set)
相关文章
相关标签/搜索