Redis串讲_詹君v3_第1页
Redis串讲_詹君v3_第2页
Redis串讲_詹君v3_第3页
Redis串讲_詹君v3_第4页
Redis串讲_詹君v3_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Redis实现分析及特点詹君 INF/HPC主要内容1、简要介绍及设计原则 (简单可依赖)2、系统架构及主要特性 (单进程单线程异步)3、主要应用场景及性能 (10w QPS -RW)4、内存结构分析(源代码)5、持久化及主从复制(aof/rdb)6、目前存在的主要不足(坑)7、最新进展及功能展望(集群化)作者主页:http:/ Salvatore Sanfilippo and Pieter Noordhuis (Sponsors: Vmware ).Remote Dictionary Server(Redis)-AK47开源,ANSI C语言编写、支持持久化性能极高:单机10万读写请求丰富的

2、特性 : 支持 publish/subscribe, key 过期,主从复制,failover事物支持(multi/exec/watch/discard)丰富的数据类型及对应的操作:Lists ,Sets ,Sorted sets ,Hashes (交集、并集、查集、自增等原子操作) “内存是新的硬盘,硬盘是新的磁带” 图灵奖得主Jim Gray 1 - A DSL for Abstract Data Types. 2 - Memory storage is #1. (vm功能被取消) 3 - Fundamental data structures for a fundamental API.

3、 4 - Code is like a poem; (欢迎self contained libraries) 5 - Were against complexity. 6 - Two levels of API. 7 - We optimize for joy. Redis Manifesto(设计原则)-自由软件经营之道 Benchmark(组内开发机, Intel(R) Xeon(R) CPU 5150 2.66GHz)./redis-benchmark -h 9 -p 6379 -c 250 -d 32 -r 10000 -n 100000 -q PING_INLI

4、NE: 74794.31 requests per secondPING_BULK: 73583.52 requests per secondSET: 68446.27 requests per secondGET: 68917.99 requests per secondINCR: 68119.89 requests per secondLPUSH: 74962.52 requests per secondLPOP: 73421.44 requests per secondSADD: 68212.83 requests per secondSPOP: 71787.51 requests pe

5、r secondLPUSH (needed to benchmark LRANGE): 71890.73 requests per secondLRANGE_100 (first 100 elements): 21565.67 requests per secondLRANGE_300 (first 300 elements): 9309.25 requests per secondLRANGE_500 (first 450 elements): 6012.87 requests per secondLRANGE_600 (first 600 elements): 4523.04 reques

6、ts per secondMSET (10 keys): 35211.27 requests per second如果开启pipeline模式,性能是至少是5X.单个客户端(单线程)查询在每秒3000以上。Redis源码概览(零依赖、自包含)ae.c (事件驱动库,默认使用epoll)sds.c(key,char *的封装 )adlist.c(双向链表)dict.c(hash字典,基础结构)db.czipmap.c/ziplist.c/intset.c(压缩数据结构)t_list.c,t_set.c,t_zset.c,t_string.c,t_hash.c(处理各种命令)networking,

7、redis.c(网络处理,程序入口)zmalloc.c.(可选malloc,jemalloc,tcmalloc)replication.c(主从复制)aof.c,rdb.c,slowlog.c,bio.c,lzf.c(压缩)-Redis命令示例命令示例Set key (INCR)Get keyRpush list valueLrange list start endHset ht key valueHget ht keyMulti/execwatch(乐观锁)SORT key BY pattern LIMIT start count GET pattern ASC|DESC ALPHA STO

8、RE dstkeyRedis配置文件示例配置文件示例Redis 内存存储结构内存存储结构struct of redisDb & dicttypedef struct redisDb dict *dict; /* The keyspace for this DB */ dict *expires; /* Timeout of keys with a timeout set */ dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */ dict *watched_keys; /* WATCHED keys for

9、MULTI/EXEC CAS */ int id; /(0-16) redisDb;typedef struct dict dictType *type; void *privdata; dictht ht2; /用了2个hash表,单线程,防止rehashing期间性能大幅度下降 int rehashidx; /* rehashing not in progress if rehashidx = -1 */ int iterators; /* number of iterators currently running */ dict;sds(key) & redisObject (val)t

10、ypedef char *sds;struct sdshdr int len; int free; char buf; /二进制安全;typedef struct redisObject unsigned type:4; unsigned notused:2; /* Not used ,以前用作vm*/ unsigned encoding:4; /- unsigned lru:22; /* lru time (relative to server.lruclock) */ int refcount; /引用计数 void *ptr; robj;SET KEY STRING实例实例具体例子str

