NoSQL数据库Redis(REmote DIctionary Server)使用介绍和特性

来源:互联网 发布:ubuntu 16.04应用商店 编辑:程序博客网 时间:2024/04/30 01:59
下面先对Redis做比较系统的介绍,对Redis的特性及各种数据类型及操作进行了介绍。

1.介绍

Redis 是一个由Salvatore Sanfilippo写的免费开源的key-value存储系统,通常被认为是一个数据结构服务器。

优点如下:

性能高 – Redis能支持超过 100K+ 每秒的读写频率。
丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

2.数据类型

有着丰富的数据结构 strings、hashes 、 list、sets、 sorted sets

(1) String类型

Redis能存储二进制安全的字符串,最大长度为1GB
redis 127.0.0.1:6379> SET name "John Doe" 
OK 
redis 127.0.0.1:6379> GET name 
"John Doe" 
String类型还支持批量的读写操作 
redis 127.0.0.1:6379> MSET age 30 sex "male" 
OK 
redis 127.0.0.1:6379> MGET age sex 
1) "30" 
2) "male"

String类型其实也可以用来存储数字,并支持对数字的加减操作。
redis 127.0.0.1:6379> INCR age 
(integer) 31 
redis 127.0.0.1:6379> INCRBY age 4 
(integer) 35 
redis 127.0.0.1:6379> GET age 
"35" 
redis 127.0.0.1:6379> DECR age 
(integer) 34 
redis 127.0.0.1:6379> DECRBY age 4 
(integer) 30 
redis 127.0.0.1:6379> GET age 
"30"

String类型还支持对其部分的修改和获取操作
redis 127.0.0.1:6379> APPEND name " Mr." 
(integer) 12 
redis 127.0.0.1:6379> GET name 
"John Doe Mr." 
redis 127.0.0.1:6379> STRLEN name 
(integer) 12 
redis 127.0.0.1:6379> SUBSTR name 0 3 
"John"

(2) List类型

Redis能够将数据存储成一个链表,并能对这个链表进行丰富的操作
redis 127.0.0.1:6379> LPUSH students "John Doe" 
(integer) 1 
redis 127.0.0.1:6379> LPUSH students "Captain Kirk" 
(integer) 2 
redis 127.0.0.1:6379> LPUSH students "Sheldon Cooper" 
(integer) 3 
redis 127.0.0.1:6379> LLEN students 
(integer) 3 

redis 127.0.0.1:6379> LRANGE students 0 2 
1) "Sheldon Cooper" 
2) "Captain Kirk" 
3) "John Doe" 
redis 127.0.0.1:6379> LPOP students 
"Sheldon Cooper" 
redis 127.0.0.1:6379> LLEN students 
(integer) 2 
redis 127.0.0.1:6379> LRANGE students 0 1 
1) "Captain Kirk" 
2) "John Doe" 
redis 127.0.0.1:6379> LREM students 1 "John Doe" 
(integer) 1 
redis 127.0.0.1:6379> LLEN students 
(integer) 1 
redis 127.0.0.1:6379> LRANGE students 0 0 
1) "Captain Kirk"

Redis也支持很多修改操作
redis 127.0.0.1:6379> LINSERT students BEFORE "Captain Kirk" "Dexter Morgan" 
(integer) 3 
redis 127.0.0.1:6379> LRANGE students 0 2 
1) "Dexter Morgan" 
2) "Captain Kirk" 
3) "John Doe" 
redis 127.0.0.1:6379> LPUSH students "Peter Parker" 
(integer) 4 
redis 127.0.0.1:6379> LRANGE students 0 3 
1) "Peter Parker" 
2) "Dexter Morgan" 
3) "Captain Kirk" 
4) "John Doe" 
redis 127.0.0.1:6379> LTRIM students 1 3 
OK 
redis 127.0.0.1:6379> LLEN students 
(integer) 3 
redis 127.0.0.1:6379> LRANGE students 0 2 
1) "Dexter Morgan" 
2) "Captain Kirk" 
3) "John Doe" 
redis 127.0.0.1:6379> LREM students 1 "John Doe" 
(integer) 1 
redis 127.0.0.1:6379> LLEN students 
(integer) 1 
redis 127.0.0.1:6379> LRANGE students 0 1 
1) "Captain Kirk"       

(3) 集合(Sets)类型

