NoSQL三步曲



      朱国能-Gallen.Chu
      http://www.84zhu.com
      guoneng.zhu@gmail.com
目录




     海选
          • NoSQL选型

          • Redis面对面
     相亲




     结婚
          • Redis实践
海选- NoSQL选型
NoSQL选型




        用MongoDB的一句设计哲学开始


• Databases are specializing – the “one size
  fits all” approach no longer applies.
我们为什么要使用NOSQL非关系数据库?



      High
                    • 对数据库高并发读写的需求
  performance


                    • 对海量数据的高效率存储和访
  Huge Storage
                    问的需求

 High Scalability
                    • 对数据库的高可扩展性和高可
    && High
   Availability       用性的需求
关系数据库的很多主要特性?


  数据库事务一致性需求




  数据库的写实时性和读实时性需求




  对复杂的SQL查询,特别是多表关联查询的需求
选型原则

                            高并发快
                            速读写

               CPU资源
                                          可用性
                消耗




       文档齐全/
                                                 一致性
       社区活跃

                            原则

          客户端
                                                可扩展
         /API支持



                                   海量数据
                       ……          的高效读
                                    写
选型原则

                      Consistency



               CAP    Availability


                      Tolerance of
                        network
                        Partition

                       Basically
       三大基石
                       Available


               BASE    Soft state


                      Eventually
              最终一致性   consistent


       理论依据   五分钟法则
NoSQL比较
我们需要什么?


•   高并发快速读写
•   海量数据高效读写
•   高可用性
•   排行、热门、分类数据结构灵活

• 简单的API、客户端支持
• 文档完善、社区活跃
• 支持良好、版本更新活跃

• 可以容忍最终一致性
• 可以容忍client分区、集群
相亲-Redis面对面
What is Redis?


             What is
                                         sponsored by:




• 全名 REmote DIctionary Server

• Redis is an open source, advanced key-value store. It is often
  referred to as a data structure server since keys can
  contain strings, hashes, lists, sets and sorted sets.

• key value store? cache? memory database? data structure
  server?
优点


•   FAST both read and write
•   data can dump to disk
•   master-slave
•   many useful data structure
•   Active community/ Antirez
缺点



•   Physical memory limit
•   Auto-sharding / Cluster
•   Scale ability
•   Automatic failover switch
Fast


• 根据 Redis 官方的测试结果:在 50 个并发的情况下请求 10w 次,写
  的速度是 110000次/s,读的速度是 81000 次/s
•  测试环境:
• 1. 50 个并发,请求 100000 次
• 2. 读和写大小为 256bytes 的字符串
• 3. Linux2.6 Xeon X3320 2.5GHz 的服务器上
• 4. 通过本机的 loopback interface 接口上执行
• 地址:
       • http://code.google.com/p/redis/wiki/Benchmarks
       • http://redis.io/topics/benchmarks
性能对比

 小数据:500W条数据;每个value:100 bytes
性能对比

 大数据:500W条数据;每个value:20k bytes
Why Fast


• Libevent。和Memcached不同,Redis并没有选择libevent。Libevent
  为了迎合通用性造成代码庞大(目前Redis代码还不到libevent的1/3)及
  牺牲了在特定平台的不少性能。Redis用libevent中两个文件修改实现
  了自己的epoll event loop(4)。业界不少开发者也建议Redis使用另外
  一个libevent高性能替代libev,但是作者还是坚持Redis应该小巧并去
  依赖的思路。一个印象深刻的细节是编译Redis之前并不需要执行
  ./configure。
• CAS问题。CAS是Memcached中比较方便的一种防止竞争修改资源
  的方法。CAS实现需要为每个cache key设置一个隐藏的cas token,
  cas相当value版本号,每次set会token需要递增,因此带来CPU和内
  存的双重开销,虽然这些开销很小,但是到单机10G+ cache以及
  QPS上万之后这些开销就会给双方相对带来一些细微性能差别(5)。
Useful data structure


键(keys)                 值(values)
page:index.html         <html><head>[...]    String


users_logged_in_today   { 1, 2, 3, 4, 5 }    Sets

latest_post_ids         [201, 204, 209,..]   List


users_and_scores        joe ~ 1.3483         ZSets
                        bert ~ 93.4
                        fred ~ 283.22
                        chris ~ 23774.17
DUMP


