redis3.0深入详解(1)

20 篇文章 3 订阅
19 篇文章 2 订阅

4月1日,redis3.0-stable正式发布。引入了久违的cluster模式,同时进行了多处优化。本文,从源码级别对3.0和2.8.19进行对比,详细解释优化细节。由于能力及时间有限,只会对我已经读过的源码部分进行对比,同时不涉及cluster相关内容。

1. Embedded String

减少由于cache miss带来的内存读取,进一步提升缓存命中率,在某些场景下,大幅提升速度。

1)2.8
redis中,所有对象通过robj表示,包括key和value:
typedef struct redisObject {
     unsigned type:4;
     unsigned encoding:4;
     unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
     int refcount;
     void *ptr;
} robj;
由type指定类型,泛型指针ptr指向具体的对象。对于字符串,ptr直接指向该字符串对应的内存。由于通过间接指针关联,一般情况下,robj和字符串不在连续内存中,读取字符串时,需要两次内存操作。
2)3.0
redis3.0中,如果字符串长度小于39,则会使用ebeded string,将robj和字符串分配在一块连续内存中。由于局部性原理,在读取时,robj和字符串内容都会读到cache中,从而只要一次内存读取即可。
    // <MM>
    // 分配一块内存,容纳robj, sds header, 字符串和'\0'
    // </MM>
    robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1);
    struct sdshdr *sh = (void*)(o+1);

    o->type = REDIS_STRING;
    o->encoding = REDIS_ENCODING_EMBSTR;
    o->ptr = sh+1;
    o->refcount = 1;
    o->lru = LRU_CLOCK();

    sh->len = len;
    sh->free = 0;
    if (ptr) {
        // <MM>
        // 拷贝字符串内容
        // </MM>
        memcpy(sh->buf,ptr,len);
        sh->buf[len] = '\0';
    } else {
        memset(sh->buf,0,len+1);
    }
    return o;
长度限制在39的原因是,redis使用jemalloc,会以64字节为一个内存块进行分配。robj(16字节),sds的头部(16字节)和字符串结尾的’\0'会占用25字节。

redis中所有的key都是字符串类型,所以这个优化会大幅提升redis的cache命中率。 在实际使用时,可以尽量将key的大小限制在39字节内,充分利用cache,提升性能。

2. AOF Rewrite

在完成rewrite的最后一个步骤中,redis主进程需要将rewrite期间的增量aof diff追加到aof文件中,这是一个比较重的磁盘io操作,会阻塞事件循环,增加延迟,造成服务抖动。
1)2.8
rewrite的流程:
- 主进程fork子进程,由子进程进行rewrite,主进程继续服务请求。同时主进程会初始化一个aof rewrite buffer,用于收集rewrite期间的增量aof diff。
- 子进程完成rewrite后,主进程会wait子进程并对其进行收割。此时,启动rewrite时的数据集已经生成一份aof文件,接下来主进程需要把aof rewrite buffer追加到该aof文件的最后。
由于rewrite过程比较漫长,累积的aof rewrite buffer会比较大,主进程进行追加写操作,会产生磁盘操作,阻塞事件循环,此时的redis是不能服务的,会影响业务。
2)3.0
父子进程间建立pipe进行通信。在子进程进行rewrite期间,父进程会不断的通过pipe向子进程发送aof diff,子进程会不停的收集到aof rewrite buffer中。当子进程完成rewrite后。会通知父进程停止发送aof diff。然后子进程将收集到的aof rewrite buffer追加到重写后的aof文件的最后。
父进程完成对子进程收割后,会把剩余的rewrite buffer追加到aof文件(这个rewrite buffer相对要小一些)。
改进点:
- 大部分的磁盘操作由子进程完成,父进程只需进行小数据量的磁盘操作
- aof rewrite buffer的输出会被打散到每个命令的处理过程中,降低延迟,不会造成大的抖动

3. LRU近似算法改进

如果配置了maxmemory,在每个命令处理过程中,如果占用内存超过maxmemory,redis会根据LRU算法踢出一些key,以释放内存。redis采用的LRU算法是近似的,并没有维护一个LRU链,以精确的表示先后顺序。
在robj中,由属性lru表示该对象最后被访问的时间。同时,全局变量redisServer.lruclock表示当前的lru时钟,在serverCron(每毫秒执行一次)中会不停更新lruclock。当对象被创建或者被访问时,用lruclock更新该对象的lru属性。
#define REDIS_LRU_BITS 24
typedef struct redisObject {
     unsigned type:4;
     unsigned encoding:4;
     unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
     int refcount;
     void *ptr;
} robj;
lru占用24个bit,最大值是2^24 - 1,单位是秒。那么,lru有效范围是0.5年(2^24 / 365 / 86400),当一个key半年没有被访问,其lru会重新归0,而错过踢出。
2)2.8
lruclock的计算方法:
    server.lruclock = (server.unixtime/REDIS_LRU_CLOCK_RESOLUTION) &
                                                REDIS_LRU_CLOCK_MAX;