Redis能够将一系列不重复的值存储成一个集合
redis 127.0.0.1:6379> SADD birds crow 
(integer) 1 
redis 127.0.0.1:6379> SADD birds pigeon 
(integer) 1 
redis 127.0.0.1:6379> SADD birds bat 
(integer) 1 
redis 127.0.0.1:6379> SADD mammals dog 
(integer) 1 
redis 127.0.0.1:6379> SADD mammals cat 
(integer) 1 
redis 127.0.0.1:6379> SADD mammals bat 
(integer) 1 
redis 127.0.0.1:6379> SMEMBERS birds 
1) "bat" 
2) "crow" 
3) "pigeon" 
redis 127.0.0.1:6379> SMEMBERS mammals 
1) "bat" 
2) "cat" 
3) "dog"

Sets结构也支持相应的修改操作
redis 127.0.0.1:6379> SREM mammals cat 
(integer) 1 
redis 127.0.0.1:6379> SMEMBERS mammals 
1) "bat" 
2) "dog" 
redis 127.0.0.1:6379> SADD mammals human 
(integer) 1 
redis 127.0.0.1:6379> SMEMBERS mammals 
1) "bat" 
2) "human" 
3) "dog"

Redis还支持对集合的子交并补等操作
redis 127.0.0.1:6379> SINTER birds mammals 
1) "bat" 
redis 127.0.0.1:6379> SUNION birds mammals 
1) "crow" 
2) "bat" 
3) "human" 
4) "pigeon" 
5) "dog" 
redis 127.0.0.1:6379> SDIFF birds mammals 
1) "crow" 
2) "pigeon"

(4) 有序集合(Sorted Sets)类型

Sorted Sets和Sets结构相似,不同的是存在Sorted Sets中的数据会有一个score属性,并会在写入时就按这个score排好序。
redis 127.0.0.1:6379> ZADD days 0 mon 
(integer) 1 
redis 127.0.0.1:6379> ZADD days 1 tue 
(integer) 1 
redis 127.0.0.1:6379> ZADD days 2 wed 
(integer) 1 
redis 127.0.0.1:6379> ZADD days 3 thu 
(integer) 1 
redis 127.0.0.1:6379> ZADD days 4 fri 
(integer) 1 
redis 127.0.0.1:6379> ZADD days 5 sat 
(integer) 1 
redis 127.0.0.1:6379> ZADD days 6 sun 
(integer) 1 
redis 127.0.0.1:6379> ZCARD days 
(integer) 7 
redis 127.0.0.1:6379> ZRANGE days 0 6 
1) "mon" 
2) "tue" 
3) "wed" 
4) "thu" 
5) "fri" 
6) "sat" 
7) "sun" 
redis 127.0.0.1:6379> ZSCORE days sat 
"5" 
redis 127.0.0.1:6379> ZCOUNT days 3 6 
(integer) 4 
redis 127.0.0.1:6379> ZRANGEBYSCORE days 3 6 
1) "thu" 
2) "fri" 
3) "sat" 
4) "sun"

(5) Hash类型

Redis能够存储key对多个属性的数据(比如user1.uname user1.passwd)
redis 127.0.0.1:6379> HKEYS student 
1) "name" 
2) "age" 
3) "sex" 
redis 127.0.0.1:6379> HVALS student 
1) "Ganesh" 
2) "30" 
3) "Male" 
redis 127.0.0.1:6379> HGETALL student 
1) "name" 
2) "Ganesh" 
3) "age" 
4) "30" 
5) "sex" 
6) "Male" 
redis 127.0.0.1:6379> HDEL student sex 
(integer) 1 
redis 127.0.0.1:6379> HGETALL student 
1) "name" 
2) "Ganesh" 
3) "age" 
4) "30"

Hash数据结构能够批量修改和获取
redis 127.0.0.1:6379> HMSET kid name Akshi age 2 sex Female 
OK 
redis 127.0.0.1:6379> HMGET kid name age sex 
1) "Akshi" 
2) "2" 
3) "Female" 

3.Publish/Subscribe


3、订阅发布

Redis支持这样一种特性,你可以将数据推到某个信息管道中,然后其它人可以通过订阅这些管道来获取推送过来的信息。
3.1 订阅信息管道
用一个客户端订阅管道
redis 127.0.0.1:6379> SUBSCRIBE channelone 
Reading messages... (press Ctrl-C to quit) 
1) "subscribe" 
2) "channelone" 
3) (integer) 1

