这一篇中我们实现了不通过zk来编写codis集群proxys的api,http://www.cnblogs.com/kangoroo/p/7481567.html

如果codis集群暴露zk给你的话,那么就方便了,探活和故障摘除与恢复codis集群都给你搞定了,你只需要监听zookeeper中实例的状态就好了。

下面看我的实现。

1、CodisByZKPool.py

这里通过zk读取并初始化pool_shards,简单说一下如何故障摘除和恢复

1)我们监听zk中节点状态改变,当发现某个实例对应的节点状态变化了,比如DELETE了,那么我们认为这个实例挂了,我们就会重新_create_pool刷新shards列表,摘除故障实例。

2)同样,当我们发现节点CREATE,就是新增了实例,或者实例从崩溃中恢复了,我们也会重新_create_pool刷新shards列表,新增实例。

  1. # -*- coding:utf-8 -*-
  2. import redis
  3. import logging
  4. from kazoo.client import KazooClient
  5. from Podis import Podis
  6. from PickUp import RandomPickUp, PickUp
  7.  
  8. logger = logging.getLogger(__name__)
  9.  
  10. class CodisByZKPool(object):
  11.  
  12. def __init__(self, zk_config):
  13. self._pool_shards = []
  14. self.zk_config = zk_config
  15. self.zk = self._init_zk()
  16.  
  17. def _init_zk(self):
  18. return KazooClient(hosts=self.zk_config.get('hosts'), timeout=self.zk_config.get('timeout'))
  19.  
  20. def _create_pool(self):
  21. try:
  22. if not self.zk.connected:
  23. self.zk.start()
  24. address_list = self.zk.get_children(self.zk_config.get('path'), watch=self._watch_codis_instances)
  25. for address in address_list:
  26. host = address.split(':')[0]
  27. port = address.split(':')[1]
  28. self._pool_shards.append(
  29. Podis(
  30. redis.ConnectionPool(
  31. host=host, port=port, db=0,
  32. password=None,
  33. max_connections=None
  34. )
  35. )
  36. )
  37. if len(self._pool_shards) == 0:
  38. raise Exception('create pool failure!')
  39. except Exception, ex:
  40. raise
  41. finally:
  42. self.zk.stop()
  43.  
  44. def _watch_codis_instances(self, event):
  45. if event.type == "CREATED" and event.state == "CONNECTED":
  46. self._create_pool()
  47. elif event.type == "DELETED" and event.state == "CONNECTED":
  48. self._create_pool()
  49. elif event.type == "CHANGED" and event.state == "CONNECTED":
  50. self._create_pool()
  51. elif event.type == "CHILD" and event.state == "CONNECTED":
  52. self._create_pool()
  53. else:
  54. logger.error('failure: not cover this event - %s'.format(event.type))
  55.  
  56. def get_connection(self, pick_up=None):
  57. if isinstance(pick_up, PickUp):
  58. codisPool = pick_up.pick_up(self._pool_shards)
  59. else:
  60. pick_up = RandomPickUp()
  61. codisPool = pick_up.pick_up(self._pool_shards)
  62. return codisPool
  63.  
  64. def get_availables(self):
  65. return self._pool_shards

2、负载均衡PickUp.py

上一篇一样,这里就不多说了。

  1. # -*- coding:utf-8 -*-
  2. import abc
  3. import uuid
  4. import threading
  5.  
  6. class PickUp(object):
  7.  
  8. __metaclass__ = abc.ABCMeta
  9.  
  10. @abc.abstractmethod
  11. def __init__(self):
  12. pass
  13.  
  14. @abc.abstractmethod
  15. def pick_up(self, pool_list):
  16. return
  17.  
  18. class RandomPickUp(PickUp):
  19. def __init__(self):
  20. PickUp.__init__(self)
  21.  
  22. def pick_up(self, pool_list):
  23. pool_size = len(pool_list)
  24. index = abs(hash(uuid.uuid4())) % pool_size
  25. pool = pool_list[index]
  26. print "RandomPickUp, 拿到第", index, "个pool"
  27. return pool
  28.  
  29. class RoundRobinPickUp(PickUp):
  30.  
  31. def __init__(self):
  32. PickUp.__init__(self)
  33. self.index = 0
  34. self.round_robin_lock = threading.Lock()
  35.  
  36. def pick_up(self, pool_list):
  37. with self.round_robin_lock:
  38. pool_size = len(pool_list)
  39. self.index += 1
  40. index = abs(self.index) % pool_size
  41. pool = pool_list[index]
  42. print "RoundRobinPickUp, 拿到第", index, "个pool"
  43. return pool

3、配置文件

这里就只用zk_config就可以了,我们认为在zk中已经有所有的codisproxy实例的address了。

  1. codis_config = {
  2. 'addrs': '100.90.186.47:3000,100.90.187.33:3000'
  3. }
  4.  
  5. zk_config = {
  6. 'hosts': '10.93.21.21:2181,10.93.18.34:2181,10.93.18.35:2181',
  7. 'timeout': 10,
  8. 'path': '/codis/instances'
  9. }