REDIS_LRU_CLOCK_RESOLUTION表示lru的精度,设置的是秒。
在freeMemoryIfNeed函数中会进行lru踢出的逻辑。
                for (k = 0; k < server.maxmemory_samples; k++) {
                    sds thiskey;
                    long thisval;
                    robj *o;

                    // <MM>
                    // 随机选择一个kv对
                    // </MM>
                    de = dictGetRandomKey(dict);
                    thiskey = dictGetKey(de);
                    /* When policy is volatile-lru we need an additional lookup
                     * to locate the real key, as dict is set to db->expires. */
                    if (server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU)
                        de = dictFind(db->dict, thiskey);
                    o = dictGetVal(de);
                    // <MM>
                    // 获取其lru值
                    // </MM>
                    thisval = estimateObjectIdleTime(o);

                    // <MM>
                    // 选择最久没有访问的key
                    // </MM>
                    /* Higher idle time is better candidate for deletion */
                    if (bestkey == NULL || thisval > bestval) {
                        bestkey = thiskey;
                        bestval = thisval;
                    }
                }
踢出逻辑比较简单,随机选择maxmemory_samples个对象,选择其中lru值最小的作为要踢出的key。 maxmemory_samples可以配置,默认是3。
3)3.0
lruclock计算方法:
(mstime()/REDIS_LRU_CLOCK_RESOLUTION) & REDIS_LRU_CLOCK_MAX;
REDIS_LRU_CLOCK_RESOLUTION为1000,即精度是毫秒。
为了提升LRU近似算法的准确性,redisDb中增加一个属性eviction_pool,表示一个要踢出的key的候选池。
/* Redis database representation. There are multiple databases identified
 * by integers from 0 (the default database) up to the max configured
 * database. The database number is the 'id' field in the structure. */
typedef 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 *ready_keys;           /* Blocked keys that received a PUSH */
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
    struct evictionPoolEntry *eviction_pool;    /* Eviction pool of keys */
    int id;                     /* Database ID */
    long long avg_ttl;          /* Average TTL, just for stats */
} redisDb;
eviction_pool结构如下,包含一个key和其对应的lru时间。
#define REDIS_EVICTION_POOL_SIZE 16
struct evictionPoolEntry {
    unsigned long long idle;    /* Object idle time. */
    sds key;                    /* Key name. */
};
eviction_pool组织成一个数组,长度为16,并且按照idle从小到大排序。看下lru踢出逻辑,同样是在freeMemoryIfNeed函数中:
                struct evictionPoolEntry *pool = db->eviction_pool;

                while(bestkey == NULL) {
                    // <MM>
                    // 填充eviction_pool,在第一次时随机选择16个key填充,
                    // 之后每次调用时,只需要填充一个key
                    // </MM>
                    evictionPoolPopulate(dict, db->dict, db->eviction_pool);
                    /* Go backward from best to worst element to evict. */
                    for (k = REDIS_EVICTION_POOL_SIZE-1; k >= 0; k--) {
                        if (pool[k].key == NULL) continue;
                        de = dictFind(dict,pool[k].key);

                        /* Remove the entry from the pool. */
                        sdsfree(pool[k].key);
                        /* Shift all elements on its right to left. */
                        memmove(pool+k,pool+k+1,
                            sizeof(pool[0])*(REDIS_EVICTION_POOL_SIZE-k-1));
                        /* Clear the element on the right which is empty
                         * since we shifted one position to the left.  */
                        pool[REDIS_EVICTION_POOL_SIZE-1].key = NULL;
                        pool[REDIS_EVICTION_POOL_SIZE-1].idle = 0;

                        /* If the key exists, is our pick. Otherwise it is
                         * a ghost and we need to try the next element. */
                        if (de) {
                            bestkey = dictGetKey(de);
                            break;
                        } else {
                            /* Ghost... */
                            continue;
                        }
                    }
                }
填充 eviction_pool时,随机选择16个key,并按照插入排序添加到pool中。填充完之后,选择pool的最后一个元素(idle最大)作为踢出对象。
改进点:
- 精度改为毫秒,更精确
- 避免每次lru踢出时,需要多次迭代选择踢出对象