另一个客户端往这个管道推送信息
redis 127.0.0.1:6379> PUBLISH channelone hello 
(integer) 1 
redis 127.0.0.1:6379> PUBLISH channelone world 
(integer) 1                     

然后第一个客户端就能获取到推送的信息
redis 127.0.0.1:6379> SUBSCRIBE channelone 
Reading messages... (press Ctrl-C to quit) 
1) "subscribe" 
2) "channelone" 
3) (integer) 1 
1) "message" 
2) "channelone" 
3) "hello" 
1) "message" 
2) "channelone" 
3) "world"

3.2 按一定模式批量订阅
用下面的命令订阅所有channel开头的信息通道
redis 127.0.0.1:6379> PSUBSCRIBE channel* 
Reading messages... (press Ctrl-C to quit) 
1) "psubscribe" 
2) "channel*" 
3) (integer) 1

在另一个客户端对两个推送信息
redis 127.0.0.1:6379> PUBLISH channelone hello 
(integer) 1 
redis 127.0.0.1:6379> PUBLISH channeltwo world 
(integer) 1

然后在第一个客户端就能收到推送的信息
redis 127.0.0.1:6379> PSUBSCRIBE channel* 
Reading messages... (press Ctrl-C to quit) 
1) "psubscribe" 
2) "channel*" 
3) (integer) 1 
1) "pmessage" 
2) "channel*" 
3) "channelone" 
4) "hello" 
1) "pmessage" 
2) "channel*" 
3) "channeltwo" 
4) "world"

4、数据过期设置

Redis支持按key设置过期时间,过期后值将被删除(在客户端看来是补删除了的)
用TTL命令可以获取某个key值的过期时间(-1表示永不过期)
redis 127.0.0.1:6379> SET name "John Doe" 
OK 
redis 127.0.0.1:6379> TTL name 
(integer) -1
下面命令先用EXISTS命令查看key值是否存在,然后设置了5秒的过期时间

redis 127.0.0.1:6379> SET name "John Doe" 
OK 
redis 127.0.0.1:6379> EXISTS name 
(integer) 1 
redis 127.0.0.1:6379> EXPIRE name 5 
(integer) 1
5秒后再查看
redis 127.0.0.1:6379> EXISTS name 
(integer) 0 
redis 127.0.0.1:6379> GET name 
(nil)
这个值已经没有了。
上在是直接设置多少秒后过期,你也可以设置在某个时间点过期,下面例子是设置2011-09-24 00:40:00过期。

redis 127.0.0.1:6379> SET name "John Doe" 
OK 
redis 127.0.0.1:6379> EXPIREAT name 1316805000 
(integer) 1 
redis 127.0.0.1:6379> EXISTS name 
(integer) 0

5、事务性

Redis本身支持一些简单的组合型的命令,比如以NX结尾命令都是判断在这个值没有时才进行某个命令。
redis 127.0.0.1:6379> SET name "John Doe" 
OK 
redis 127.0.0.1:6379> SETNX name "Dexter Morgan" 
(integer) 0 
redis 127.0.0.1:6379> GET name 
"John Doe" 
redis 127.0.0.1:6379> GETSET name "Dexter Morgan" 
"John Doe" 
redis 127.0.0.1:6379> GET name 
"Dexter Morgan"

当然,Redis还支持自定义的命令组合,通过MULTI和EXEC,将几个命令组合起来执行
redis 127.0.0.1:6379> SET counter 0 
OK 
redis 127.0.0.1:6379> MULTI 
OK 
redis 127.0.0.1:6379> INCR counter 
QUEUED 
redis 127.0.0.1:6379> INCR counter 
QUEUED 
redis 127.0.0.1:6379> INCR counter 
QUEUED 
redis 127.0.0.1:6379> EXEC 
1) (integer) 1 
2) (integer) 2 
3) (integer) 3 
redis 127.0.0.1:6379> GET counter 
"3"

你还可以用DICARD命令来中断执行中的命令序列
redis 127.0.0.1:6379> SET newcounter 0 
OK 
redis 127.0.0.1:6379> MULTI 
OK 
redis 127.0.0.1:6379> INCR newcounter 
QUEUED 
redis 127.0.0.1:6379> INCR newcounter 
QUEUED 
redis 127.0.0.1:6379> INCR newcounter 
QUEUED 
redis 127.0.0.1:6379> DISCARD 
OK 
redis 127.0.0.1:6379> GET newcounter 
"0"


