python codis集群客户端(二) - 基于zookeeper对实例创建与摘除
在这一篇中我们实现了不通过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列表,新增实例。
# -*- coding:utf-8 -*-
import redis
import logging
from kazoo.client import KazooClient
from Podis import Podis
from PickUp import RandomPickUp, PickUp logger = logging.getLogger(__name__) class CodisByZKPool(object): def __init__(self, zk_config):
self._pool_shards = []
self.zk_config = zk_config
self.zk = self._init_zk() def _init_zk(self):
return KazooClient(hosts=self.zk_config.get('hosts'), timeout=self.zk_config.get('timeout')) def _create_pool(self):
try:
if not self.zk.connected:
self.zk.start()
address_list = self.zk.get_children(self.zk_config.get('path'), watch=self._watch_codis_instances)
for address in address_list:
host = address.split(':')[0]
port = address.split(':')[1]
self._pool_shards.append(
Podis(
redis.ConnectionPool(
host=host, port=port, db=0,
password=None,
max_connections=None
)
)
)
if len(self._pool_shards) == 0:
raise Exception('create pool failure!')
except Exception, ex:
raise
finally:
self.zk.stop() def _watch_codis_instances(self, event):
if event.type == "CREATED" and event.state == "CONNECTED":
self._create_pool()
elif event.type == "DELETED" and event.state == "CONNECTED":
self._create_pool()
elif event.type == "CHANGED" and event.state == "CONNECTED":
self._create_pool()
elif event.type == "CHILD" and event.state == "CONNECTED":
self._create_pool()
else:
logger.error('failure: not cover this event - %s'.format(event.type)) def get_connection(self, pick_up=None):
if isinstance(pick_up, PickUp):
codisPool = pick_up.pick_up(self._pool_shards)
else:
pick_up = RandomPickUp()
codisPool = pick_up.pick_up(self._pool_shards)
return codisPool def get_availables(self):
return self._pool_shards
2、负载均衡PickUp.py
跟上一篇一样,这里就不多说了。
# -*- coding:utf-8 -*-
import abc
import uuid
import threading class PickUp(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod
def __init__(self):
pass @abc.abstractmethod
def pick_up(self, pool_list):
return class RandomPickUp(PickUp):
def __init__(self):
PickUp.__init__(self) def pick_up(self, pool_list):
pool_size = len(pool_list)
index = abs(hash(uuid.uuid4())) % pool_size
pool = pool_list[index]
print "RandomPickUp, 拿到第", index, "个pool"
return pool class RoundRobinPickUp(PickUp): def __init__(self):
PickUp.__init__(self)
self.index = 0
self.round_robin_lock = threading.Lock() def pick_up(self, pool_list):
with self.round_robin_lock:
pool_size = len(pool_list)
self.index += 1
index = abs(self.index) % pool_size
pool = pool_list[index]
print "RoundRobinPickUp, 拿到第", index, "个pool"
return pool
3、配置文件
这里就只用zk_config就可以了,我们认为在zk中已经有所有的codisproxy实例的address了。
codis_config = {
'addrs': '100.90.186.47:3000,100.90.187.33:3000'
}
zk_config = {
'hosts': '10.93.21.21:2181,10.93.18.34:2181,10.93.18.35:2181',
'timeout': 10,
'path': '/codis/instances'
}
4、链接类Podis.py
# -*- coding:utf-8 -*-
import redis
import logging
import traceback logger = logging.getLogger(__name__) def redis_getter(func):
def wrapper(*args, **kwargs):
try:
result = func(*args, **kwargs)
return result or None
except Exception, ex:
logger.error(traceback.format_exc())
raise
return wrapper def redis_setter(func):
def wrapper(*args, **kwargs):
try:
func(*args, **kwargs)
return True
except Exception, ex:
logger.error(traceback.format_exc())
raise
return wrapper class Podis(object): def __init__(self, pool):
self._connection = redis.StrictRedis(connection_pool=pool) @redis_getter
def ping(self):
return self._connection.ping() @redis_getter
def get(self, key):
return self._connection.get(key) @redis_setter
def set(self, key, value):
self._connection.set(key, value) @redis_setter
def lpush(self, key, *value):
self._connection.lpush(key, *value) @redis_getter
def lpop(self, key):
return self._connection.lpop(key) @redis_getter
def lrange(self, key, start, end):
return self._connection.lrange(key, start, end) @redis_setter
def sadd(self, key, *value):
self._connection.sadd(key, *value) @redis_setter
def srem(self, key, *value):
self._connection.srem(key, *value) @redis_getter
def zrange(self,key,start,end):
return self._connection.zrange(key,start,end) @redis_getter
def zrevrange(self,key,start,end):
return self._connection.zrevrange(key,start,end,withscores=True) @redis_getter
def zscore(self,key,*value):
return self._connection.zscore(key,value) @redis_setter
def zadd(self,key,score,*value):
self._connection.zadd(key,score,value) @redis_getter
def smembers(self, key):
return self._connection.smembers(key) @redis_getter
def hgetall(self, key):
return self._connection.hgetall(key) @redis_getter
def hget(self, key, name):
return self._connection.hget(key, name) @redis_getter
def hkeys(self, key):
return self._connection.hkeys(key) @redis_setter
def hset(self, key, name, value):
self._connection.hset(key, name, value) @redis_setter
def hmset(self, name, mapping):
self._connection.hmset(name, mapping) @redis_setter
def hdel(self, key, name):
self._connection.hdel(key, name) @redis_setter
def delete(self, *key):
self._connection.delete(*key) # codis不支持
@redis_getter
def keys(self, pattern):
return self._connection.keys(pattern) @redis_setter
def expire(self, key, time):
return self._connection.expire(key, time) @redis_getter
def ttl(self, key):
return self._connection.ttl(key)
5、例子
import sys
sys.path.append('../')
import time
import threading
from pycodis.CodisConfig import zk_config
from pycodis.CodisByZKPool import CodisByZKPool
from pycodis.PickUp import RoundRobinPickUp codis_pool1 = CodisByZKPool(zk_config)
print '------1-------'
pick_up1 = RoundRobinPickUp()
print '------2-------'
codis_pool2 = CodisByZKPool(zk_config)
print '------3-------'
pick_up2 = RoundRobinPickUp()
print '------4-------' def func(i):
for i in range(10):
podis1 = codis_pool1.get_connection(pick_up=pick_up1)
podis2 = codis_pool2.get_connection(pick_up=pick_up2)
podis1.delete(i)
podis2.delete(i)
time.sleep(1) thread_list = []
for i in range(100):
thread_list.append(threading.Thread(target=func, args=[i])) for thread in thread_list:
thread.setDaemon(True)
thread.start() time.sleep(10)
python codis集群客户端(二) - 基于zookeeper对实例创建与摘除的更多相关文章
- python codis集群客户端(一) - 基于客户端daemon探活与服务列表维护
在使用codis时候,我们遇到的场景是,公司提供了HA的Proxy(例如N个),但是不暴露zookeeper(也就是说没有codis后端服务列表). 如果暴露zk的话,可以看这一篇,http://ww ...
- 七、Hadoop3.3.1 HA 高可用集群QJM (基于Zookeeper,NameNode高可用+Yarn高可用)
目录 前文 Hadoop3.3.1 HA 高可用集群的搭建 QJM 的 NameNode HA Hadoop HA模式搭建(高可用) 1.集群规划 2.Zookeeper集群搭建: 3.修改Hadoo ...
- Dubbo+zookeeper构建高可用分布式集群(二)-集群部署
在Dubbo+zookeeper构建高可用分布式集群(一)-单机部署中我们讲了如何单机部署.但没有将如何配置微服务.下面分别介绍单机与集群微服务如何配置注册中心. Zookeeper单机配置:方式一. ...
- Linux Redis集群搭建与集群客户端实现(Python)
硬件环境 本文适用的硬件环境如下 Linux版本:CentOS release 6.7 (Final) Redis版本: Redis已经成功安装,安装路径为/home/idata/yangfan/lo ...
- 实战Centos系统部署Codis集群服务
导读 Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可 ...
- Codis集群的搭建与使用
一.简介 Codis是一个分布式的Redis解决方案,对于上层的应用来说,连接Codis Proxy和连接原生的Redis Server没有明显的区别(不支持的命令列表),上层应用可以像使用单机的Re ...
- Codis集群的搭建
Codis集群的搭建与使用 一.简介 Codis是一个分布式的Redis解决方案,对于上层的应用来说,连接Codis Proxy和连接原生的Redis Server没有明显的区别(不支持的命令列表 ...
- [Big Data - Codis] Codis集群的搭建与使用
一.简介 Codis是一个分布式的Redis解决方案,对于上层的应用来说,连接Codis Proxy和连接原生的Redis Server没有明显的区别(不支持的命令列表),上层应用可以像使用单机的Re ...
- JMS之——ActiveMQ 高可用与负载均衡集群安装、配置(ZooKeeper + LevelDB + Static discovery)
一.说明 从 ActiveMQ 5.9 开始, ActiveMQ 的集群实现方式取消了传统的 Master-Slave 方式,增加了基于ZooKeeper + LevelDB 的 Master-Sla ...
随机推荐
- 201521123084 《Java程序设计》第13周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. answer: (1)netassist可以用来链接IP端口 (2)accept方法可以用来监听端口,当没 ...
- 集美大学网络1413第八次作业(团队四)-- 第一次项目冲刺(Alpha版本)成绩
首先非常抱歉,刚休完假,凌晨才回来,导致这么晚发布成绩,以后旅行可以考虑带点轻便点的笔记本~ O(∩_∩)O 第一次项目冲刺结束了,可以看出来,有的团队做的很棒,也有的团队组合不是很理想,导致进度一直 ...
- Beta冲刺前准备
一.介绍小组新成员,Ta担任的角色. 201421123121 栗海辉 来自Sugar Free 风格:低调中的高调,给你不一样的视觉 擅长的技术:C语言/JAVA 在曾经的团队里面担任主要编程人员, ...
- 201521123113《Java程序设计》第8周学习总结
1. 本周学习总结 2. 书面作业 本次作业题集集合 Q1.List中指定元素的删除(题目4-1) 1.1 实验总结 remove函数中,开始我的写法是 for(int i=0;i<list.s ...
- 201521123098 《Java程序设计》第7周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 2. 书面作业 1. ArrayList代码分析 1.1 解释ArrayList的contains源代码 该方法调用了ind ...
- 201521123064 《Java程序设计》第7周学习总结
1. 本章学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 参考资料: XMind 2. 书面作业 Q1:ArrayList代码分析 1.1 解释ArrayList的contains源 ...
- 201521123030《Java程序设计》第6周学习总结
1. 本周学习总结 2. 书面作业 1.clone方法 1.1 Object对象中的clone方法是被protected修饰,在自定义的类中覆盖clone方法时需要注意什么? 覆盖clone的方法,声 ...
- 201521123008《Java程序设计》第四周学习总结
1.本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 1.包的命名规范 2.面向对象设计:名词/动词 3.类的设计技巧:一定将属性设计为私有priv ...
- 201521123102 《Java程序设计》第1周学习总结
#1. 本周学习总结(1)初步了解java程序的运行环境,通过命令行语句编译简单的java程序(2)使用notepad编写,cmd下进入文件夹编译程序(3)学习使用各种快捷键补全代码(4)能够区别jd ...
- 201521123108《Java程序设计》第14周学习总结
1. 本周学习总结 2. 书面作业 Q1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自己的学号.姓名) 答: 在自己建立的数据库上执行常见SQL语句(截 ...