4. INCR命令

1)2.8
redis为了节省内存,对于可以整数化的字符串直接以long型存储(只占8个字节)。并且redis有一个整数常量池,对于在[0, 10000]内的整数,直接引用常量池中的对象。
    oldvalue = value;
    if ((incr < 0 && oldvalue < 0 && incr < (LLONG_MIN-oldvalue)) ||
            (incr > 0 && oldvalue > 0 && incr > (LLONG_MAX-oldvalue))) {
        addReplyError(c,"increment or decrement would overflow");
        return;
    }
    // value是原来的值,加上增量
    value += incr;
    // 根据value,创建一个新的string类型的robj,
    // 如果命中常量池,并不会创建新的对象,只有大于10000的才会创建。
    new = createStringObjectFromLongLong(value);
    // 需要一次hash查找,添加新对象或覆盖原有对象
    if (o)
        dbOverwrite(c->db,c->argv[1],new);
    else
        dbAdd(c->db,c->argv[1],new);
只要调用incr命令,就会存在一次hash查找。并且,对于大于10000的情况,需要创建新的robj
2)3.0
3.0对大于10000,不命中常量池的场景做了优化,可以避免hash查找,以及对象创建。
    // 计算新的值
    value += incr;

    if (o && o->refcount == 1 && o->encoding == REDIS_ENCODING_INT &&
            (value < 0 || value >= REDIS_SHARED_INTEGERS) &&
             value >= LONG_MIN && value <= LONG_MAX)
    {
       // 如果该对象的encoding是REDIS_ENCODING_INT,并且不在常量池的范围内
       // 同时引用计数小于1,则直接更改对象的值
       new = o;
       o->ptr = (void*)((long)value);
    } else {
       // 命中常量池,或者引用计数不唯一,按照以前的方式
       new = createStringObjectFromLongLong(value);
       if (o) {
           dbOverwrite(c->db,c->argv[1],new);
       } else {
           dbAdd(c->db,c->argv[1],new);
       }
    }
在没有命中常量池并且引用计数为1的情况,直接修改对象的值,不需要hash查找以及创建新对象。其余情况,还走原来的流程。
之所以只有引用计数为1时才进行优化,是避免与其他逻辑共享对象,造成不一致(比如key,重新编码后,hash查找会失败)。




  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