6、持久化

Redis的所有数据都存储在内存中,但是他也提供对这些数据的持久化。

(1) 数据快照
数据快照的原理是将整个Redis中存的所有数据遍历一遍存到一个扩展名为rdb的数据文件中。通过SAVE命令可以调用这个过程。
redis 127.0.0.1:6379> SET name "John Doe" 
OK 
redis 127.0.0.1:6379> SAVE 
OK 
redis 127.0.0.1:6379> SET name "Sheldon Cooper" 
OK 
redis 127.0.0.1:6379> BGSAVE 
Background saving started
如果你是使用的brew在Mac OSX上安全的Redis,那么rdb文件会存在如下路径
/usr/local/var/db/redis/dump.rdb        

(2) Append-Only File(追加式的操作日志记录)
Redis还支持一种追加式的操作日志记录,叫append only file,其日志文件以aof结局,一般称为aof文件。要开启aof日志的记录,你需要在配置文件中进行如下设置:
appendonly yes
这时候你所有的操作都会记录在aof日志文件中

redis 127.0.0.1:6379> GET name 
(nil) 
redis 127.0.0.1:6379> SET name "Ganesh Gunasegaran" 
OK 
redis 127.0.0.1:6379> EXIT 
→ cat /usr/local/var/db/redis/appendonly.aof 
*2 
$6 
SELECT 
$1 

*3 
$3 
SET 
$4 
name 
$18 

Ganesh Gunasegaran


7、管理命令

Redis支持多个DB,默认是16个,你可以设置将数据存在哪一个DB中,不同DB间的数据具有隔离性。也可以在多个DB间移动数据。
redis 127.0.0.1:6379> SELECT 0 
OK 
redis 127.0.0.1:6379> SET name "John Doe" 
OK 
redis 127.0.0.1:6379> SELECT 1 
OK 
redis 127.0.0.1:6379[1]> GET name 
(nil) 
redis 127.0.0.1:6379[1]> SELECT 0 
OK 
redis 127.0.0.1:6379> MOVE name 1 
(integer) 1 
redis 127.0.0.1:6379> SELECT 1 
OK 
redis 127.0.0.1:6379[1]> GET name 
"John Doe"


Redis还能进行一些如下操作,获取一些运行信息
redis 127.0.0.1:6379[1]> DBSIZE 
(integer) 1 
redis 127.0.0.1:6379[1]> INFO 
redis_version:2.2.13 
redis_git_sha1:00000000 
redis_git_dirty:0 
arch_bits:64 
multiplexing_api:kqueue 
......


Redis还支持对某个DB数据进行清除(当然清空所有数据的操作也是支持的)
redis 127.0.0.1:6379> SET name "John Doe" 
OK 
redis 127.0.0.1:6379> DBSIZE 
(integer) 1 
redis 127.0.0.1:6379> SELECT 1 
OK 
redis 127.0.0.1:6379[1]> SET name "Sheldon Cooper" 
OK 
redis 127.0.0.1:6379[1]> DBSIZE 
(integer) 1 
redis 127.0.0.1:6379[1]> SELECT 0 
OK 
redis 127.0.0.1:6379> FLUSHDB 
OK 
redis 127.0.0.1:6379> DBSIZE 
(integer) 0 
redis 127.0.0.1:6379> SELECT 1 
OK 
redis 127.0.0.1:6379[1]> DBSIZE 
(integer) 1 
redis 127.0.0.1:6379[1]> FLUSHALL 
OK 
redis 127.0.0.1:6379[1]> DBSIZE 
(integer) 0

8、客户端

Redis的客户端很丰富,几乎所有流行的语言都有其客户端,可以上Redis的Clients页面去查找。

hiredis是redis的c客户端,使用时需要注意其操作的同步特性:

(1)block方式:

每个命令都是单独发向Redis的,且也会等待每个的结果返回。即,通过redisCommand调用,即完成了向Redis发送命令,也等待Redis返回结果。换言之,是一个阻塞的过程。如果在是并发量比较高的情况下,此种方式,会使得客户端效率较差。即便是将Redis部署在本地,通过local进行访问,也会有0.02毫秒级别的等待过程。如果客户端有很多次的访问操作,每次都会阻塞一小段时间,会使得客户端本身的处理速度降下来。为了降低这种开销,可以采用pipeline的方式。也即一次向Redis发送多个命令。将这多个命令发送完毕后,再进行统一处理。当然,这样的代价是客户端的发送缓冲区会变大,接收缓冲区也会变大。但处理的吞吐量会增加。

