分类: NOSQL
2015-06-15 15:14:55
事务处理
Redis对事务的支持目前还比较简单。Redis只能保证一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令。当一个client在一个连接中发出multi命令时,这个连接会进入一个事务上下文,该连接后续的命令不会立即执行,而是先放到一个队列中,当执行exec命令时,redis顺序的执行队列中的所有命令。
简单的事务处理:
127.0.0.1:6379> get age
"20"
127.0.0.1:6379> multi 打开一个上下文
OK
127.0.0.1:6379> set age 10
QUEUED 返回QUEUED表示将上面的这条命令放入队列
127.0.0.1:6379> set age 30
QUEUED
127.0.0.1:6379> exec 执行队列中的命令
1) OK
2) OK
127.0.0.1:6379> get age
"30"
如何取消一个事务:
127.0.0.1:6379> get age
"30"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 40
QUEUED
127.0.0.1:6379> set age 50
QUEUED
127.0.0.1:6379> discard 使用discard取消一个事务
OK
127.0.0.1:6379> get age
"30"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> incr name
QUEUED
127.0.0.1:6379> exec 当exec执行后非数字会报错,数字会自增
1) (integer) 31
2) (error) ERR value is not an integer or out of range
通过上面的例子,redis事务中某一个命令执行错误后,整个事务不会回滚
乐观锁复杂事务控制
乐观锁:大多数是基于数据版本(version)的记录机制实现的。即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表添加一个“version”字段来读取出数据时,将此版本号一同读出,之后更新时,对版本号加1.此时,将提交数据的版本号与数据库表对应记录的当前版本号进行比对,如果提交的数据版本号大于数据库当前版本号,则予以更新,否则认为是过期数据。
Redis乐观锁实例:假设游弋geage的key,我们开2个session来对age进行赋值操作,我们来看一下结果如何。
(1)第1步 session1
127.0.0.1:6379> get age
"31"
127.0.0.1:6379> watch age
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 20
QUEUED
127.0.0.1:6379> exec
1) OK
127.0.0.1:6379> get age
"20"
Watch命令会监视给定的key,当exec时候如果监视的key从调用watch后发生过变化,则整个事务会失败。也可以调用watch多次监视多个key。这样就可以对指定的key加乐观锁了。注意watch的key是对整个连接有效的,事务也一样。如果连接断开,监视和事务都会被自动清除。当然了exec,discard,unwatch命令都会清除连接中的所有监视。
持久化机制
Redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到硬盘来保证持久化。
Redis支持两种持久化方案:
1.snapshotting(快照)也是默认方式
2.Append-only file(缩写aof)的方式。
Snapshotting方式
快照是默认的持久化方式。这种方式是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配置设置自动做快照持久化的方式。我们可以配置redis在n秒内如果超过m个key呗修改就自动做快照。
Save 900 1 #900秒内如果超过1个key被修改,则发起快照保存。
Save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
Save 60 10000
Aof方式
由于快照方式是在一定间隔时间做一次的,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。
Aof比快照方式有更好的持久化性,是由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到文件中,当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
当然由于os会在内核中缓存write做的修改,所以可能不是立即写到磁盘上。这样aof方式的持久化也还是有可能会丢失部分修改。
可以通过配置文件告诉redis我们想要通过fsync函数强制os写入到磁盘的时机。
[root@vm4 ~]# vim /usr/local/lnmp/redis/etc/redis.conf
appendonly yes #启用aof持久化方式
# appendonly always #收到写命令就立即写入磁盘,最慢,但是保证完全的持久化
Appendfsync everysec #每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
# appendfsync no #完全依赖os,性能最好,持久化没保证
[root@vm4 ~]# redis-cli -a westos shutdown 配置完成后重启redis
[root@vm4 ~]# redis-server /usr/local/lnmp/redis/etc/redis.conf
[root@vm4 ~]# redis-cli -a westos
127.0.0.1:6379> set name hy_new
OK
127.0.0.1:6379> quit
[root@vm4 ~]# ls
appendonly.aof dump.rdb
我们看到了appendonly.aof文件,里面存的是一些命令的操作,dump.rdb里面存的是数据
[root@vm4 ~]# cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$4
name
$6
hy_new
发布及订阅消息
发布订阅(pub/sub)是一种消息通知模式,主要的目的是截除消息发布者和消息订阅者之间的耦合,Redis作为一个pub/sub的server,在订阅者和发布者之间起到了消息路由的功能。订阅者可以通过subscribe和psubscribe命令向redis server订阅自己感兴趣的消息类型,redis将消息类型称为通道(channel)。当发布者通过publish命令向redis server发送特定类型的信息时,订阅该信息类型的全部client都会收到此消息。
[root@vm4 ~]# redis-cli -a westos
127.0.0.1:6379> SUBSCRIBE tv1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "tv1"
3) (integer) 1
1) "message"
2) "tv1"
3) "hy"
[root@vm4 ~]# redis-cli -a westos
127.0.0.1:6379> SUBSCRIBE tv1 tv2
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "tv1"
3) (integer) 1
1) "subscribe"
2) "tv2"
3) (integer) 2
1) "message"
2) "tv1"
3) "hy"
1) "message"
2) "tv2"
3) "hy_new"
[root@vm4 ~]# redis-cli -a westos
127.0.0.1:6379> PUBLISH tv1 hy
(integer) 2
127.0.0.1:6379> PUBLISH tv2 hy_new
(integer) 1
虚拟内存的使用
Redis的虚拟内存与操作系统的虚拟内存不是一回事,但是思路和目的都是相同的。就是暂时把不经常访问的数据从内存交换到磁盘中,从而腾出宝贵的内存空间用于其他需要访问的数据。尤其是对于redis这样的内存数据库,内存总是不够用的。除了可以将数据分割到多个redis server外。另外能够提高数据库容量的办法就是使用虚拟内存把那些不经常访问的数据交换到磁盘上。
下面是vm相关配置:
vm-enabled yes #开启vm功能
vm-swap-file /tmp/redis.swap #交换出来的value保存的文件路径
vm-max-memory 1000000 #每个页面的大小32字节
vm-pages 134217728 #最多使用多少页面
vm-max-threads 4 #用于执行value对象换入的工作线程数量