Redis从理论到实例

Redis,在好多项目场景中帮助我们。

老生常谈,Redis与memcached的区别

1. Redis不仅仅支持简单的k/v类型的数据,还提供List、Set、Hash、Sorted Set等数据结构的存储。相比而言更具数据库特征。

3. 除了多种数据结构的支持,Redis还提供更多额外的特性,比如Subscribe/Publish,以支持发布/订阅这种事件通知机制等。

4. Redis支持数据的备份,即master-slave模式的数据备份。

5. Redis支持数据的持久化,并不是所有的数据都一直存储在内存中的,通过snapshot快照或AOF增量LOG方式,可将内存中的数据保持在磁盘中,重启的时候可以再次加载重新使用。

6. 过期策略 Memcached在set时指定,redis可通过expire指定 

7. Memcached可以缓存图片、视频等。

8. 从网络IO模型上,Memcached是多线程非堵塞IO复用的网络模型,分监听主线程和Worker子线程。网络层使用libevent封装的事件库。映入了缓存一致性(cache coherency)和锁,带来性能损耗;Redis使用单线程的IO复用模型,封装了一个简单的AeEvent事件处理框架。单纯IO操作,单线程可将速度发挥到最大,但是一些简单的操作如排序和聚合等,CPU计算过程中,整个IO调度被堵塞,影响吞吐量。

9. 从数据一致性上,Mmecached引入了CAS,保证了多个并发访问同一份数据的一致性;Redis提供了事务功能,保证了一串命令的原子性。

10. 从内存管理上,Memcached使用预分配内存池的方式,使用slab和chunk管理内存。内存池可以省去申请、释放内存的开销,减小内存碎片的发生,但也带来一定程度的空间浪费。并且在空间仍很大时,新的数据仍有可能被剔除。Redis使用现场申请内存的方式,很少使用free-list等方式优化内存分配,一定程度上存在内存碎片。Redis把带过期时间的数据单独放在一起,称为临时数据。非临时数据永远不会剔出,即便内存不够导致swap。

总之,Redis的更多场景是作为Memcached的替代者来使用的,当需要除key/value以外的更多数据类型支持时,使用Redis更合适,当存储的数据不能被剔除时,使用Redis更合适。

附参考: http://blog.csdn.net/tonysz126/article/details/8280696

Redis 安装 + Sentinel配置主从

[root@bx_2_35 ~]# cd /opt/soft/
[root@bx_2_35 soft]# wget http://download.redis.io/releases/redis-2.8.13.tar.gz
[root@bx_2_35 soft]# tar -xzf redis-2.8.13.tar.gz
[root@bx_2_35 soft]# tar -xzf redis-2.8.13.tar.gz 
[root@bx_2_35 soft]# cd redis-2.8.13
[root@bx_2_35 redis-2.8.13]# make

短连接:
[root@bx_2_35 redis-2.8.13]# cd src
[root@bx_2_35 src]# cp -pf redis-server /usr/local/bin
[root@bx_2_35 src]# cp -pf redis-cli /usr/local/bin
[root@bx_2_35 src]# cp -pf redis-sentinel /usr/local/bin

[root@bx_2_35 src]# cd ..
[root@bx_2_35 redis-2.8.13]# vim redis.conf 


[root@bx_2_35 redis-2.8.13]# redis-server 


关闭XShell会话(或者指定配置文件 redis-server redis.conf 就不需要关闭会话了)
重新打开会话
[root@bx_2_35 ~]# redis-cli 


持久化相关的配置在 redis.conf中
快照的方式持久化到磁盘
自动持久化规则配置
save 900 1
save 300 10
save 60 10000
Append-only file 的方式持久化 
每次执行写操作命令之后,都会将数据写到server.aofbuf中。
# appendfsync always
appendfsync everysec
# appendfsync no



重启 redis


关闭会话(或者指定配置文件就不需要关闭会话了)

设置主从 ( 2.35主, 5.23从)
[root@bx_2_35 ~]# pkill redis-server

[@bx_5_23 /]# cd /opt/soft/redis-2.8.13/
[@bx_5_23 redis-2.8.13]# vim redis.conf 

[root@bx_2_35 redis-2.8.13]# redis-server redis.conf 
[@bx_5_23 redis-2.8.13]# redis-server redis.conf




[root@bx_2_35 redis-2.8.13]# vim sentinel.conf 
sentinel monitor mymaster 10.16.2.35 6379 1
[root@bx_2_35 redis-2.8.13]# redis-sentinel sentinel.conf --sentinel &


Redis消息队列

Redis除了可以当做Key-Value型的NoSql数据库外,同时由于它支持List数据结构,完全可以实现轻量级的消息队列服务。

个人在项目中使用的几个简单应用场景是: 

1. 将新增加的奖品不时lpush到奖品队列中,用户符合中奖规则,rpop出来该奖品。简单的生产者消费者队列。

2. 用户播放历史记录。

生产者

播放影片,前端Http轮询上报当前用户(user)、影片(film)、播放时长(time)。放入生产者队列。由于用户量较多,分配了5个队列。按照user hashcode除以5取余,分配该记录到指定的队列中。按user哈希的好处是同一个用户的不同记录肯定会落到唯一特定的队列中。若落入不同的队列,可能两个队列处理不是按上传的先后顺序,先上传的可能会把后上传的覆盖掉。

String key = "film-history-q-" + (user.hashCode() % 5);
Long beforeLen = redisUtils.lLen(key);
    if (beforeLen < 50000) {
      StringBuilder sb = new StringBuilder(user);
      sb.append("|").append(film).append("|").append(video).append("|").append(time);
      Long afterLen = redisUtils.lPush(key, sb.toString());
      if (afterLen > 0) {
        return true;
      }
    }

此处限制beforeLen < 50000是为了防止生产者队列无限增大。超过这个限定,我们认为很可能消费者挂掉了。另外未考虑更高的伸缩性: 如果5个队列也不够用,业务要求严格的话要考虑一致性哈希了。

消费者

构建5个消费者Worker,分别 对5个队列进行消费,调用上报播放记录接口。期间我们可以做一些合并相同用户同一影片播放记录的策略,减少上报播放记录接口次数。


最后推荐一篇关于Redis应用场景的不错的文章 http://www.cnblogs.com/si812cn/p/4042992.html

以及Redis命令参考 http://redisdoc.com/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章