(2)non-block方式:

默认的调用redisCommand就会立即返回,相当于block模式下显式的调用AppendCommand。在non-block方式下,要显式的调用获取回应的replay,并将其释放掉,以免造成内存泄漏。

9、Redis数据恢复

(1)数据快照

数据快照的原理是将整个Redis内存中存的所有数据遍历一遍存到一个扩展名为rdb的数据文件中.通过SAVE命令可以调用这个过程.

数据快照配置
save 900 1
save 300 10
save 60 10000
以上在redis.conf中的配置指出在多长时间内,有多少次更新操作,就将数据同步到数据文件,这个可以多个条件配合.上面的含义是900秒后有一个
key发生改变就执行save,300秒后有10个key发生改变执行save,60秒有10000个key发生改变执行save


数据快照的缺点

是持久化之后如果出现crash则会丢失一段数据,因此作者增加了另外一种追加式的操作日志记录,叫append only file,其日志文件以aof结尾,我们一般称为aof文件.
要开启aof日志的记录,需要在配置文件中进行如下设置:
appendonly yes

(2)aof日志

appendonly配置如果不开启,可能会在断电时导致一段时间内的数据丢失.

因为redis本身同步数据文件是按save条件来同步的,所以有的数据会在一段时间内只存在于内存中.
appendfsync no/always/everysec 

1. no:表示等操作系统进行数据缓存同步到磁盘.
2. always:表示每次更新操作后手动调用fsync() 将数据写到磁盘.
3. everysec:表示每秒同步一次.一般用everysec.

AOF文件只增不减会导致文件越来越大,重写过程如下
1. Redis通过fork产生子进程.
2. 子进程将当前所有数据写入一个临时文件.
3. 父子进程是并行执行的,在子进程遍历并写临时文件的时候,父进程在照常接收请求,处理请求,写AOF,不过这时他是把新来的AOF写在一个缓冲区中.
4. 子进程写完临时文件后就会退出.这时父进程会接收到子
进程退出的消息,他会把自己现在收集在缓冲区中的所有AOF追加在临时文件中.
5. 最后把临时文件rename一下,改名为appendonly.aof, 这时原来的aof文件被覆盖.整个过程完成.

(3)恢复数据

当Redis服务器挂掉时,重启时将按以下优先级恢复数据到内存中:
1. 如果只配置了AOF,重启时加载AOF文件恢复数据.
2.如果同时配置了RBD和AOF,启动时只加载AOF文件恢复数据.
3.如果只配置了RDB,启动时将加载dump文件恢复数据.

10、Redis主从复制

(1)Master/Slave配置

Master IP:175.41.209.118
Master Redis Server Port:6379

Slave配置很简单,只需要在slave服务器的redis.conf加入:
slaveof 175.41.209.118 6379
启动master和slave,然后写入数据到master,读取slave,可以看到数据被复制到slave了.
用途:读写分离,数据备份,灾难恢复等

(2)Redis主从复制过程

配置好slave后,slave与master建立连接,然后发送sync命令. 无论是第一次连接还是重新连接,master都会启动一个后台进程,将数据库快照保存到文件中,同时master主进程会开始收集新的写命令并缓存. 后台进程完成写文件后,master就发送文件给slave,slave将文件保存到硬盘上,再加载到内存中, 接着master就会把缓存的命令转发给slave,后续master将收到的写命令发送给slave. 如果master同时收到多个slave发来的同步连接命令,master只会启动一个进程来写数据库镜像, 然后发送给所有的slave.

(3)Redis主从复制特点

1. master可以拥有多个slave.
2. 多个slave可以连接同一个master外,还可以连接到其他slave.
3. 主从复制不会阻塞master,在同步数据时,master可以继续处理client请求.
4. 可以在master禁用数据持久化,注释掉master配置文件中的所有save配置,只需在slave上配置数据持久化.
5. 提高系统的伸缩性.

(4)Redis主从复制速度

官方提供了一个数据, Slave在21秒即完成了对Amazon网站 10G key set的复制.


11、 跟传统存储差异

