一篇文章读懂redis( 四 )

客户端连接集群

  • ./redis-cli -h 127.0.0.1 -p 7001 -c
  • 添加新的节点:./redis-trib.rb add-node 127.0.0.1:7007 127.0.0.1:7001./redis-trib.rb reshard 127.0.0.1:7001(连接上任一节点即可)./redis-trib.rb add-node --slave --master-id 主节点id 新节点的IP和端口 旧节点ip和端口(集群中任一节点都可以)
redis实现分布式锁
  • 单应用一般用synchronize,ReentrantLock实现锁
  • 分布式分布式锁注意事项:互斥性:即在任一时刻只有一个客户端能持有锁同一性:加锁和解锁必须是同一客户端可重入性:即使一个客户端没有主动解锁(崩溃等),也能保证后续其他客户端能加锁(超时时间)
  • 基于数据库的乐观锁实现分布式锁
  • zookeeper临时节点的分布式锁
  • 基于Redis的分布式锁使用set key value [ex seconds] [px milliseconds] [NX|XX]ex和px都表示过期时间,单位不一样NX是在不存在时设置,XX是在存在时设置public static boolean getLock(String lockKey, String requestId, int expireTime) {
    String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime);
    return "OK".equals(result);
    }释放锁public static void releaseLock(String requestId, String lockKey) {
    if (requestId.equals(jedis.get(lockKey))) {
    jedis.del(lockKey);
    }
    }
redis 过期策略
  • 定期删除+ 惰性删除 + 内存淘汰机制定期删除: Redis默认是每隔100ms就随机抽取一些设置了过期时间的key. 假如redis中有100万个key, 都设置了过期时间,那么肯定不会每隔100毫秒就遍历100万个key然后删除过期了的key. 当get某个key的时候, redis会检测该key有没有过期, 如果过期,就删除, 然后返回空.这就是惰性删除. 但是内存中如果有10万个key没有被访问到, 不可能让他们长期在内存中消耗内存, 这时候就需要走内存淘汰机制内存淘汰机制: noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个keyvolatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除
 
redis cluster对mget的操作Redis cluster不支持mget操作. 最初是facebook, 2010年使用memcache作缓存, 共有3000个节点. 发现节点太多, 连接频率下降. 继续增加节点, 并没有改善, 是因为IO的成本已经超过数据传输.
所以redis cluster也因此不支持mget操作.redis引入cluster模式后, 是将数据hash到16384个slot上, 每个node负责一部分slot.
mget优化方案:
  1. n个key, 传统IO, 分别获取, 时间复杂度为O(n)
  2. n个key, 通过Redis的hash算法可以得出各个key所对应的节点, 这样时间复杂度就位O(node.size())
  3. 在B方案的基础之上并发处理
redis的redlock
  • redlock的前提是有N个redis的master, 这些节点之间没有主从复制, 或者其他集群协调机制.
  • client从N个节点尝试获取锁, 只要有N/2 + 1个节点获取成功, 那么便获取成功; 如果最终获取失败, 客户端应该在所有的节点上进行解锁.
  • redlock的出发点是为了解决Redis集群环境下, 出现的分布式锁的问题(client1获取锁, master 宕机, slave变成master, client2获取到锁). 但是redlock的出现并没有解决这样的问题.
Martin和Redis作者antirez之间的争辩:
martin挑了两个缺点:
1. 对于提升效率的场景, redlock太重
2. 对于正确性要求极高的场景, redlock并不能保证正确性;
问题: 在client1获取锁之后, 由于某种原因发生系统停顿, 锁过期, 然后client1执行操作; client2这时候也会拿到锁, 就会出现问题)
问题: A, B, C, D, E 5个redis节点,如果C的时间走得快, client1拿到锁(A, B, C), C节点先过期, client2又拿到了(C, D, E)这样就出问题了;
所以Redis从根本上来说是AP, 而分布式锁是要求CP的.
redis各种数据类型的数据结构Redis的底层数据结构
  • 简单动态字符串sds(Simple Dynamic String)
  • 双端链表(LinkedList)
  • 字典(Map)
  • 跳跃表(SkipList)
redis各种数据类型使用的数据结构