• snapshot(RDB)
   – 定时将内存的快照(snapshot)持久化到硬盘,这种方法缺点是持久
     化之后如果出现crash则会丢失一段数据。

• AOP(append only mode)
   – 写入内存数据的同时将操作命令保存到日志文件,在一个并发更
     改上万的系统中,命令日志是一个非常庞大的数据,管理维护成
     本非常高,恢复重建时间会非常长,这样导致失去aof高可用性本
     意。
RDB


• Fork一个进程,利用copy on write原理,遍历所有的db的hash
  table,进行整库的dump
• Save命令,shutdown命令,slave启动都会触发
• 利用LZF进行压缩
• 持久化触发条件:
• #sava 900 1
• #save 300 10
• #save 60
BGREWRITEAOF


• 避免aof文件过大
• 2.4版本增加自动的bgrewriteaof

• auto-aof-rewrite-min-size 64mb
• auto-aof-rewrite-percentage 100

• 手动bgrewriteaof
Best redo-logo


• 当redisserver异常crash掉的时候,重启时将会进行如下的操作:
  – 假如只配置了aof,启动时加载aof文件
  – 假如同事配置了rdb/aof,启动时只加载aof文件
  – 假如只配置rdb,启动时将加载dump文件

• 在非创建快照期间追加redo-log,在完成快照后清除redo-log
存储模式


• VM方式:将数据分页存放,由应用(如Redis)或者操作系统(如Varnish)将访
 问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存
 中。应用实现VM缺点是代码逻辑复杂,如果业务上冷热数据边界并不分明,
 则换入换出代价太高,系统整体性能低。不少抢鲜的网友在微博上也反馈过
 使用VM种种不稳定情况。 (目前Redis使用的方式)
• 磁盘方式:所有的数据读写访问都是基于磁盘,由操作系统来只能的缓存访
 问的数据。由于现代操作系统都非常聪明,会将频繁访问的数据加入到内存
 中,因此应用并不需要过多特殊逻辑。MongoDB就是这种设计方式。这种方
 式也有一些已知的缺点,比如操作MMap写入磁盘由操作系统控制,操作系
 统先写哪里后写哪里应用并不知情,如果写入过程中发生了crash则数据一致
 性会存在问题。 (作者称其为MongoDB的方式)
• Diskstore:实际原理和mysql+memcache方式类似,只不过将两者功
  能合二为一到一个底层服务中,简化了调用。(作者打算使用的新方
  式,alpha版本,Demo)
Replication


• master可以有多个slave
• 除了多个slave连到相同的master外,slave也可以连接其他slave形成
  图状结构
• 主从复制不会阻塞master。也就是说当一个或多个slave与master进
  行初次同步数据时,master可以继续处理client发来的请求。相反
  slave在初次同步数据时则会阻塞不能处理client的请求。
• 主从复制可以用来提高系统的可伸缩性,我们可以用多个slave 专门用
  于client的读请求,比如sort操作可以使用slave来处理。也可以用来
  做简单的数据冗余
• 可以在master禁用数据持久化,只需要注释掉master 配置文件中的
  所有save配置,然后只在slave上配置数据持久化
• slaveof 172.16.3.35 6379 #指定master的ip和端口
• slave重连无增量复制,slave表重建
Author
应用场景


•   取最新N个数据的操作
•   排行榜应用,取TOP N操作
•   需要精准设定过期时间的应用
•   计数器应用
•   Uniq操作,获取某段时间所有数据排重值
•   实时系统,反垃圾系统
•   Pub/Sub构建实时消息系统
•   构建队列系统
•   缓存
2.4版本改进


•   对Sorted Sets的内存优化
•   RDB文件持久化提速
•   提供批量写入功能
•   改用jemalloc的内存分配模式
•   减少 copy-on-write 使用
•   INFO输出内容增强
•   VM机制彻底废弃
•   总的来说2.4版本会在各方面有性能上的提升
Why 6379



                         Why?
                   6379

6379在是手机按键上MERZ对应的号码
MERZ取自意大利歌女Alessia Merz的名字
结婚- Redis实践
Redis容量规划及建议