4、链接类Podis.py

  1. # -*- coding:utf-8 -*-
  2. import redis
  3. import logging
  4. import traceback
  5.  
  6. logger = logging.getLogger(__name__)
  7.  
  8. def redis_getter(func):
  9. def wrapper(*args, **kwargs):
  10. try:
  11. result = func(*args, **kwargs)
  12. return result or None
  13. except Exception, ex:
  14. logger.error(traceback.format_exc())
  15. raise
  16. return wrapper
  17.  
  18. def redis_setter(func):
  19. def wrapper(*args, **kwargs):
  20. try:
  21. func(*args, **kwargs)
  22. return True
  23. except Exception, ex:
  24. logger.error(traceback.format_exc())
  25. raise
  26. return wrapper
  27.  
  28. class Podis(object):
  29.  
  30. def __init__(self, pool):
  31. self._connection = redis.StrictRedis(connection_pool=pool)
  32.  
  33. @redis_getter
  34. def ping(self):
  35. return self._connection.ping()
  36.  
  37. @redis_getter
  38. def get(self, key):
  39. return self._connection.get(key)
  40.  
  41. @redis_setter
  42. def set(self, key, value):
  43. self._connection.set(key, value)
  44.  
  45. @redis_setter
  46. def lpush(self, key, *value):
  47. self._connection.lpush(key, *value)
  48.  
  49. @redis_getter
  50. def lpop(self, key):
  51. return self._connection.lpop(key)
  52.  
  53. @redis_getter
  54. def lrange(self, key, start, end):
  55. return self._connection.lrange(key, start, end)
  56.  
  57. @redis_setter
  58. def sadd(self, key, *value):
  59. self._connection.sadd(key, *value)
  60.  
  61. @redis_setter
  62. def srem(self, key, *value):
  63. self._connection.srem(key, *value)
  64.  
  65. @redis_getter
  66. def zrange(self,key,start,end):
  67. return self._connection.zrange(key,start,end)
  68.  
  69. @redis_getter
  70. def zrevrange(self,key,start,end):
  71. return self._connection.zrevrange(key,start,end,withscores=True)
  72.  
  73. @redis_getter
  74. def zscore(self,key,*value):
  75. return self._connection.zscore(key,value)
  76.  
  77. @redis_setter
  78. def zadd(self,key,score,*value):
  79. self._connection.zadd(key,score,value)
  80.  
  81. @redis_getter
  82. def smembers(self, key):
  83. return self._connection.smembers(key)
  84.  
  85. @redis_getter
  86. def hgetall(self, key):
  87. return self._connection.hgetall(key)
  88.  
  89. @redis_getter
  90. def hget(self, key, name):
  91. return self._connection.hget(key, name)
  92.  
  93. @redis_getter
  94. def hkeys(self, key):
  95. return self._connection.hkeys(key)
  96.  
  97. @redis_setter
  98. def hset(self, key, name, value):
  99. self._connection.hset(key, name, value)
  100.  
  101. @redis_setter
  102. def hmset(self, name, mapping):
  103. self._connection.hmset(name, mapping)
  104.  
  105. @redis_setter
  106. def hdel(self, key, name):
  107. self._connection.hdel(key, name)
  108.  
  109. @redis_setter
  110. def delete(self, *key):
  111. self._connection.delete(*key)
  112.  
  113. # codis不支持
  114. @redis_getter
  115. def keys(self, pattern):
  116. return self._connection.keys(pattern)
  117.  
  118. @redis_setter
  119. def expire(self, key, time):
  120. return self._connection.expire(key, time)
  121.  
  122. @redis_getter
  123. def ttl(self, key):
  124. return self._connection.ttl(key)

5、例子

  1. import sys
  2. sys.path.append('../')
  3. import time
  4. import threading
  5. from pycodis.CodisConfig import zk_config
  6. from pycodis.CodisByZKPool import CodisByZKPool
  7. from pycodis.PickUp import RoundRobinPickUp
  8.  
  9. codis_pool1 = CodisByZKPool(zk_config)
  10. print '------1-------'
  11. pick_up1 = RoundRobinPickUp()
  12. print '------2-------'
  13. codis_pool2 = CodisByZKPool(zk_config)
  14. print '------3-------'
  15. pick_up2 = RoundRobinPickUp()
  16. print '------4-------'
  17.  
  18. def func(i):
  19. for i in range(10):
  20. podis1 = codis_pool1.get_connection(pick_up=pick_up1)
  21. podis2 = codis_pool2.get_connection(pick_up=pick_up2)
  22. podis1.delete(i)
  23. podis2.delete(i)
  24. time.sleep(1)
  25.  
  26. thread_list = []
  27. for i in range(100):
  28. thread_list.append(threading.Thread(target=func, args=[i]))
  29.  
  30. for thread in thread_list:
  31. thread.setDaemon(True)
  32. thread.start()
  33.  
  34. time.sleep(10)

