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 ...
随机推荐
- Project 1 :创建链表与显示链表
目标:创建一个链表,并将链表输出.结构体中包括学号与分数.链表以输入学号为0作为结束.输出模版为 No.学号 Score:分数 输入样例: 10101 98 10102 97 10103 100 10 ...
- PHP初入,div知识点整理(特效&字体等元素的使用整理)
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- 自制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 通 实验步骤: 步骤一:基本配 ...
- Markdown 模板
一个例子: 例子开始 1. 本章学习总结 今天主要学习了三个知识点 封装 继承 多态 2. 书面作业 Q1. java HelloWorld命令中,HelloWorld这个参数是什么含义? 今天学了一 ...
- Mybatis映射文件处理特殊字符【转发】
该博文下的方法就非常好了! http://blog.csdn.net/zheng0518/article/details/10449549
- Servlet第七篇【Cookie和Session的区别、应用】
Session和Cookie的区别 从存储方式上比较 Cookie只能存储字符串,如果要存储非ASCII字符串还要对其编码. Session可以存储任何类型的数据,可以把Session看成是一个容器 ...
- Android 之json解析
JSON(JavaScript Object Notation) 定义:字符串 键值对 解析方法有JSON,谷歌GSON,阿里巴巴FastJSON(推荐) 一种轻量级的数据交换格式,具有良好的可读和便 ...
- 如何快速成长?我的java之路!
由于一些外部的原因,我不得不从自己熟悉的php领域,转战到java战场.我个人觉得还是有些心得吧,不管怎么样,或多或少可能都会有那么些经历的人,和你一起走在这世上!尽管你不知道TA是谁. 其实,转换一 ...
- thinkphp5.0无限极分类及格式化输出
首先我们来看数据表 从上图中可以发现,中国下有贵州,北京两个子节点,而北京有天安门一个子节点,纽约的子节点是"纽约的子类". 从pid为0看出,中国和纽约是顶级节点. 因为贵州的p ...
- 转自知乎(JAVA后台开发可以纯粹用JAVA SE吗?)
著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:巴多崽链接:http://www.zhihu.com/question/29663744/answer/45154839来源: ...