•   数据项: value保存的内容是什么,如用户资料
•   业务数据类型: 如String, List, set
•   数据大小: 如100字节
•   记录数: 如100万条(决定是否需要拆分)
•   数据增多如何扩展?
•   读写瓶颈如何扩展?
•   不仅要规划还要严密监控!
•   sharding策略与HA(rolling/pre-sharding/双写/多slave)
•   使用Pipeline减小网络IO/原子操作
•   Redis的最佳使用方式是 in-memory
Redis数据库的键值设计(一)

 mysql> select * from login;
 +---------+----------------------------+-------------------------+--------------------------------------+
 | user_id | name                      | login_times              | last_login_time                      |
 +---------+----------------------------+-------------------------+--------------------------------------+
 |        1 | Doug.Wang                |                       5|      2011-10-01 00:00:00             |
 |        2 | Jeff.Tu                  |                       1|      2011-10-01 00:00:00             |
 |        3 | Gallen.Chu                |                      2|      2011-11-01 00:00:00             |
 +----------+---------------------------+-------------------------+-------------------------------------+

 key表名:主键值:列名
 Set login:1:login_times 5
 Set login:2:login_times 1
 Set login:3:login_times 2

 Set login:1:last_login_time 2011-10-1
 Set login:2:last_login_time 2011-10-1
 Set login:3:last_login_time 2011-11-1

 Set login:1:name “Doug.Wang”
 Set login:2:name “Jeff.Tu””
 Set login:3:name “Gallen.Chu”
Redis数据库的键值设计(二)



排序需求

zadd post:post_times 15 1
zadd post:post_times 11 2
zadd post:post_times 28 3



