Redis 缓存服务器 Redis 服务器

Remote Dictionay Server  

Redis是一个key-value持久化产品,通常被称为数据结构服务器。

Redis的key是string类型;value可以是string、hash、list、set、sorted set等类型;

实际上,Redis内部会将key和value都以二进制字节流的格式存储。

安装  redis:

redis官网:

http://code.google.com/p/redis/

安装方法:

http://code.google.com/p/redis/wiki/QuickStart

$ tar xvzf redis-1.02.tar.gz

$ cd redis-1.02

$ make

$ make test

部署:

将redis-cli redis-benchmark redis-server redis.conf靠到指定的目录。

修改配置文件:

在redis.conf可以指定db的保存路径,默认是保存在当前目录。具体内容见redis.conf中的注释。

启动:

./redis-server

KEY操作

exists  key                    测试key是否存在,返回1存在,0不存在 

dbsize  当前数据库的key数量 

dump key                    返回被序列化的值 

del key1 key2 ...          删除给定的key,返回删除key的数目 

type key                      返回给定key的value类型,返回none表示不存在key 

keys patten                  返回匹配指定模式的所有key 

randomkey 返回一个随机选择的key 

rename oldkey newkey     重命名一个key,如果newkey存在将会被覆盖 

renamenx  oldkey newkey     重命名一个key,如果newkey存在返回失败 

expire key seconds           为key指定过期时间,相对时间 

expireat key timestamp     为key指定过期时间,绝对时间(UNIX时间) 

ttl key                             返回设置过期时间的key的剩余过期秒数 

persist key                      移除key的过期时间 

VALUE的 五种 数据结构

1、string(字符串)

set key value                       插入一条数据(key-value pair),若key已存在,则覆盖旧value 

append key value                 对已存在的key,在其value末尾添加新数据;如key不存在,等效于set命令 

setex key seconds value        原子性完成两个操作,一是设置key值为指定value,同时设置该key的ttl 

setnx key val                        key不存在时才插入该记录    

get key                                按键索引数据,如key不存在,返回nil 

getset key value                   将key设置为新的value,并返回旧value 

mget key1 key2                    返回多个key的值 

mset key1 val1 key2 val2 

getrange key start end           返回value的一个切片,双闭区间 

setrange  key offset value        替换key的部分字符串值 

substr key start end 

getbit

setbit

strlen key                            value长度 

incr key                              value++(原子操作),将value当成整型处理 

incrby key n                        value+=n 

decr key                             value-- 

decrby key n                        value-=n 

2、hash(哈希表)

哈希表结构

hset table field value 

hmset table field1 val1 field2 val2 ... 

hget table field 

hmget table field1 field2 field3 ... 

hdel table field 

hgetall table 

hkeys table 

hvals table 

3、list(列表)

FIFO结构,用链表实现,支持快速插入元素,但查找性能比较低

lpush list node                  在list头部插入 

rpush list node                 在list尾部插入 

lpop list                           在list头部删除 

rpop list                          在list尾部删除 

linsert list   before val_b node          在val_b前插入新元素val 

lrange list start end          返回list的一个切片 list[start:end],双闭区间,索引可以为负数,-1表示最后一个元素,-2表示倒数第二个元素 

ltrim list start end             对list进行裁减,只保留指定范围内的元素 

llen list                            list长度 

4、set(集合)

将一系列不重复的值存储成一个集合

sadd set element          往集合中添加元素 

srem set element         从集合中删除指定元素 

smembers set        返回集合所有元素 

sinter set1 set2     取交集 

sunion set1 set2    取并集 

sdiff   set1 set2     取差集 

5、sorted set(有序集合)

与set类似,但sorted set中的数据有一个score属性,集合中的所有元素按照其score排序。

sorted set采用了skip list结构的实现,插入一个元素的时间复杂度是O(logN)

zadd sorted_set score member                                   添加元素,并指定score 

zscore sorted_set member                                         返回指定元素的score 

zrange sorted_set start end  [  withscores]   返回从start到end次序的元素,zrange sorted_set 0 -1 返回所有member 

zrevrange sorted_set start end                                   反序,按score从大到小的顺序返回 

zrangebyscore sorted_set min_score max_score          返回score在指定范围内的元素 