第 1 章Redis 介绍. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 第 2 章数据类型初探. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 字符串 (Strings) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 列表 (Lists). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 集合 (Sets) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 哈希 / 散列 (Hashes) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 有序集合 (Sorted sets) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 位图 (Bitmaps) 和超重对数 (HyperLogLogs) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 第 3 章从入门到精通(上) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Redis 键 (Keys). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Redis 字符串 (Strings) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 改变和查询键空间 (key space). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Redis 过期 (expires):有限生存时间的键. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 第 4 章从入门到精通(中) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Redis 列表(Lists) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Redis 列表起步. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 列表的通用场景(Common use cases) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 上限列表(Capped) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 列表的阻塞操作 (blocking) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 自动创建和删除键. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Redis 哈希/散列 (Hashes). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Redis 集合 (Sets) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 第 5 章从入门到精通(下) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Redis 有序集合 (Sorted sets) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 范围操作 (ranges) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 字典分数 (Lexicographical scores). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 更新分数:排行榜 (leader boards) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 位图 (Bitmaps). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 超重对数 (HyperLogLogs). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 其他值得注意的特性 (notable features). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 了解更多 (Learn more) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 第 6 章使用 Redis 实现 Twitter(上). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 前提条件(Prerequisites) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 数据设计(Layout) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 粉丝(followers),关注(following),和帖子(updates). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 身份验证(Authentication) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 第 7 章使用 Redis 实现 Twitter(下). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 帖子(Updates) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 帖子分页(Paginating). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 关注用户(Following users) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 水平伸缩(horizontally scalable) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 第 8 章使用 Redis 作为 LRU 缓存. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 maxmemory 配置指令(configuration directive) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 回收策略(Eviction policies) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 回收过程 (Eviction process) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 近似的 LRU 算法(Approximated LRU algorithm) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 第 9 章分片. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 分片为何有用(Why useful) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 分片基础(Basics) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 分片的不同实现(Different implementations) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 分片的缺点(Disadvantages) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 数据存储还是缓存(Store or cache) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 预分片(Presharding) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 Redis 分片的实现(Implementations) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 Redis 集群(Redis Cluster) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Twemproxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 支持一致性哈希的客户端. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 第 10 章复制. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 主服务器关闭持久化时的安全性(Safety of replication). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 Redis 复制如何工作(How works) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 部分重同步(partial resynchronization) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 无盘复制(Diskless replication) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 配置(Configuration) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 只读从服务器(Read-only slave) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 认证主服务器(Authenticate to a master) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 N 个副本才能写(Allow writes only with N attached replicas) . . . . . . . . . . . . . . . . . . . . . . . 93 第 11 章持久化. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 Redis 持久化(Persistence) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 RDB 优点(RDB advantages) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 RDB 缺点(RDB disadvantages). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 AOF 优点(AOF advantages) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 AOF 缺点(AOF disadvantages) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 我们该选谁(what) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 快照(Snapshotting) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 如何工作(How works) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 只追加文件(Append-only file) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 日志重写(Log rewriting). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 AOF 持久性如何(How durable) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 AOF 损坏了怎么办(corrupted). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 如何工作(How works) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 如何从 RDB 切换到 AOF(How switch) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 AOF 和 RDB 的相互作用(Interactions) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 备份数据(Backing up) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 灾难恢复(Disaster recovery). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 第 12 章集中插入. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 使用协议,伙计. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 生成 Redis 协议(Generating Redis Protocol) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 管道模式如何工作(How works) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 第 13 章高可用(上) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 分布式特性(Distributed nature) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 获取 Sentinel(Obtaining Sentinel) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 运行 Sentinel(Running Sentinel) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 配置 Sentinel(Configuring Sentinel). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 仲裁人数(Quorum) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 配置纪元 (Configuration epochs) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 配置传播(Configuration propagation). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 SDOWN 和 ODOWN 更多细节. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 自动发现(Auto discovery) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 第 14 章高可用(下) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 分割下的一致性(Consistency under partitions) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 Sentinel 的持久化状态 (Sentinel persistent state) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 Sentinel 重配置实例(Sentinel reconfiguration of instances). . . . . . . . . . . . . . . . . . . . . . . . 135 从服务器的选举和优先级(Slave selection and priority) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 Sentinel API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Sentinel 命令. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 运行时重配置 Sentinel(Reconfiguring Sentinel). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 添加和删除 Sentinel(Adding or removing Sentinels). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 删除旧的主服务器或不可达从服务器(unreachable) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 发布和订阅消息(Pub/Sub Messages) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 TILT 模式. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 处理 - BUSY 状态. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 Sentinel 客户端实现. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 第 15 章高可用客户端指引. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 支持Redis Sentinel的Redis客户端指引. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 支持 Redis Sentinel 的 Redis 客户端指引. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 通过 Sentinel 实现 Redis 服务发现(Redis service discovery) . . . . . . . . . . . . . . . . . . . . . . . 152 处理重连(Handling reconnections). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Sentinel 故障转移断开(Sentinel failover disconnection) . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 连接从服务器(Connecting to slaves) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 连接池(Connection pools). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 错误报告(Error reporting) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 Sentinel 列表自动刷新(Sentinels list automatic refresh) . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 订阅 Sentinel 事件来改进响应能力(Subscribe to Sentinel events to improve responsivenes s). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 额外信息(Additional information) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 第 16 章集群(上) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 Redis 集群(Redis Cluster) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 Redis 集群的 TCP 端口(Redis Cluster TCP ports) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 Redis 集群的数据分片(Redis Cluster data sharding) . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 Redis 集群的主从模型(Redis Cluster master-slave model). . . . . . . . . . . . . . . . . . . . . . 167 Redis 集群的一致性保证(Redis Cluster consistency guarantees) . . . . . . . . . . . . . . . . . 168 创建和使用 Redis 集群(Creating and using a Redis Cluster) . . . . . . . . . . . . . . . . . . . . . 170 创建集群(Creating the cluster) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 与集群共舞(Playing with the cluste) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 第 17 章集群(中) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 使用 redis-rb-cluster 写一个示例应用. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 重新分片集群(Resharding the cluster) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 一个更有意思的示例程序. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 测试故障转移(Testing the failover) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 第 18 章集群(下) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 手动故障转移(Manual failover) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 添加新节点(Adding a new node) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 添加副本节点(Adding a new node as a replica) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 移除节点(Removing a node) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 副本迁移(Replicas migration) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 升级节点(Upgrading nodes in a Redis Cluster) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 迁移到 Redis 集群(Migrating to Redis Cluster) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值