(1)跟sql server、mySQL等关系型数据库差异
 redis目前还只能作为小数据量存储(全部数据能够加载在内存中) ,海量数据存储方面并不是redis所擅长的领域 
 设计、实现方法很不一样.关系型数据库通过表来存储数据,通过SQL来查询数据。而Redis通上述五种数据结构来存储数据,通过命令 来查询数据 
(2)跟Memcached等缓存系统差异
网络IO模型方面:

Memcached是多线程,分为监听线程、worker线程,引入锁,带来了性能损耗。Redis使用单线程的IO复用模型,将速度优势发挥到最大,也提供了较简单的计算功能
内存管理方面:

Memcached使用预分配的内存池的方式,带来一定程度的空间浪费 并且在内存仍然有很大空间时,新的数据也可能会被剔除,而Redis使用现场申请内存的方式来存储数据,不会剔除任何非临时数据 Redis更适合作为存储而不是cache 
数据的一致性方面:

Memcached提供了cas命令来保证.而Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何操作打断 
存储方式方面:

Memcached只支持简单的key-value存储,不支持枚举,不支持持久化和复制等功能。redis很大程度弥补了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。

12、 内存优化

通过我们上面的一些实现上的分析可以看出redis实际上的内存管理成本非常高,即占用了过多的内存,作者对这点也非常清楚,所以提供了一系列的参数和手段来控制和节省内存。

(1)虚拟内存功能

首先最重要的一点是不要开启Redis的VM选项,即虚拟内存功能,这个本来是作为Redis存储超出物理内存数据的一种数据在内存与磁盘换入换出的一个持久化策略,但是其内存管理成本也非常的高,并且此种持久化策略并不成熟,所以要关闭VM功能,请检查你的redis.conf文件中 vm-enabled 为 no。

(2)最大使用内存

其次最好设置下redis.conf中的maxmemory选项,该选项是告诉Redis当使用了多少物理内存后就开始拒绝后续的写入请求,该参数能很好的保护好你的Redis不会因为使用了过多的物理内存而导致swap,最终严重影响性能甚至崩溃。

(3)数据类型内存参数

Redis为不同数据类型分别提供了一组参数来控制内存使用,我们在前面提到过Redis Hash的value内部是一个HashMap,如果该Map的成员数比较少,则会采用一维数组的方式来紧凑存储该Map,即省去了大量指针的内存开销,

这个参数在redis.conf配置文件中下面2项:
hash-max-zipmap-entries 64
hash-max-zipmap-value 512


hash-max-zipmap-entries:

含义是当value这个Map内部不超过多少个成员时会采用线性紧凑格式存储,默认是64,即value内部有64个以下的成员就是使用线性紧凑存储,超过该值自动转成真正的HashMap.
hash-max-zipmap-value :

含义是当value这个Map内部的每个成员值长度不超过多少字节就会采用线性紧凑存储来节省空间.
以上2个条件任意一个条件超 过设置值都会转换成真正的HashMap,也就不会再节省内存了.

那么这个值是不是设置的越大越好呢,答案当然是否定的,HashMap的优势就是查找和操作的时间复杂度都是O(1)的,而放弃Hash采用一维存储则是O(n)的时间复杂度,如果成员数量很少,则影响不大,否则会严重影响性能,所以要权衡好这个值的设置,总体上还是时间成本和空间成本上的权衡.

同样类似的参数
list-max-ziplist-entries 512
说明:list数据类型多少节点以下会采用去指针的紧凑存储格式。
list-max-ziplist-value 64
说明:list数据类型节点值大小小于多少字节会采用紧凑存储格式。
set-max-intset-entries 512
说明:set数据类型内部数据如果全部是数值型,且包含多少节点以下会采用紧凑格式存储。

13、Redis 集群

当前稳定版本的redis(2.4.5)只支持简单的master-slave replication: 一个master写,多个slave读.只能通过客户端一致性哈希自己做sharding.
Redis cluster是下一阶段最重要的功能之一,会有集群的自动sharding,多节点容错等. 集群功将在3.0版本推出.

(1)Redis使用在旅馆的例子

1)一主一从

Master提供读服务,Slave提供写服务

使用亚马逊AWS虚拟机,机器配置如下:
7.5 GB memory
4 EC2 Compute Units (2 virtual cores with 2 
EC2 Compute Units each)
64-bit platform
I/O Performance: High

2)数据量

