欢迎投稿

今日深度:

使用 Redis 实现分布式系统轻量级协调技术(1)(3)

消息队列

消息队列是分布式系统之间的通信基本设施,通过消息可以构造复杂的进程间的协调操作和互操作。Redis 也提供了构造消息队列的原语,比如 Pub/Sub 系列命令,就提供了基于订阅/发布模式的消息收发方法,但是 Pub/Sub 消息并不在 Redis 内保持,从而也就没有进行持久化,适用于所传输的消息即使丢失了也没有关系的场景。

如果要考虑到持久化,则可以考虑 list 系列操作命令,用 PUSH 系列命令(LPUSH, RPUSH 等)推送消息到某个 list,用 POP 系列命令(LPOP, RPOP,BLPOP,BRPOP 等)获取某个 list 上的消息,通过不同的组合方式可以得到 FIFO,FILO,比如:

  1. import redis 
  2. rc = redis.Redis() 
  3.  
  4. def fifo_push(q, data): 
  5.  rc.lpush(q, data) 
  6.  
  7. def fifo_pop(q): 
  8.  return rc.rpop(q) 
  9.  
  10. def filo_push(q, data): 
  11.  rc.lpush(q, data) 
  12.  
  13. def filo_pop(q): 
  14.  return rc.lpop(q) 

如果用 BLPOP,BRPOP 命令替代 LPOP, RPOP,则在 list 为空的时候还支持阻塞等待。不过,即使按照这种方式实现了持久化,如果在 POP 消息返回的时候网络故障,则依然会发生消息丢失,针对这种需求 Redis 提供了 RPOPLPUSH 和 BRPOPLPUSH 命令来先将提取的消息保存在另外一个 list 中,客户端可以先从这个 list 查看和处理消息数据,处理完毕之后再从这个 list 中删除消息数据,从而确保了消息不会丢失,示例如下:

  1. def safe_fifo_push(q, data): 
  2.  rc.lpush(q, data) 
  3.  
  4. def safe_fifo_pop(q, cache): 
  5.  msg = rc.rpoplpush(q, cache) 
  6.  # check and do something on msg 
  7.  rc.lrem(cache, 1) # remove the msg in cache list. 
  8.  return msg 

如果使用 BRPOPLPUSH 命令替代 RPOPLPUSH 命令,则可以在 q 为空的时候阻塞等待。

结语

使用 Redis 作为分布式系统的共享内存,以共享内存模式为基础来实现分布式系统协调技术,虽然不像传统的基于消息传递的技术那样有着坚实的理论证明的基础,但是它在一些要求不苛刻的情况下不失为一种简单实用的轻量级解决方案,毕竟不是每个系统都需要严格的容错性等要求,也不是每个系统都会频繁地发生进程异常,而且 Redis 本身已经经受了工业界的多年实践和考验。另外,用 Redis 技术还有一些额外的好处,比如在开发过程中和生产环境中都可以直接观察到锁、队列的内容,实施的时候也不需要额外的特别配置过程等,它足够简单,在调试问题的时候逻辑清晰,进行排查和临时干预也比较方便。在可扩展性方面也比较好,可以动态扩展分布式系统的进程数目,而不需要事先预定好进程数目。

Redis 支持基于 Key 值 hash 的集群,在集群中应用本文所述技术时建议另外部署专用 Redis 节点(或者冗余 Redis 节点集群)来使用,因为在基于 Key 值 hash 的集群中,不同的 Key 值会根据 hash 值被分布到不同的集群节点上,而且对于 Lua 脚本的支持也受到限制,难以保证一些操作的原子性,这一点是需要考虑到的。使用专用节点还有一个好处是专用节点的数据量会少很多,当应用了 master/slave 部署或者 AOF 模式的时候,因为数据量少,master 和 slave 之间的同步会少很多,AOF 模式实时写入磁盘的数据也少很多,这样子也可以大大提高可用性。

本文示例所列 Python 代码在 Python3.4 下运行,Redis 客户端采用 redis 2.10.3 ,Redis 服务端版本为 3.0.1 版。




www.htsjk.Com true http://www.htsjk.com/shujukukf/17676.html NewsArticle 消息队列 消息队列是分布式系统之间的通信基本设施,通过消息可以构造复杂的进程间的协调操作和互操作。Redis 也提供了构造消息队列的原语,比如...
评论暂时关闭