zcard sorted_set                                                       返回集合中的元素个数 

zcount sorted_set  min max                                       返回集合中在指定分数范围内的元素个数                                        

zremrangebyscore sorted_set min_score max_score    删除score在指定范围内的元素 

zrank sorted_set member                                          返回元素在集合中的排名(从0开始计算) 

zincrby sorted_set increment member                         为指定元素的score加上一个增量increment 

zrem sorted_set member                                           删除指定元素 

 

 

 

 

6、publish/subscribe(订阅)

可以将数据推送到某个信息管道中,然后其他人可以通过订阅这些管道来获取推送过来的信息。

publish channlone key 

subscribe channlone 

常用命令:

info 打印redis信息 

select n                               选取数据库(默认支持16个db) 

move key n                           将key从当前库移至指定数据库 

flushdb 清空当前数据库 

flushall 清空所有数据库 

config get parameter 读取服务器的运行时参数(redis.conf文件中的配置项) 

config set parameter value 重新配置运行时参数 

save 保存数据快照(dump.rdb) 

bgsave

bgrewriteaof 压缩aof持久化文件 

shutdown 停止所有客户端,同时以阻塞的方式执行内存数据持久化 

slaveof host port 修改SLAVE服务器的复制设置 

管线(pipelining)

客户端在发送命令之后,不用立即等待来自服务器的响应,而是可以继续发送后面的命令,

在命令发送完毕之后,再一次性的读取之前所有命令的应答。

持久化(persistence)

Redis 的数据持久化是通过将内存中的数据同步到磁盘来实现的,Redis支持两种持久化方式:

1、  Snapshotting ,将内存中的数据以快照方式写入二进制文件中,默认文件名为dump.rdb。 

相关配置:

save seconds changed     # 在指定时间内,如果超过changed个key被修改,则发起快照保存

快照保存过程:

  • fork一个子进程,父进程继续处理client请求,子进程负责将内存内容写入临时文件;
  • 由于os的写时复制技术(copy on write),当父进程处理写请求时,os会为其要修改的页面创建副本,所以子进程的地址空间数据是fork时刻整个数据库的一个快照;
  • 子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。

使用snap shot方式,当Redis物理内存使用超过内存总量的3/5时就会开始有crash的风险。

fork调用的copy-on-write机制是基于操作系统页这个单位的,也就是只有写入的脏页会被复制,通常系统不会在短时间内所有页都发生了写入而导致复制。

crash的真正原因是持久化使用了Buffer IO,所谓Buffer IO是指Redis对持久化文件的写入和读取操作都会使用物理内存的Page Cache。

2、  Append-only file(aof) ,快照方式实在一定间隔时间做一次,如果redis发送了意外crash,就会丢失最后一次快照后的所有修改。 

aof方式会将每一个收到的写命令通过write函数追加到文件中(默认是appendonly.aof),当redis重启时通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。

相关配置:

appendonly yes                      # 启用aof持久化方式;

appendfsync always               # 每次收到写命令就立即强制写入磁盘,最慢,但是保证完全的持久化;

appendfsync everysec            # 每秒强制写入磁盘一次

appendfsync no                     # 依赖os内核自身的缓存机制

redis-check-aof --fix <filename>          # 修复损坏的AOF文件

aof方式类似mysql的基于语句的binlog方式,可能会导致log文件体积过大,当系统重启恢复数据时如果是aof方式则加载数据会非常慢。

事务(transactions)

事务特征:

1、在事务中的所有命令都会被串行化的顺序执行,事务执行期间,Redis不会再为client的请求提供任何服务,从而保证事务中的所有命令被原子的执行;

2、Redis事务中如果有一条命令执行失败,其后的命令仍然会继续执行;

3、当使用aof模式时,Redis会将事务内的所有写操作在本次调用中全部写入磁盘,如果在写入的过程中出现崩溃(如断电),那么此时也许只有部分数据被写入磁盘,Redis服务器在重新启动时执行一系列必要的一致性检测,如果发现问题,可以将已写入的部分数据进行回滚。

事务的提交和回滚操作:

1、multi...exec的命令组合类似于关系数据库的BEGIN TRANSACTION ... COMMIT语句;