python codis集群客户端(二) - 基于zookeeper对实例创建与摘除的更多相关文章

  1. python codis集群客户端(一) - 基于客户端daemon探活与服务列表维护

    在使用codis时候,我们遇到的场景是,公司提供了HA的Proxy(例如N个),但是不暴露zookeeper(也就是说没有codis后端服务列表). 如果暴露zk的话,可以看这一篇,http://ww ...

  2. 七、Hadoop3.3.1 HA 高可用集群QJM (基于Zookeeper,NameNode高可用+Yarn高可用)

    目录 前文 Hadoop3.3.1 HA 高可用集群的搭建 QJM 的 NameNode HA Hadoop HA模式搭建(高可用) 1.集群规划 2.Zookeeper集群搭建: 3.修改Hadoo ...

  3. Dubbo+zookeeper构建高可用分布式集群(二)-集群部署

    在Dubbo+zookeeper构建高可用分布式集群(一)-单机部署中我们讲了如何单机部署.但没有将如何配置微服务.下面分别介绍单机与集群微服务如何配置注册中心. Zookeeper单机配置:方式一. ...

  4. Linux Redis集群搭建与集群客户端实现(Python)

    硬件环境 本文适用的硬件环境如下 Linux版本:CentOS release 6.7 (Final) Redis版本: Redis已经成功安装,安装路径为/home/idata/yangfan/lo ...

  5. 实战Centos系统部署Codis集群服务

    导读 Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可 ...

  6. Codis集群的搭建与使用

    一.简介 Codis是一个分布式的Redis解决方案,对于上层的应用来说,连接Codis Proxy和连接原生的Redis Server没有明显的区别(不支持的命令列表),上层应用可以像使用单机的Re ...

  7. Codis集群的搭建

    Codis集群的搭建与使用   一.简介 Codis是一个分布式的Redis解决方案,对于上层的应用来说,连接Codis Proxy和连接原生的Redis Server没有明显的区别(不支持的命令列表 ...

  8. [Big Data - Codis] Codis集群的搭建与使用

    一.简介 Codis是一个分布式的Redis解决方案,对于上层的应用来说,连接Codis Proxy和连接原生的Redis Server没有明显的区别(不支持的命令列表),上层应用可以像使用单机的Re ...

  9. JMS之——ActiveMQ 高可用与负载均衡集群安装、配置(ZooKeeper + LevelDB + Static discovery)

    一.说明 从 ActiveMQ 5.9 开始, ActiveMQ 的集群实现方式取消了传统的 Master-Slave 方式,增加了基于ZooKeeper + LevelDB 的 Master-Sla ...

随机推荐

  1. Project 1 :创建链表与显示链表

    目标:创建一个链表,并将链表输出.结构体中包括学号与分数.链表以输入学号为0作为结束.输出模版为 No.学号 Score:分数 输入样例: 10101 98 10102 97 10103 100 10 ...

  2. PHP初入,div知识点整理(特效&字体等元素的使用整理)

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  3. 自制ACL+DHCP实验(初版)

    (实验用gns模拟器) ACL 实验拓扑: 实验要求: 1.1.1.1→3.3.3.3 不通 11.11.11.11→3.3.3.3 通 2.2.2.2→3.3.3.3 通 实验步骤: 步骤一:基本配 ...

  4. Markdown 模板

    一个例子: 例子开始 1. 本章学习总结 今天主要学习了三个知识点 封装 继承 多态 2. 书面作业 Q1. java HelloWorld命令中,HelloWorld这个参数是什么含义? 今天学了一 ...

  5. Mybatis映射文件处理特殊字符【转发】

    该博文下的方法就非常好了! http://blog.csdn.net/zheng0518/article/details/10449549

  6. Servlet第七篇【Cookie和Session的区别、应用】

    Session和Cookie的区别 从存储方式上比较 Cookie只能存储字符串,如果要存储非ASCII字符串还要对其编码. Session可以存储任何类型的数据,可以把Session看成是一个容器 ...

  7. Android 之json解析

    JSON(JavaScript Object Notation) 定义:字符串 键值对 解析方法有JSON,谷歌GSON,阿里巴巴FastJSON(推荐) 一种轻量级的数据交换格式,具有良好的可读和便 ...

  8. 如何快速成长?我的java之路!

    由于一些外部的原因,我不得不从自己熟悉的php领域,转战到java战场.我个人觉得还是有些心得吧,不管怎么样,或多或少可能都会有那么些经历的人,和你一起走在这世上!尽管你不知道TA是谁. 其实,转换一 ...

  9. thinkphp5.0无限极分类及格式化输出

    首先我们来看数据表 从上图中可以发现,中国下有贵州,北京两个子节点,而北京有天安门一个子节点,纽约的子节点是"纽约的子类". 从pid为0看出,中国和纽约是顶级节点. 因为贵州的p ...

  10. 转自知乎(JAVA后台开发可以纯粹用JAVA SE吗?)

    著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:巴多崽链接:http://www.zhihu.com/question/29663744/answer/45154839来源: ...