每天约更新30万左右的数据,现在库里有400W条纪录(400W个Key,使用的是Hash结构存储),每条数据都设有过期时间,占用了2.5G的内存.
为了提高读写性能Master关闭了Persistence功能,Slave只负责同步备份Master的数据,不对外提供服务.另一种可选方案是用Master提供写服务,Slave提供读服务来
实现读写分离.
 
(3)Master开启Save功能
在dump过程中,除了磁盘有大量的IO操作以外,Redis是fork一个子进程来dump数据到硬盘,原有进程占用30%+的CPU,dump数据的子进程单独另外占用一个CPU.
Master开启Save对性能的直接影响:
TPS大概减少30%.
Choice Master Redis服务器开启Save功能后的明显影响是: 
机器Load一直居高不下,大量请求超时. 
关闭Save功能后服务器压力锐减,基本无请求超时情况发生.
 
(4)Redis开启AOF日志功能
对性能有影响,但是由于每次追加的数据量小,所以对性能的影响相对小很多.Choice Master Reids开启AOF功能后,机器load 微升,对性能无明显影响.
 
(5)bgrewriteaof对性能影响
为了定时减小AOF文件的大小,Redis2.4以后增加了自动的bgrewriteaof的功能,Redis会选择一个自认为负载低的情况下执行bgrewriteaof,这个重写AOF文件的过程是很影响性能的.
Master开启自动bgrewriteaof功能对系统的明显影响是:
高并发时段有请求超时,机器load 明显上升几倍.
 
(6)目前较好的方案

Master提供读服务,Slave提供持久性备份服务
Mater关闭Save功能,关闭AOF日志功能,以求达到性能最佳. 
Slave开启Save并开启AOF日志功能,并开启bgrewriteaof 功能,不对外提供服务,这样Slave的负载总体上会一直略高于Master负载,但Master性能达到最好.
 
(7)总结

数据结构上:旅店的价格存储使用Redis的Hash 结构也非常适合,HotelCode+Date最为key, 这样
的key很容易设置过期,RatePlan+RoomType作为Filed, 价格和流量是Value.

性能上:从目前使用的情况来看,总体效果还是比较理想的。目前每天从GTA到Choice大约500w个请求,整个过程80%的请求在500毫秒内返回,基本无超时现象发生.


14、其他特性

(1)性能特性

1. 速度快:使用标准C写,所有数据都在内存中完成,读写速度分别达到10万/20万 

2. 持久化:对数据的更新采用Copy-on-write技术,可以异步地保存到磁盘上,主要有两种策略,一是根据时间,更新次数的快照(save 300 10 )二是基于语句追加方式(Append-only file,aof) 
3. 快速的主--从复制,官方提供了一个数据,Slave在21秒即完成了对Amazon网站10G key set的复制。 

(2)数据操作

 自动操作:对不同数据类型的操作都是自动的,很安全 


(3)拓展特性

1. Sharding技术: 很容易将数据分布到多个Redis实例中,数据库的扩展是个永恒的话题,在关系型数据库中,主要是以添加硬件、以分区为主要技术形式的纵向扩展解决了很多的应用场景,但随着web2.0、移动互联网、云计算等应用的兴起,这种扩展模式已经不太适合了,所以近年来,像采用主从配置、数据库复制形式的,Sharding这种技术把负载分布到多个特理节点上去的横向扩展方式用处越来越多。
2. 提高了DB的可扩展性,只需要将新加的数据放到新加的服务器上就可以了 
3. 提高了DB的可用性,只影响到需要访问的shard服务器上的数据的用户 
4. 提高了DB的可维护性,对系统的升级和配置可以按shard一个个来搞,对服务产生的影响较小 
5. 小的数据库存的查询压力小,查询更快,性能更好

15、redis使用注意

1. 要进行Master-slave配置,出现服务故障时可以支持切换。 
2. 在master侧禁用数据持久化,只需在slave上配置数据持久化。 
3. 物理内存+虚拟内存不足,这个时候dump一直死着,时间久了机器挂掉。这个情况就是灾难! 
4. 当Redis物理内存使用超过内存总容量的3/5时就会开始比较危险了,就开始做swap,内存碎片大 
5. 当达到最大内存时,会清空带有过期时间的key,即使key未到过期时间. 
6. redis与DB同步写的问题,先写DB,后写redis,因为写内存基本上没有问题


0 0
原创粉丝点击