watch key1, key2... 

multi

cmd1

cmd2

...

exec

2、multi...discard的命令组合类似于关系数据库的BEGIN TRANSACTION ... ROLLBACK语句;

multi

cmd1

cmd2

...

discard

在multi命令执行之前,可以使用watch命令指定待监控的keys;

然后在执行EXEC之前,如果被监控的keys发生了修改(被其它客户端更改了),EXEC将放弃执行该事务队列中的所有命令。

在事务中,可以使用unwatch命令取消当前事务监控的keys;

如果已经执行了EXEC或DISCARD命令,则无需再手工执行unwatch命令,因为在此之后,事务中所有被监控的keys都将自动取消。

主从复制(replication)

Replication的特征:

1、同一个Master可以同步多个Slaves;

2、Master Server以非阻塞的方式为Slaves提供服务,因此,在主从同步期间,client仍可以提交查询或修改请求;

3、

Replication的工作原理:

在Slave启动并连接到Master之后,它将主动发送一个SYNC命令,此后Master将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,

在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave服务器在接收到数据库文件数据之后将其存盘并加载内存中。

此后, Master继续将所有已收集到的修改命令,和新的修改命令一次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。

虚拟内存( virtual memory)

Redis的虚拟内存是为了保证key的查找速度,只会将value交换到swap文件中。

因此,如果Redis的内存问题是由于太多value很小的key造成的,那么虚拟内存并不解决问题。

Redis没有使用操作系统提供的虚拟内存机制,而是实现了自己的虚拟内存机制,主要是因为以下两点:

1、操作系统的虚拟内存是以4K页面为最小单位进行的,而redis的大多数对象都远小于4K;

2、Redis可以将交换到磁盘的对象进行压缩,一般压缩后的对象回比内存中的对象小10倍;

相关配置:

vm-enabled yes                   # 打开虚拟内存功能

vm-max-memory bytes         # Redis使用的内存上限

vm-swap-file path                # 交换出来的value保存的文件路径

vm-page-size bytes             # 页面大小

vm-pages  number              # 页面数量的上限

vm-max-threads num          # 执行value换入换出的工作线程数量

一个value可以保持在多个page里面,但一个page只能保存一个value;

在Redis使用的内存没超过vm-max-memory之前是不会交换任何value的。

当超过最大内存限制后,Redis优先选择过期或较大的对象进行交换:

swappablility = age * log(size_in_memory)

vm-max-threads=0时,会启用阻塞式虚拟内存,以同步方式执行I/O操作。

通信协议(Protocol)

http://www.redisdoc.com/en/latest/topic/protocol.html

*<参数数量> CR LF

$<参数 1 的字节数量> CR LF

<参数 1 的数据> CR LF

...

$<参数 N 的字节数量> CR LF

<参数 N 的数据> CR LF

注意:命令本身也作为协议的一个参数来传送;

比如:client要向server发送如下命令:set mykey myvalue

则格式化成协议的数据为:

"*3 $3 SET $5 mykey $7 myvalue "

Redis命令会返回不同类型的回复,每种类型的回复以第一个字节区分:

1、status reply: "  + ",例如:"+OK " 

2、error reply: "  - ",例如:"-ERR unknown command 'foobar'" 

3、interger reply: "  : ",例如:":1000 " 

4、bulk reply: "  $ ",例如:"$6 foobar " 

5、multi bulk reply: "  * ",例如:"*4 $3 foo $3 bar $5 Hello $5 World " 

status reply通常是由那些不需要返回数据的命令返回(如set命令),这种回复不是binary safe的;

bulk reply用来返回binary safe字符串,字符串的最大长度为512M,常用于get命令的返回结果;

如果请求的key不存在,会返回"$-1 ",这称为NULL Bulk Reply;

multi bulk reply常用于lrange这样的命令,它返回多个值。

Empty Multi Bulk Reply: "*0 "

NULL Multi Bulk Reply: "*-1 "

C 客户端官

官网:

http://github.com/redis/hiredis

安装方法:

git clone https://github.com/redis/hiredis

$ cd hiredis

$ make

$ make install

编译:

以hiredis自带的example.c程序为例:

gcc  -lhiredis  example.c