一、介绍
Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、 Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。
Redis 是一个 Key-Value 存储系统。和 Memcached 类似,它支持存储的 value 类型相对更多, 包括 string(字符串)、list(链表)、set(集合)和 zset(有序集合)。这些数据类型都支持 push/pop、 add/remove 及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础 上,Redis 支持各种不同方式的排序。与 memcached 一样,为了保证效率,数据都是缓存在 内存中。区别的是 Redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录 文件,并且在此基础上实现了 master-slave(主从)同步。
- Redis 适用的一些场景
- 取最新 N 个数据的操作
- 排行榜应用,取 TOP N 操作
- 需要精准设定过期时间的应用
- 计数器应用
Redis 的命令都是原子性的,你可以轻松地利用 INCR,DECR 命令来构建计数器系统。 - Uniq 操作,获取某段时间所有数据排重值
这个使用 Redis 的 set 数据结构最合适了,只需要不断地将数据往 set 中扔就行了,set 意为 集合,所以会自动排重。 - 实时系统,反垃圾系统
- Pub/Sub 构建实时消息系统
- 构建队列系统
- 缓存
性能优于 Memcached,数据结构更多样化。
二、安装与配置
登录远程主机:ssh 用户名@IP地址 ,然后输入密码。
进入想要安装Redis的目录,执行:
$ wget http://download.redis.io/releases/redis-3.2.9.tar.gz
$ tar xzf redis-3.2.9.tar.gz
$ cd redis-3.2.9
$ make
启动Redis服务
$ src/redis-server
如果出现下图,就说明启动成功。
image.png
但是这个服务不是后台的,如果想让Redis以后台服务的形式运行,可以修改配置文件。
解压后的文件夹redis-3.2.9内有一个redis.conf的文件,可以修改配置参数,并在启动Redis的时候指定该配置文件,使其按照配置启动。
比如,
修改默认端口6379为6380:port 6380
修改为后台运行:daemonize yes
修改后,在刚才的窗口中按Control+C键,关闭前台Redis服务,指定配置文件重新启动
`$ src/redis-server ./redis.conf`
此时,没有任何提示(没有消息就是好消息),不放心可以查看当前进程
$ ps -ef |grep -i redis
#可以在控制台看到如下的信息
xxx 3940 27646 0 14:25 pts/1 00:00:00 src/redis-server 127.0.0.1:6380
现在,用Redis客户端与该服务交互,执行
# 启动Redis客户端:默认端口是6379,所以要指定端口为6380
$ src/redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> set name laoyue
OK
127.0.0.1:6380> get name
"laoyue"
127.0.0.1:6380>
# 要退出Redis客户端,按Control+C键或输入quit回车。
Redis服务器默认只允许本机访问。如果想要远程访问Redis,修改配置文件中的bind参数。
更多配置
daemonize:
默认情况下,redis 不是在后台运行的,如果需要在后台运行,把该项的值更改为 yes
pidfile
当 Redis 在后台运行的时候,Redis 默认会把 pid 文件放在/var/run/redis.pid,
你可以配置到其他地址。当运行多个 redis 服务时,需要指定不同的 pid 文件和端口
bind
指定 Redis 只接收来自于该 IP 地址的请求,如果不进行设置,
那么将处理所有请求,在生产环境中最好设置该项
port
监听端口,默认为 6379
timeout
设置客户端连接时的超时时间,单位为秒。
当客户端在这段时间内没有发出任何指令, 那么关闭该连接
loglevel
log 等级分为 4 级,debug, verbose, notice, 和 warning。
生产环境下一般开启 notice
logfile
配置 log 文件地址,默认使用标准输出,即打印在命令行终端的窗口上
databases
设置数据库的个数,可以使用 SELECT <dbid>命令来切换数据库。默认使用的数据库是 0
save
设置 Redis 进行数据库镜像的频率。
if(在 60 秒之内有 10000 个 keys 发生变化时){
进行镜像备份
}else if(在 300 秒之内有 10 个 keys 发生了变化){
进行镜像备份
}else if(在 900 秒之内有 1 个 keys 发生了变化){
进行镜像备份
}
rdbcompression :在进行镜像备份时,是否进行压缩
dbfilename :镜像备份文件的文件名
dir
数据库镜像备份的文件放置的路径。这里的路径跟文件名要分开配置是因为 Redis 在进行备份时,
先会将当前数据库的状态写入到一个临时文件中,等备份完成时,再把该临时文件替换为上面所指定的
文件,而这里的临时文件和上面所配置的备份文件都会放 在这个指定的路径当中
slaveof: 设置该数据库为其他数据库的从数据库
masterauth :当主数据库连接需要密码验证时,在这里指定
requirepass
设置客户端连接后进行任何其他指定前需要使用的密码。
警告:因为 redis 速度相当快, 所以在一台比较好的服务器下,一个外部的用户可以在一秒钟
进行 150K 次的密码尝试, 这意味着你需要指定非常非常强大的密码来防止暴力破解。
maxclients
限制同时连接的客户数量。当连接数超过这个值时,redis 将不再接收其他连接请求,
客户端尝试连接时将收到 error 信息。
maxmemory
设置 redis 能够使用的最大内存。
当内存满了的时候,如果还接收到 set 命令,redis 将先尝试剔除设置过expire信息的key,
而不管该 key 的过期时间还没有到达。在删除时,将按照过期时间进行删除,最早将要被过期的
key 将最先被删除。如果带有expire 信息的key都删光了,那么将返回错误。
这样,redis 将不再接收写请求,只接收get请求。 maxmemory 的设置比较适合于把 redis
当作于类似 memcached 的缓存来使用。
appendonly
默认情况下,redis 会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时的,
而且备份也不能很频繁,如果发生诸如拉闸限电、拔插头等状况,那么将造成比较 大范围的数据丢失。
所以 redis 提供了另外一种更加高效的数据库备份及灾难恢复方式。 开启 append only 模式
之后,redis 会把所接收到的每一次写操作请求都追加到 appendonly.aof 文件中,
当redis重新启动时,会从该文件恢复出之前的状态。但是这样会造成 appendonly.aof文件过大,
所以 redis 还支持了 BGREWRITEAOF 指令,对 appendonly.aof 进行重新整理。
所以我认为推荐生产环境下的做法为关闭镜像,开启 appendonly.aof,同时可以选择在访问
较少的时间每天对 appendonly.aof 进行重写一次。
appendfsync
设置对 appendonly.aof 文件进行同步的频率。always 表示每次有写操作都进行同步,
everysec 表示对写操作进行累积,每秒同步一次。
这个需要根据实际业务场景进行配置
vm-enabled
是否开启虚拟内存支持。因为 redis 是一个内存数据库,而且当内存满的时候,
无法接收新的写请求,所以在 redis 2.0 中,提供了虚拟内存的支持。
但是需要注意的是,redis 中,所有的 key 都会放在内存中,在内存不够时,
只会把 value 值放入交换区。这样保证了虽然使用虚拟内存,但性能基本不受影响,
同时,你需要注意的是你要把 vm-max-memory 设置到足够来放下你的所有的 key
vm-swap-file :设置虚拟内存的交换文件路径
vm-max-memory
这里设置开启虚拟内存之后,redis 将使用的最大物理内存的大小。
默认为 0,redis 将 把他所有的能放到交换文件的都放到交换文件中,以尽量少的使用物理内存。
在生产环 境下,需要根据实际情况设置该值,最好不要使用默认的 0
vm-page-size
设置虚拟内存的页大小,如果你的 value 值比较大,比如说你要在 value 中放置博客、
新闻之类的所有文章内容,就设大一点,如果要放置的都是很小的内容,那就设小一点。
vm-pages
设置交换文件的总的 page 数量,需要注意的是,page table 信息会放在物理内存中,
每 8 个 page 就会占据 RAM 中的 1 个 byte。
总的虚拟内存大小 = vm-page-size * vm-pages
vm-max-threads
设置 VM IO 同时使用的线程数量。因为在进行内存交换时,对数据有编码和解码的过程,
所以尽管 IO 设备在硬件上本上不能支持很多的并发读写,
但是还是如果你所保存的vlaue值比较大,将该值设大一些,还是能够提升性能的
glueoutputbuf
把小的输出缓存放在一起,以便能够在一个 TCP packet 中为客户端发送多个响应,
具体原理和真实效果我不是很清楚。所以根据注释,你不是很确定的时候就设置成 yes
hash-max-zipmap-entries
在 redis 2.0 中引入了 hash 数据结构。当 hash 中包含超过指定元素个数并且最大的
元素没有超过临界时,hash 将以一种特殊的编码方式(大大减少内存使用)来存储,
这里可以设置这两个临界值
activerehashing
开启之后,redis 将在每100毫秒时使用1毫秒的CPU时间来对redis的 hash 表进行重新hash,
可以降低内存的使用。当你的使用场景中,有非常严格的实时性需要,不能够接受 Redis
时不时的对请求有 2 毫秒的延迟的话,把这项配置为 no。
如果没有这么严格的实时性要求,可以设置为 yes,
以便能够尽可能快的释放内存
三、数据类型及操作
3.1 strings
string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据,比如 jpg 图片或者序 列化的对象。从内部实现来看其实 string 可以看作 byte 数组,最大上限是 1G 字节。</br>
常见操作
#
# set 和setnx :OK说明操作成功;nx表示not exist
#
127.0.0.1:6380> set name laoyue
OK
127.0.0.1:6380> setnx name yueyue
(integer) 0
127.0.0.1:6380> get name
"laoyue"
127.0.0.1:6380>
#
# setex:设置 key 对应的值为 string 类型的 value,并指定此键值对应的有效期。
# 下例表示有效期10s
#
127.0.0.1:6380> setex gender 10 male
OK
127.0.0.1:6380> get gender
"male"
127.0.0.1:6380> get gender
"male"
127.0.0.1:6380> get gender
(nil)
#
# setrange key offset value:替换value字符串的一部分
#
127.0.0.1:6380> set mail 1234567@qq.com
OK
127.0.0.1:6380> get mail
"1234567@qq.com"
127.0.0.1:6380> setrange mail 5 abc@gmail.com
(integer) 18
127.0.0.1:6380> get mail
"12345abc@gmail.com"
#
# mset key value [key value, key value...]:批量设置key value
# msetnx key value [key value, key value...]:区别是不会覆盖已经存在的key
#
127.0.0.1:6380> mset address smailroom phone 123456789
OK
127.0.0.1:6380> get address
"smailroom"
127.0.0.1:6380> get phone
"123456789"
127.0.0.1:6380>
#
# get相关
# get key :根据key获取value
# getset key value :设置 key 的值,并返回 key 的旧值。
# getrange key start end:获取指定 key 的 value 值的子字符串。
# mget key1 key2 ...:一次获取多个 key 的值,如果对应 key 不存在,则对应返回 nil。
#
# incr key:对 key 的值做加加操作,并返回新的值。
# 注意 ,incr 一个不是 int 的 value 会返回错误,
# key 不存在时候会设置 key,并认为原来的 value 是 0
# incrby key increment:incr是加1,incrby是加increment
# 对应的减操作为:decr和decrby(key 不存在时候会设置 key,并认为原来的 value 是 0)
# append key value:给指定 key 的字符串值追加 value,返回新字符串值的长度。
# strlen key:取指定 key 的 value 值的长度。
3.2 hashes
Redis hash是一个string类型的field和value的映射表.它的添加、删除操作都是O(1()平均)。 hash 特别适合用于存储对象。相较于将对象的每个字段存成单个 string 类型。将一个对象存 储在 hash 类型中会占用更少的内存,并且可以更方便的存取整个对象。省内存的原因是新 建一个 hash 对象时开始是用 zipmap(又称为 small hash)来存储的。这个 zipmap 其实并不 是 hash table,但是 zipmap 相比正常的 hash 实现可以节省不少 hash 本身需要的一些元数据 存储开销。尽管 zipmap 的添加,删除,查找都是 O(n),但是由于一般对象的 field 数量都不 太多。所以使用 zipmap 也是很快的,也就是说添加删除平均还是 O(1)。如果 field 或者 value 的大小超出一定限制后,Redis 会在内部自动将 zipmap 替换成正常的 hash 实现. 这个限制可 以在配置文件中指定
hash-max-zipmap-entries 64 #配置字段最多 64 个
hash-max-zipmap-value 512 #配置 value 最大为 512 字节</br>
常用操作
# 假如对象user有属性:name,age,gender,address,phone。
# 现在将user1存在Redis中:(该对象的key取为user1)
#
# hset key field value:设置属性field的值为value
# hsetnx key field value :如果 key 不存在,则先创建。如果 field 已经存在,返回 0
# hmset key field1 value1 [field2 value2...]:批量设置
# hget key field:获取key的指定field的值。
# hmget key field1 value1 [field2 value2...]:获取全部指定的filed的值。
#
#
127.0.0.1:6380> hset user1 name laoyue
(integer) 1
127.0.0.1:6380> hmset user1 age 27 address beijing gender male phone 111111
OK
127.0.0.1:6380> hget user1 name
"laoyue"
127.0.0.1:6380> hmget user1 name age gender address phone
1) "laoyue"
2) "27"
3) "male"
4) "beijing"
5) "111111"
127.0.0.1:6380>
#
# hincrby key field increment:指定的filed 加上给定值increment(可正可负),返回修改后的值
# hexists key field:测试指定 field 是否存在,返回1或0
# hlen key:返回指定 hash 的 field 数量。
# hdel key field1 [field2, field3...]:删除一个或多个field
# hkeys key:返回 hash 的所有 field。
# hvals key :返回 hash 的所有 value。
# hgetall key:获取某个 hash 中全部的 filed 及 value。
#
127.0.0.1:6380> hincrby user1 age -2
(integer) 25
127.0.0.1:6380> hexists user1 address
(integer) 1
127.0.0.1:6380> hlen user1
(integer) 5
127.0.0.1:6380> hdel user1 age phone
(integer) 2
127.0.0.1:6380> hlen user1
(integer) 3
127.0.0.1:6380> hkeys user1
1) "name"
2) "address"
3) "gender"
127.0.0.1:6380> hvals user1
1) "laoyue"
2) "beijing"
3) "male"
127.0.0.1:6380> hgetall user1
1) "name"
2) "laoyue"
3) "address"
4) "beijing"
5) "gender"
6) "male"
127.0.0.1:6380>
3.3 lists
list 是一个链表结构,主要功能是 push、pop、获取一个范围的所有值等等,操作中 key 理 解为链表的名字。
Redis 的 list 类型其实就是一个每个子元素都是 string 类型的双向链表。链表的最大长度是(2 的 32 次方)。我们可以通过 push,pop 操作从链表的头部或者尾部添加删除元素。这使得 list 既可以用作栈,也可以用作队列。
有意思的是 list 的 pop 操作还有阻塞版本的,当我们[lr]pop 一个 list 对象时,如果 list 是空, 或者不存在,会立即返回 nil。但是阻塞版本的 b[lr]pop 可以则可以阻塞,当然可以加超时时 间,超时后也会返回 nil。为什么要阻塞版本的 pop 呢,主要是为了避免轮询。举个简单的 例子如果我们用 list 来实现一个工作队列。执行任务的 thread 可以调用阻塞版本的 pop 去获 取任务这样就可以避免轮询去检查是否有任务存在。当任务来时候工作线程可以立即返回, 也可以避免轮询带来的延迟。</br>
常用操作
#
# lpush key value [value, value...]:在key对应list的头部添加字符串元素
# rpush key value [value, value...]:在key对应list的尾部添加字符串元素
# linsert key BEFORE|AFTER pivot value:
# 在 key 对应 list 的特定位置之前或之后添加字符串元素
# lset key index value:设置list中指定下标的元素值(下标从 0 开始)
# lrem key count value:从key对应list中删除 count 个和 value 相同的元素。
# count>0 时,按从头到尾的顺序删除;
# count<0 时,按从尾到头的顺序删除;
# count=0 时,删除全部;
# ltrim key start stop:保留指定key的值范围内的数据
# lpop key :从 list 的头部删除一个元素,并返回删除元素
# rpop key :从 list 的尾部删除一个元素,并返回删除元素
# rpoplpush source destination :
# 从第一个list(source)的尾部移除元素并添加到第二个list(destination)的头部,
# 最后返回被移除的元素值;
# 整个操作是原子的.如果第一个list是空或者不存在返回nil
# lindex key index:返回key对应list中index位置的元素
# llen key:返回key对应list的长度
#
3.4 sets
set 是集合,和我们数学中的集合概念相似,对集合的操作有添加删除元素,有对多个集合求交并差等操作,操作中 key 理解为集合的名字。
Redis 的 set 是 string 类型的无序集合。set 元素最大可以包含(2 的 32 次方)个元素。
set 的是通过 hash table 实现的,所以添加、删除和查找的复杂度都是 O(1)。hash table 会随 着添加或者删除自动的调整大小。需要注意的是调整 hash table 大小时候需要同步(获取写 锁)会阻塞其他读写操作,可能不久后就会改用跳表(skip list)来实现,跳表已经在 sorted set 中使用了。关于 set 集合类型除了基本的添加删除操作,其他有用的操作还包含集合的 取并集(union),交集(intersection),差集(difference)。通过这些操作可以很容易的实现 sns 中的好友推荐和 blog的tag功能。
常用操作
#
# sadd key member [member, member...]:
# 向名称为key的set中添加一个或多个元素;返回成功添加的元素个数
# srem key member [member, member...]:
# 删除名称为 key 的 set 中的元素 member;返回成功删除的元素的个数
# smembers key:返回key对应set的所有元素
# spop key [count]:
# 随机返回并删除名称为key的set中count个元素(默认为1)
# sdiff key [key, key...]:
# 返回所有给定 key 与第一个 key 的差集
# sdiffstore destination key [key, key...]:
# 返回所有给定 key 与第一个 key 的差集,并将结果存到destination中
# sinter key [key, key...]:返回所有给定 key 的交集
# sinterstore destination key [key, key...]:
# 返回所有给定 key 的交集,并将结果存到destination
# sunion key [key, key...]:返回所有给定 key 的并集
# sunionstore destination key [key, key...]:
# 返回所有给定 key 的并集,并将结果存到destination
# smove source destination member:
# 从source set 中移除 member 并添加到destination set 中
#scard key:返回名称为 key 的 set 的元素个数
# sismember key member:
# 测试 member 是否是名称为 key 的 set 的元素
#srandmember key [count]
# 随机返回名称为 key 的 set 的count个元素(不指定count则为1),但是不删除元素
#
3.5 sorted sets
sorted set 是 set 的一个升级版本,它在 set 的基础上增加了一个顺序属性,这一属性在添加 修改元素的时候可以指定,每次指定后,zset 会自动重新按新的值调整顺序。可以理解为有 两列的 mysql 表,一列存 value,一列存顺序。操作中 key 理解为 zset 的名字。
和 set 一样 sorted set 也是 string 类型元素的集合,不同的是每个元素都会关联一个 double 类型的 score。sorted set 的实现是 skip list 和 hash table 的混合体。
当元素被添加到集合中时,一个元素到 score 的映射被添加到 hash table 中,所以给定一个 元素获取 score 的开销是 O(1),另一个 score 到元素的映射被添加到 skip list,并按照 score 排 序,所以就可以有序的获取集合中的元素。添加,删除操作开销都是 O(log(N))和 skip list 的 开销一致,redis 的 skip list 实现用的是双向链表,这样就可以逆序从尾部取元素。sorted set 最 经常的使用方式应该是作为索引来使用.我们可以把要排序的字段作为 score 存储,对象的 id 当元素存储。</br>
常用操作
#
# zadd key [NX|XX] [CH] [INCR] score member [score member ...]:
# 向名称为key的zset中添加元素member,score 用于排序。
# 如果该元素已经存在,则根据 score 更新该元素的顺序
# zrem key member [ member ...]
# 删除名称为 key 的 zset 中的元素 member
# zincrby key increment member:
# 如果在名称为key的zset中已经存在元素member,则该元素的 score 增加 increment;
# 否则向集合中添加该元素,其 score 的值为 increment
# zrank key member
# 返回名称为 key 的 zset 中 member 元素的排名(按 score 从小到大排序)即下标。
# zrevrank key member
# 返回名称为key的zset中member元素的排名(按 score 从大到小排序)即下标
# zrevrange key start stop [WITHSCORE]
# 返回名称为 key 的 zset(按 score 从大到小排序)中的 index 从 start 到 end 的所有元素
# zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
# 返回集合中 score 在给定区间的元素
# zcount key min max
# 返回集合中 score 在给定区间的数量
# zcard key
# 返回集合中元素个数
# zscore key member
# 返回给定元素对应的 score
# zremrangebyrank key stat stop
# 删除集合中排名在给定区间的元素
# zremrangebyscore key min max
# 删除集合中score在给定区间的元素
#
四、Redis 常用命令
Redis 提供了丰富的命令(command)对数据库和各种数据类型进行操作,这些 command 可以在 Linux 终端使用。在编程时,比如各类语言包,这些命令都有对应的方法。下面将 Redis 提供的命令做一总结。
4.1 键值相关
#
# keys pattern:返回满足给定 pattern 的所有 key
#
127.0.0.1:6380> keys *
1) "myset1"
2) "name"
3) "user1"
4) "mail"
5) "address"
6) "phone"
127.0.0.1:6380> keys m*
1) "myset1"
2) "mail"
127.0.0.1:6380>
#
# exists key [key, key ... ]:确认一个或多个key 是否存在(返回存在的个数)
# del key [key, key ... ]:删除一个或多个 key
# expire key seconds:设置一个 key 的过期时间(单位:秒)
# move key db:将当前数据库中的 key 转移到其它数据库db中
# persist key:移除给定 key 的过期时间,就是一直有效
# randomkey:随机返回所有keys中的一个 key
# rename key newkey:重命名 key
# type key:返回值的类型
#
4.2 服务器相关
# ping :测试连接是否存活
# echo message:在命令行打印一些内容
# select index:
# 选择数据库。
# Redis 数据库编号从 0~15,我们可以选择任意一个数据库来进行数据的存取。
# quit:退出连接
# dbsize:返回当前数据库中 key 的数目
# info [session]:获取服务器的信息和统计。
# monitor:实时转储收到的请求。
# config get 配置项:获取配置项的信息
# flushdb :删除当前选择数据库中的所有 key。
# flushall:删除所有数据库中的所有 key。
#
网友评论