【代码】基于etcd的分布式队列(python版)

参考 利用zookeeper实现分布式队列

设计如下:
在这里插入图片描述
构成组件:
watcher
(长连接,监听):
1.监听业务操作etcd产生的事件,打毫秒戳来记录,写入central queue(保证对象的历史事件不丢失)
2.写入central queue后,记录此次监听的mod revision

scheduler
(短连接,定时列举):
1.从队列读出事件,分发给alive handler
2.将dead handler未消费的事件写回central queue
3.如果对象已绑定binding handler,则分发该对象的后续事件给binding handler
4.新handler成员等待,直到分配新对象(未绑定handler的对象)的事件

handler
(短连接,定时列举):
1.基于统一调度,handler成员只读取分配给自己的事件(handler 成员增减时,避免对central queue对象事件的竞争)
2.对同一对象根据事件类型合并,处理完成后删除事件

部署状态:
单实例
(多进程,多机器):watcher&scheduler(running实例工作,waiting实例等待)
多实例
(多进程,多机器):handler(多个alive实例同时工作,dead实例事件会回收)

目录结构:
在这里插入图片描述

实现代码:
client.py

import time
from concurrent import futures
from threading import Thread

import etcd3
from etcd3 import events


class Etcd:
    def __init__(self,
                 host="127.0.0.1",
                 port=2379,
                 timeout=20,
                 max_txn_ops=2**14,
                 max_message_length=512 * 1024 * 1024):
        self.client = etcd3.client(host=host,
                                   port=port,
                                   timeout=timeout,
                                   grpc_options=[('grpc.max_send_message_length', max_message_length),
                                                 ('grpc.max_receive_message_length', max_message_length)])
        self.max_txn_ops = max_txn_ops

    def wait_lock(self, name: str, ttl=10) -> etcd3.Lock:
        """try register global lock, then refresh it until process dead"""
        lock = self.client.lock(name=name, ttl=ttl)

        def wait_acquire():
            lock.acquire(timeout=None)

        def refresh():
            while True:
                if not lock.is_acquired():
                    wait_acquire()
                    continue
                lock.refresh()
                time.sleep(ttl // 2)

        wait_acquire()
        refresher = Thread(target=refresh)
        refresher.start()
        return lock

    def watch_prefix(self, key_prefix=None, start_revision=1, prev_kv=True):
        events_iterator, _ = self.client.watch_prefix(key_prefix, start_revision=start_revision, prev_kv=prev_kv)
        for ev in events_iterator:
            key = ev.key.decode()
            value = ev.value.decode()
            revision = ev.mod_revision
            event_type = "create" if isinstance(ev, events.PutEvent) else "delete"
            yield key, value, revision, event_type

    def read_key(self, key, meta=False):
        value, kv_meta_data = self.client.get(key)
        if value is not None:
            value = value.decode()
        if meta is False:
            return value
        return value, kv_meta_data

    def read_keys(self, key_prefix):
        keys = list()
        for _, meta in self.client.get_prefix(key_prefix):
            keys.append(meta.key.decode())
        return keys

    def read_items(self, key_prefix, order_func=None):
        items = list()
        for value, met
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值