11、uct zset (有序(有序set) Skip list是一种多层次的有序链表,通过随机地选择层数来实现插入、查找和删除都是O(logn)的时间复杂度typedef struct zskiplistNode struct zskiplistNode *forward;struct zskiplistNode *backward;double score;robj *obj; zskiplistNode;typedef struct zskiplist struct zskiplistNode *header, *tail;unsigned long length;int level;/层数

12、zskiplist;typedef struct zset dict *dict;zskiplist *zsl; /skiplist zset;SkipList (平衡树的概率版)(平衡树的概率版)跳表具有如下性质:(1) 由很多层结构组成(2) 每一层都是一个有序的链表(3) 最底层(Level 1)的链表包含所有元素(4) 如果一个元素出现在 Level i 的链表中,则它在 Level i 之下的链表也都会出现。(5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。插入插入,删除删除skiplist跳表的插入跳表的插入先确定该元素要占据的层数 K(采用丢硬

13、币的方式,这完全是随机的)然后在 Level 1 . Level K 各个层的链表都插入元素。例子:插入 119, K = 2内容使用效率问题内容使用效率问题Redis数据存储优化机制 1.zipmap优化优化hash hash-max-zipmap-entries 512 #配置字段最多512个 hash-max-zipmap-value 64 #配置value最大为64字节2.ziplist优化优化list list_max_ziplist_entries list_max_ziplist_value 3.intset优化优化set set_max_intset_entries4.zipl

14、ist优化优化sorted set zset_max_ziplist_entries zset_max_ziplist_value 根据不同的需求调整参数,对性能有很大的影响 优化空间优化空间ziplist内存使用效率优化内存使用效率优化intset固定宽度,有序存放,二分检索createSharedObjects()函数 将一些在程序中反复大量使用到的变量在程序启动时就创建好,全局共享,节省大量内存和变量分配的初始化时间。shared.crlf = createObject(REDIS_STRING,sdsnew(rn);shared.ok = createObject(REDIS_STRI

15、NG,sdsnew(+OKrn);shared.err = createObject(REDIS_STRING,sdsnew(-ERRrn);shared.emptybulk = createObject(REDIS_STRING,sdsnew($0rnrn);for (j = 0; j encoding = REDIS_ENCODING_INT;请求回复aof协议Inline 协议协议协议格式:argv0 argv1 argv2 . CR LF举例:SET mykey 6 CR LFMultibulk 协议(协议(AOF文件采用文件采用)协议格式* CR LF$ CR LF CR LF.$

16、CR LF CR LF协议举例 (aof文件)*3$3SET$5mykey$7myvalue共用协议对应一些错误或简单的成功返回,inline 和multibulk 是一样的比如:+OKrn或者-ERRrn等等Main函数int main(int argc, char *argv) zmalloc_enable_thread_safeness(); initServerConfig(); if (server.sentinel_mode) initSentinelConfig(); initSentinel(); / if (server.daemonize) daemonize(); ini

17、tServer(); /-创建定时事件等等 loadDataFromDisk(); /aof 、rdb 恢复AOF 文件优先 aeSetBeforeSleepProc(server.el,beforeSleep); /注册每次事件循环前要执行的函数 aeMain(server.el); /主事件循环 / server为全局变量 aeDeleteEventLoop(server.el); return 0;单线程异步的执行流程(EPOLL)1. Redis支持 epoll, select, kquque,通过配置文件来决定采取哪一种 2. 支持文件读写事件和定时事件 (servercon)3.

18、采用数组来维护文件事件,链表来保存定时事件(在查找定时事件时,性能不高,有待提高) 4. Redis Server单线程响应事件,按照先后顺序来响应事件,因此单台 Redis服务器的吞吐量会随着连接的 clients越来越多而下降,可以通过增加更多的 Redis服务器来解决这个问题 5. Redis在很多代码里都考虑到了尽快地响应各种事件,如在 aeProcessEvent里面,轮询的 wait时间等于当前时间和最近的定时事件响应时间的差值;每次进入轮询 wait之前,在 beforesleep方法里先响应刚刚 unblock的 clients等。 aeMain函数void aeMain(ae

19、EventLoop *eventLoop) eventLoop-stop = 0; while (!eventLoop-stop) if (eventLoop-beforesleep != NULL) eventLoop-beforesleep(eventLoop); aeProcessEvents(eventLoop, AE_ALL_EVENTS); #define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS)aeEventLoop/* State of an event based program */typedef struct aeEven

20、tLoop int maxfd; /* highest file descriptor currently registered */ int setsize; /* max number of file descriptors tracked */ long long timeEventNextId; aeFileEvent *events; /* Registered events */ aeFiredEvent *fired; /* Fired events */ aeTimeEvent *timeEventHead; / 链表 int stop; void *apidata; /* T

21、his is used for polling API specific data */ aeBeforeSleepProc *beforesleep; aeEventLoop;serverCron - (维护状态,统计信息等)#define run_with_period(_ms_) if (!(server.cronloops%(_ms_)/(1000/REDIS_HZ) int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) /列出了主要函数 if (server.watchdog_per

22、iod) watchdogScheduleSignal(server.watchdog_period); updateLRUClock(); tryResizeHashTables(); if (server.activerehashing) incrementallyRehash(); clientsCron(); rewriteAppendOnlyFileBackground(); if (server.aof_flush_postponed_start) flushAppendOnlyFile(0); if (server.masterhost = NULL) activeExpireC

23、ycle(); /master过期处理 freeClientsInAsyncFreeQueue(); run_with_period(1000) replicationCron(); server.cronloops+; 简单事物支持int processCommand(redisClient *c) /* Exec the command */ if (c-flags & REDIS_MULTI & c-cmd-proc != execCommand & c-cmd-proc != discardCommand & c-cmd-proc != multiCommand & c-cmd-pro

24、c != watchCommand) queueMultiCommand(c); addReply(c,shared.queued); else call(c,REDIS_CALL_FULL); return REDIS_OK;在事务的执行过程中不会为另一个客户端发起的请求提供服务来确保原子性。Errors inside a transaction (正确部分会正确执行,错误部分不回滚)Redis is internally simplified and faster because it does not need the ability to roll back. (AK47)乐观锁,Op

25、timistic locking using check-and-set(watch)当AOF开启的时候:每个属于某个Redis事务的命令只要操作完成了的话就会记录在AOF中,所以如果Redis服务器崩溃或者被系统管理员以一种粗暴的方式杀死,可能只有部分操作被登记在AOF中。(check-aof命令修复)事物支持的特点持久化持久化 Persistenceredis使用了两种文件格式:全量数据和增量请求。Snapshot 快照 (rdb 二进制格式)Fork process, loop hash table, save on file dump.rdbsequential write (copy

26、 on write 机制)Aof (一般设置为1秒 fsync一次即可满足使用需求)Like binlog, for recover after crashappendfsyncAof file is big use bgrewriteaof(文本格式,mulitbulk)AOF ( Asynchronous AOF fsync )在发送数据之前先写aof文件void beforeSleep(struct aeEventLoop *eventLoop) - /* Write the AOF buffer on disk */ flushAppendOnlyFile(0); server.aof

27、_buf = sdsempty(); serverCron() flushAppendOnlyFile(0); aof文件例子 (cat my.aof) *3 $3 SET $5 mykey $7 myvalue主从复制replication第一次Slave向Master同步的实现是:Slave向Master发出同步请求,Master先dump出rdb文件,然后将rdb文件全量传输给slave,然后Master把缓存的命令转发给Slave,初次同步完成。第二次以及以后的同步实现是:Master将变量的快照直接实时依次发送给各个Slave。不管什么原因导致Slave和Master断开重连都会重复

28、以上过程。Redis的主从复制是建立在内存快照的持久化基础上,只要有Slave就一定会有内存快照发生。在serverCron()中,Master会删除过期的数据,Slave则等待Master同步,DEL指令将过期数据删除。(强一致性保证) if (server.masterhost = NULL) activeExpireCycle();Pre-Sharding方法是将每一个台物理机上,运行多个不同断口的Redis实例,假如有三个物理机,每个物理机运行三个Redis实例,那么我们的分片列表中实际有9个Redis实例,当我们需要扩容时,增加一台物理机,步骤如下:A. 在新的物理机上运行Redis

29、-Server;B. 该Redis-Server从属于(slaveof)分片列表中的某一Redis-Server(假设叫RedisA);C. 等主从复制(Replication)完成后,将客户端分片列表中RedisA的IP和端口改为新物理机上Redis-Server的IP和端口;D. 停止RedisA。 这样相当于将某一Redis-Server转移到了一台新机器上。Prd-Sharding实际上是一种在线扩容的办法,但还是很依赖Redis本身的复制功能的,如果主库快照数据文件过大,这个复制的过程也会很久,同时会给主库带来压力。在线扩容(Pre-Sharding)典型应用场景(举例)-weibo

30、新浪微博大约使用了200台服务器,并且部分参与了redis的开发。新浪微博中Redis主要用于两个方面:好友关系和计数器。用Redis来存储好友关系好友关系,解决了对following和follower两张表插入时的插入慢、非事务和一致性问题。用Redis记录数字数字,包括永久计数和临时计数,较适应“大写入量,大读取量,持久化”的场景。 数据规模上,存储关系:“TB级级”且“growing fast”,记录数字: “场景:微博的评论数;每天写入亿级,每天读取十亿级”。公司内部使用情况调研-移动云架构部 目前支持的主要业务 主要提供BAE的counter(点击计数)、rank(最火的app)、全局appid分配、bsmc的消息推送服务(暂未上线)。 集群规模 共8台同构30G内存限制的服务器

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论