#对该应用的评论次数自增1
ret = r.zincrby(“post:post_times", 1, app_id)


获得评论次数最多的应用,逆序排列取的排名第N的应用
ret = r.zrevrange(“post:post_times", 0, N-1)
Redis数据库的键值设计(三)

Set app:1:name   "冒泡音乐盒"
Set app:2:name   "股票指南"
Set app:3:name   "幻想三国"

sadd appTag:application   1
sadd appTag:application   2
sadd appTag:tools         2
sadd appTag:webgame       3


即属于application又属于tools的应用?
inter_list = redis.sinter("appTag:application", "appTag:tools")

即属于application,但不属于tools的应用
inter_list = redis.sdiff("appTag:application", "appTag:tools")

属于application和属于tools的书的合集?
inter_list = redis.sunion("appTag:application", "appTag:tools")
Example


• A_start 10, A_end 20
• B_start 30, B_end 40

•   redis 127.0.0.1:6379> zadd ranges 10 A_start (integer) 1
•   redis 127.0.0.1:6379> zadd ranges 20 A_end (integer) 1
•   redis 127.0.0.1:6379> zadd ranges 30 B_start (integer) 1
•   redis 127.0.0.1:6379> zadd ranges 40 B_end (integer) 1

• redis 127.0.0.1:6379> zrangebyscore ranges (15 +inf LIMIT 0 1 1)
  "A_end“

• redis 127.0.0.1:6379> zrangebyscore ranges (25 +inf LIMIT 0 1 1)
  "B_start"
使用hset代替set


对象:skyapp

id : 1
name : 天气助手
appid : 2914
created_time : 132013777338
                              HSET skyapp:1 name “天气助手”
                              HSET skyapp:1 appid 2914
                              HSET skyapp:1 created_time 132013777338
• 结构化数据存取
                              ---------------------------------------------------
• 提高内存使用率                     HLEN skyapp:1 == 3
                              HGET skyapp:1 name == “天气助手”
                              HKEYS skyapp:1 == name , appid, created_time
                              HGETALL skyapp:1 ==
                                                             name => 天气助手
                                                              time => 2914
                                                              created_time => 132013777338
使用Pipleline模式


•发送多个命令,一次性接收多个命令,减少网络IO次数
•服务器将命令结果放进queue,再返回给客户端

Client: INCR X    Client: INCR X
Server: 1         Client: INCR X
Client: INCR X    Client: INCR X
Server: 2         Client: INCR X
Client: INCR X    Server: 1
Server: 3         Server: 2
Client: INCR X    Server: 3
Server: 4         Server: 4
不要使用VM


• Redis VM 不靠谱,作者在2.4版本中已经彻底放弃了VM
 – 症状:
   •   代码逻辑复杂
   •   系统整体性能低
   •   如业务冷热数据边界不分明,换入换出代价太高
   •   数据DUMP的时候内存耗光,CPU100%
 – 方案:
   • 加大物理内存
   • 数据sharding
集群架构(一)

 主从架构

• Redis缺少同步机制常见的check point和校验机制
• 如果同步转发丢失,一致性无法保证,只有slave重启时全量加载才
  能修复
   – 方案:主库在内存中运行,从库不提供线上服务只做持久化备份



          Master   Replication
                                  Slave




          纯内存                    备份、持久化
集群架构(二)



 单机多节点       ( 节点数=CPU - 1 )    分布式缓存 (一致性哈希)


Redis1:6380   每天2点        6G
                                   redis
                                              redis
Redis2:6381   每天3点        6G

Redis3:6382   每天4点        6G

                        预留6G      redis       redis


  分时间段 bgrewriteaof
  充分提高内存使用率
集群架构(三)

 Sharding 数据分片

                            应用层

                            sharding
                  R/          R/       R/
                  W           W        W

        master1              master2        master3




        slave1               slave2         slave3

  备份                   备份              备份
集群架构(四)



          •All nodes are directly connected with a
          service channel.

          •TCP baseport+4000, example 6379 ->
          10379.

          •Node to Node protocol is binary,optimized
          for bandwidth and speed.

          •Clients talk to nodes as usually, using ascii
          protocol, with minor additions.

          •Nodes don't proxy queries.
Redis客户端


• 各种语言客户端支持。
• Jedis,ShardJedis,ShardJedisPipeline
• 支持客户端分布式,ShardJedis。一致性哈希算
  法,采用TreepMap<String,ShardInfo>存储redis
  节点,murmur哈希函数计算key和server的值。
  默认虚拟160个节点,支持权重配置。
• 连接池管理。JedisPool。
WEB界面管理工具


• 一个PHP的Redis WEB管理工具phpRedisAdmin

• 项目地址:https://github.com/ErikDubbelboer/phpRedisAdmin
• 演示demo:http://dubbelboer.com/phpRedisAdmin/
附:参数说明(一)

配置项              说明
daemonize no     是否以后台进程运行,默认为no

pidfile          如以后台进程运行,则需指定一个pid,默认/var/run/redis.pid

port 6379        监听端口,默认为6379

bind 127.0.0.1   绑定主机IP,默认值为127.0.0.1

timeout 300      超时时间,默认为300(秒)

loglevel         日志记录等级,有4个可选值,debug,verbose(默认值),notice,warning

logfile          日志记录方式,默认值为stdout

slaveof          当本机为从服务时,设置主服务的IP及端口。在启动时,REDIS会自动从
                 MASTER上把数据先同步过来,而无需我们手动进行。MASTER上每有一次
                 落地保存,会自动向SLAVE进行同步。
masterauth       当本机为从服务时,设置主服务的连接密码

requirepass      连接密码

maxclients       最大客户端连接数,默认不限制

maxmemory        设置最大内存,达到最大内存设置后,Redis会先尝试清除已到期或即将到期
                 的Key,当此方法处理后,任到达最大内存设置,将无法再进行写入操作。
附:参数说明(二)

配置项              说明
save 900 1       900秒内有1个改变,
save 300 10      300秒内有10个改变,
save 60 10000    60秒内有10000个改变,
                 redis就会内存中的key保存到数据库文件中去
rdbcompression   存储至本地数据库时是否压缩数据,默认为yes

dbfilename       本地数据库文件名,默认值为dump.rdb

dir              本地数据库存放路径,默认值为 ./

Appendonly       是否在每次更新操作后进行日志记录,开启AOF

appendfilename   更新日志文件名,默认值为appendonly.aof

appendfsync      新日志条件,共有3个可选值。no表示等操作系统进行数据缓存同步到磁盘,
                 always表示每次更新操作后手动调用fsync()将数据写到磁盘,everysec表示
                 每秒同步一次(默认)
hash-max-        当hash中包含超过指定元素个数并且最大的元素没有超过临界时,hash将以
zipmap-entries   一种特殊的编码方式(大大减少内存使用)来存储

hash-max-        hash中一个元素的最大值
zipmap-value
附:参数说明(三)

配置项              说明
vm-enabled       是否使用虚拟内存,默认值为no

vm-swap-file     虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享


vm-max-memory    将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory
                 设置多小,所有索引数据都是内存存储的 (Redis的索引数据就是keys),也就
                 是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。
                 默认值为0


vm-page-size     虚拟内存文件以块存储,默认每块32bytes

vm-pages         虚拟内在文件的最大数,默认134217728

vm-max-threads   可以设置访问swap文件的线程数,设置最好不要超过机器的核数,如果设置
                 为0,那么所有对swap文件的操作都是串行的.可能会造成比较长时间的延
                 迟,但是对数据完整性有很好的保证.
附:Redis扩展阅读



我怎么获得更多,更全的Redis信息?
1、http://code.google.com/p/redis/
2、http://redis.io
3、http://antirez.com/
4、http://blog.nosqlfan.com/tags/Redis
5、http://redis.readthedocs.org/en/2.4/index.html
6、http://www.google.com
Q&A

Nosql三步曲

  • 1.
    NoSQL三步曲 朱国能-Gallen.Chu http://www.84zhu.com guoneng.zhu@gmail.com
  • 2.
    目录 海选 • NoSQL选型 • Redis面对面 相亲 结婚 • Redis实践
  • 3.
  • 4.
    NoSQL选型 用MongoDB的一句设计哲学开始 • Databases are specializing – the “one size fits all” approach no longer applies.
  • 5.
    我们为什么要使用NOSQL非关系数据库? High • 对数据库高并发读写的需求 performance • 对海量数据的高效率存储和访 Huge Storage 问的需求 High Scalability • 对数据库的高可扩展性和高可 && High Availability 用性的需求
  • 6.
    关系数据库的很多主要特性? 数据库事务一致性需求 数据库的写实时性和读实时性需求 对复杂的SQL查询,特别是多表关联查询的需求
  • 7.
    选型原则 高并发快 速读写 CPU资源 可用性 消耗 文档齐全/ 一致性 社区活跃 原则 客户端 可扩展 /API支持 海量数据 …… 的高效读 写
  • 8.
    选型原则 Consistency CAP Availability Tolerance of network Partition Basically 三大基石 Available BASE Soft state Eventually 最终一致性 consistent 理论依据 五分钟法则
  • 9.
  • 10.
    我们需要什么? • 高并发快速读写 • 海量数据高效读写 • 高可用性 • 排行、热门、分类数据结构灵活 • 简单的API、客户端支持 • 文档完善、社区活跃 • 支持良好、版本更新活跃 • 可以容忍最终一致性 • 可以容忍client分区、集群
  • 11.
  • 12.
    What is Redis? What is sponsored by: • 全名 REmote DIctionary Server • Redis is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets. • key value store? cache? memory database? data structure server?
  • 13.
    优点 • FAST both read and write • data can dump to disk • master-slave • many useful data structure • Active community/ Antirez
  • 14.
    缺点 • Physical memory limit • Auto-sharding / Cluster • Scale ability • Automatic failover switch
  • 15.
    Fast • 根据 Redis官方的测试结果:在 50 个并发的情况下请求 10w 次,写 的速度是 110000次/s,读的速度是 81000 次/s • 测试环境: • 1. 50 个并发,请求 100000 次 • 2. 读和写大小为 256bytes 的字符串 • 3. Linux2.6 Xeon X3320 2.5GHz 的服务器上 • 4. 通过本机的 loopback interface 接口上执行 • 地址: • http://code.google.com/p/redis/wiki/Benchmarks • http://redis.io/topics/benchmarks
  • 16.
  • 17.
  • 18.
    Why Fast • Libevent。和Memcached不同,Redis并没有选择libevent。Libevent 为了迎合通用性造成代码庞大(目前Redis代码还不到libevent的1/3)及 牺牲了在特定平台的不少性能。Redis用libevent中两个文件修改实现 了自己的epoll event loop(4)。业界不少开发者也建议Redis使用另外 一个libevent高性能替代libev,但是作者还是坚持Redis应该小巧并去 依赖的思路。一个印象深刻的细节是编译Redis之前并不需要执行 ./configure。 • CAS问题。CAS是Memcached中比较方便的一种防止竞争修改资源 的方法。CAS实现需要为每个cache key设置一个隐藏的cas token, cas相当value版本号,每次set会token需要递增,因此带来CPU和内 存的双重开销,虽然这些开销很小,但是到单机10G+ cache以及 QPS上万之后这些开销就会给双方相对带来一些细微性能差别(5)。
  • 19.
    Useful data structure 键(keys) 值(values) page:index.html <html><head>[...] String users_logged_in_today { 1, 2, 3, 4, 5 } Sets latest_post_ids [201, 204, 209,..] List users_and_scores joe ~ 1.3483 ZSets bert ~ 93.4 fred ~ 283.22 chris ~ 23774.17
  • 20.
    DUMP • snapshot(RDB) – 定时将内存的快照(snapshot)持久化到硬盘,这种方法缺点是持久 化之后如果出现crash则会丢失一段数据。 • AOP(append only mode) – 写入内存数据的同时将操作命令保存到日志文件,在一个并发更 改上万的系统中,命令日志是一个非常庞大的数据,管理维护成 本非常高,恢复重建时间会非常长,这样导致失去aof高可用性本 意。
  • 21.
    RDB • Fork一个进程,利用copy onwrite原理,遍历所有的db的hash table,进行整库的dump • Save命令,shutdown命令,slave启动都会触发 • 利用LZF进行压缩 • 持久化触发条件: • #sava 900 1 • #save 300 10 • #save 60
  • 22.
    BGREWRITEAOF • 避免aof文件过大 • 2.4版本增加自动的bgrewriteaof •auto-aof-rewrite-min-size 64mb • auto-aof-rewrite-percentage 100 • 手动bgrewriteaof
  • 23.
    Best redo-logo • 当redisserver异常crash掉的时候,重启时将会进行如下的操作: – 假如只配置了aof,启动时加载aof文件 – 假如同事配置了rdb/aof,启动时只加载aof文件 – 假如只配置rdb,启动时将加载dump文件 • 在非创建快照期间追加redo-log,在完成快照后清除redo-log
  • 24.
    存储模式 • VM方式:将数据分页存放,由应用(如Redis)或者操作系统(如Varnish)将访 问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存 中。应用实现VM缺点是代码逻辑复杂,如果业务上冷热数据边界并不分明, 则换入换出代价太高,系统整体性能低。不少抢鲜的网友在微博上也反馈过 使用VM种种不稳定情况。 (目前Redis使用的方式) • 磁盘方式:所有的数据读写访问都是基于磁盘,由操作系统来只能的缓存访 问的数据。由于现代操作系统都非常聪明,会将频繁访问的数据加入到内存 中,因此应用并不需要过多特殊逻辑。MongoDB就是这种设计方式。这种方 式也有一些已知的缺点,比如操作MMap写入磁盘由操作系统控制,操作系 统先写哪里后写哪里应用并不知情,如果写入过程中发生了crash则数据一致 性会存在问题。 (作者称其为MongoDB的方式) • Diskstore:实际原理和mysql+memcache方式类似,只不过将两者功 能合二为一到一个底层服务中,简化了调用。(作者打算使用的新方 式,alpha版本,Demo)
  • 25.
    Replication • master可以有多个slave • 除了多个slave连到相同的master外,slave也可以连接其他slave形成 图状结构 • 主从复制不会阻塞master。也就是说当一个或多个slave与master进 行初次同步数据时,master可以继续处理client发来的请求。相反 slave在初次同步数据时则会阻塞不能处理client的请求。 • 主从复制可以用来提高系统的可伸缩性,我们可以用多个slave 专门用 于client的读请求,比如sort操作可以使用slave来处理。也可以用来 做简单的数据冗余 • 可以在master禁用数据持久化,只需要注释掉master 配置文件中的 所有save配置,然后只在slave上配置数据持久化 • slaveof 172.16.3.35 6379 #指定master的ip和端口 • slave重连无增量复制,slave表重建
  • 26.
  • 27.
    应用场景 • 取最新N个数据的操作 • 排行榜应用,取TOP N操作 • 需要精准设定过期时间的应用 • 计数器应用 • Uniq操作,获取某段时间所有数据排重值 • 实时系统,反垃圾系统 • Pub/Sub构建实时消息系统 • 构建队列系统 • 缓存
  • 28.
    2.4版本改进 • 对Sorted Sets的内存优化 • RDB文件持久化提速 • 提供批量写入功能 • 改用jemalloc的内存分配模式 • 减少 copy-on-write 使用 • INFO输出内容增强 • VM机制彻底废弃 • 总的来说2.4版本会在各方面有性能上的提升
  • 29.
    Why 6379 Why? 6379 6379在是手机按键上MERZ对应的号码 MERZ取自意大利歌女Alessia Merz的名字
  • 30.
  • 31.
    Redis容量规划及建议 • 数据项: value保存的内容是什么,如用户资料 • 业务数据类型: 如String, List, set • 数据大小: 如100字节 • 记录数: 如100万条(决定是否需要拆分) • 数据增多如何扩展? • 读写瓶颈如何扩展? • 不仅要规划还要严密监控! • sharding策略与HA(rolling/pre-sharding/双写/多slave) • 使用Pipeline减小网络IO/原子操作 • Redis的最佳使用方式是 in-memory
  • 32.
    Redis数据库的键值设计(一) mysql> select* from login; +---------+----------------------------+-------------------------+--------------------------------------+ | user_id | name | login_times | last_login_time | +---------+----------------------------+-------------------------+--------------------------------------+ | 1 | Doug.Wang | 5| 2011-10-01 00:00:00 | | 2 | Jeff.Tu | 1| 2011-10-01 00:00:00 | | 3 | Gallen.Chu | 2| 2011-11-01 00:00:00 | +----------+---------------------------+-------------------------+-------------------------------------+ key表名:主键值:列名 Set login:1:login_times 5 Set login:2:login_times 1 Set login:3:login_times 2 Set login:1:last_login_time 2011-10-1 Set login:2:last_login_time 2011-10-1 Set login:3:last_login_time 2011-11-1 Set login:1:name “Doug.Wang” Set login:2:name “Jeff.Tu”” Set login:3:name “Gallen.Chu”
  • 33.
    Redis数据库的键值设计(二) 排序需求 zadd post:post_times 151 zadd post:post_times 11 2 zadd post:post_times 28 3 #对该应用的评论次数自增1 ret = r.zincrby(“post:post_times", 1, app_id) 获得评论次数最多的应用,逆序排列取的排名第N的应用 ret = r.zrevrange(“post:post_times", 0, N-1)
  • 34.
    Redis数据库的键值设计(三) Set app:1:name "冒泡音乐盒" Set app:2:name "股票指南" Set app:3:name "幻想三国" sadd appTag:application 1 sadd appTag:application 2 sadd appTag:tools 2 sadd appTag:webgame 3 即属于application又属于tools的应用? inter_list = redis.sinter("appTag:application", "appTag:tools") 即属于application,但不属于tools的应用 inter_list = redis.sdiff("appTag:application", "appTag:tools") 属于application和属于tools的书的合集? inter_list = redis.sunion("appTag:application", "appTag:tools")
  • 35.
    Example • A_start 10,A_end 20 • B_start 30, B_end 40 • redis 127.0.0.1:6379> zadd ranges 10 A_start (integer) 1 • redis 127.0.0.1:6379> zadd ranges 20 A_end (integer) 1 • redis 127.0.0.1:6379> zadd ranges 30 B_start (integer) 1 • redis 127.0.0.1:6379> zadd ranges 40 B_end (integer) 1 • redis 127.0.0.1:6379> zrangebyscore ranges (15 +inf LIMIT 0 1 1) "A_end“ • redis 127.0.0.1:6379> zrangebyscore ranges (25 +inf LIMIT 0 1 1) "B_start"
  • 36.
    使用hset代替set 对象:skyapp id : 1 name: 天气助手 appid : 2914 created_time : 132013777338 HSET skyapp:1 name “天气助手” HSET skyapp:1 appid 2914 HSET skyapp:1 created_time 132013777338 • 结构化数据存取 --------------------------------------------------- • 提高内存使用率 HLEN skyapp:1 == 3 HGET skyapp:1 name == “天气助手” HKEYS skyapp:1 == name , appid, created_time HGETALL skyapp:1 == name => 天气助手 time => 2914 created_time => 132013777338
  • 37.
    使用Pipleline模式 •发送多个命令,一次性接收多个命令,减少网络IO次数 •服务器将命令结果放进queue,再返回给客户端 Client: INCR X Client: INCR X Server: 1 Client: INCR X Client: INCR X Client: INCR X Server: 2 Client: INCR X Client: INCR X Server: 1 Server: 3 Server: 2 Client: INCR X Server: 3 Server: 4 Server: 4
  • 38.
    不要使用VM • Redis VM不靠谱,作者在2.4版本中已经彻底放弃了VM – 症状: • 代码逻辑复杂 • 系统整体性能低 • 如业务冷热数据边界不分明,换入换出代价太高 • 数据DUMP的时候内存耗光,CPU100% – 方案: • 加大物理内存 • 数据sharding
  • 39.
    集群架构(一)  主从架构 • Redis缺少同步机制常见的checkpoint和校验机制 • 如果同步转发丢失,一致性无法保证,只有slave重启时全量加载才 能修复 – 方案:主库在内存中运行,从库不提供线上服务只做持久化备份 Master Replication Slave 纯内存 备份、持久化
  • 40.
    集群架构(二)  单机多节点 ( 节点数=CPU - 1 )  分布式缓存 (一致性哈希) Redis1:6380 每天2点 6G redis redis Redis2:6381 每天3点 6G Redis3:6382 每天4点 6G 预留6G redis redis  分时间段 bgrewriteaof  充分提高内存使用率
  • 41.
    集群架构(三)  Sharding 数据分片 应用层 sharding R/ R/ R/ W W W master1 master2 master3 slave1 slave2 slave3 备份 备份 备份
  • 42.
    集群架构(四) •All nodes are directly connected with a service channel. •TCP baseport+4000, example 6379 -> 10379. •Node to Node protocol is binary,optimized for bandwidth and speed. •Clients talk to nodes as usually, using ascii protocol, with minor additions. •Nodes don't proxy queries.
  • 43.
    Redis客户端 • 各种语言客户端支持。 • Jedis,ShardJedis,ShardJedisPipeline •支持客户端分布式,ShardJedis。一致性哈希算 法,采用TreepMap<String,ShardInfo>存储redis 节点,murmur哈希函数计算key和server的值。 默认虚拟160个节点,支持权重配置。 • 连接池管理。JedisPool。
  • 44.
    WEB界面管理工具 • 一个PHP的Redis WEB管理工具phpRedisAdmin •项目地址:https://github.com/ErikDubbelboer/phpRedisAdmin • 演示demo:http://dubbelboer.com/phpRedisAdmin/
  • 45.
    附:参数说明(一) 配置项 说明 daemonize no 是否以后台进程运行,默认为no pidfile 如以后台进程运行,则需指定一个pid,默认/var/run/redis.pid port 6379 监听端口,默认为6379 bind 127.0.0.1 绑定主机IP,默认值为127.0.0.1 timeout 300 超时时间,默认为300(秒) loglevel 日志记录等级,有4个可选值,debug,verbose(默认值),notice,warning logfile 日志记录方式,默认值为stdout slaveof 当本机为从服务时,设置主服务的IP及端口。在启动时,REDIS会自动从 MASTER上把数据先同步过来,而无需我们手动进行。MASTER上每有一次 落地保存,会自动向SLAVE进行同步。 masterauth 当本机为从服务时,设置主服务的连接密码 requirepass 连接密码 maxclients 最大客户端连接数,默认不限制 maxmemory 设置最大内存,达到最大内存设置后,Redis会先尝试清除已到期或即将到期 的Key,当此方法处理后,任到达最大内存设置,将无法再进行写入操作。
  • 46.
    附:参数说明(二) 配置项 说明 save 900 1 900秒内有1个改变, save 300 10 300秒内有10个改变, save 60 10000 60秒内有10000个改变, redis就会内存中的key保存到数据库文件中去 rdbcompression 存储至本地数据库时是否压缩数据,默认为yes dbfilename 本地数据库文件名,默认值为dump.rdb dir 本地数据库存放路径,默认值为 ./ Appendonly 是否在每次更新操作后进行日志记录,开启AOF appendfilename 更新日志文件名,默认值为appendonly.aof appendfsync 新日志条件,共有3个可选值。no表示等操作系统进行数据缓存同步到磁盘, always表示每次更新操作后手动调用fsync()将数据写到磁盘,everysec表示 每秒同步一次(默认) hash-max- 当hash中包含超过指定元素个数并且最大的元素没有超过临界时,hash将以 zipmap-entries 一种特殊的编码方式(大大减少内存使用)来存储 hash-max- hash中一个元素的最大值 zipmap-value
  • 47.
    附:参数说明(三) 配置项 说明 vm-enabled 是否使用虚拟内存,默认值为no vm-swap-file 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享 vm-max-memory 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory 设置多小,所有索引数据都是内存存储的 (Redis的索引数据就是keys),也就 是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。 默认值为0 vm-page-size 虚拟内存文件以块存储,默认每块32bytes vm-pages 虚拟内在文件的最大数,默认134217728 vm-max-threads 可以设置访问swap文件的线程数,设置最好不要超过机器的核数,如果设置 为0,那么所有对swap文件的操作都是串行的.可能会造成比较长时间的延 迟,但是对数据完整性有很好的保证.
  • 48.
  • 49.