Skip to main content

Distributed lock manager, support many types of backend, e.g. redis, django-redis, etcd, zookeeper...

Project description

globallock

统一接口的分布式锁管理器,支持 RedisDjango-RedisetcdZooKeeper 四种后端。

名称 globallock 中有两个 l


安装

pip install globallock

快速开始

Redis 后端(默认)

from globallock import GlobalLockManager

config = {
    "global_lock_engine_options": {
        "host": "localhost",
        "port": 6379,
        "db": 0,
    },
}
lockman = GlobalLockManager(config)

with lockman.lock("my_lock", timeout=60, blocking=True, blocking_timeout=5) as lock:
    if lock.is_locked:
        # 获得锁,执行临界区代码
        ...
    else:
        # 未获得锁,多数情况下什么都不做
        ...

etcd 后端

from globallock import GlobalLockManager
from globallock import ETCD_GLOBAL_LOCK_CLASS

config = {
    "global_lock_engine_class": ETCD_GLOBAL_LOCK_CLASS,
    "global_lock_engine_options": {
        "host": "localhost",
        "port": 2379,
    },
}
lockman = GlobalLockManager(config)
with lockman.lock("my_lock", timeout=60, blocking=True, blocking_timeout=5) as lock:
    if lock.is_locked:
        ...

ZooKeeper 后端

from globallock import GlobalLockManager
from globallock import ZOOKEEPER_GLOBAL_LOCK_CLASS

config = {
    "global_lock_engine_class": ZOOKEEPER_GLOBAL_LOCK_CLASS,
    "global_lock_engine_options": {
        "hosts": "localhost:2181",
    },
}
lockman = GlobalLockManager(config)
with lockman.lock("my_lock", blocking=True, blocking_timeout=5) as lock:
    if lock.is_locked:
        ...

ZooKeeper 后端不支持 timeout 参数(锁不会自动超时释放)。

Django 集成

# settings.py
GLOBAL_LOCK_CONFIG = {
    "global_lock_engine_options": {
        "redis-cache-name": "default",
    },
}
from globallock.django import get_default_global_lock_manager

lockman = get_default_global_lock_manager()
with lockman.lock("my_lock", timeout=60) as lock:
    if lock.is_locked:
        ...

配置项说明

GlobalLockManager(config)

config 是一个字典,支持以下键:

类型 默认值 说明
global_lock_engine_class str globallock.redis_global_lock.RedisGlobalLock 锁定引擎类的完整路径,可使用 REDIS_GLOBAL_LOCK_CLASSDJANGO_REDIS_GLOBAL_LOCK_CLASSETCD_GLOBAL_LOCK_CLASSZOOKEEPER_GLOBAL_LOCK_CLASS 常量
global_lock_engine_options dict {} 传递给后端驱动的连接参数
global_lock_key_prefix str _glocks: 锁 key 的前缀,不同后端会自动转换为合适的格式(见"key 前缀策略")
timeout float / None None 锁超时时间(秒),超时后自动释放
sleep float 0.1 轮询等待锁的间隔(秒)
blocking bool True 是否阻塞等待锁
blocking_timeout float / None None 阻塞等待超时(秒),超时未获得锁则返回 False

timeoutsleepblockingblocking_timeout 也可以在 lockman.lock() 调用时传入,会覆盖 config 中的默认值。

lockman.lock(name, ...)

参数 类型 默认值 说明
name str 必填 锁的名称,同一时间同一名称的锁只能被一个进程持有
timeout float / None config 中的值 锁超时(秒),ZooKeeper 后端不支持
sleep float config 中的值 / 0.1 轮询间隔(秒)
blocking bool config 中的值 / True 是否阻塞
blocking_timeout float / None config 中的值 阻塞超时(秒)

锁实例方法 / 属性

方法/属性 类型 说明
lock.acquire() bool 主动请求锁,成功返回 True
lock.release() None 释放锁
lock.is_locked bool 当前是否持有锁
lock.lock_key str 锁在存储引擎中的实际 key

后端引擎说明

依赖安装

各后端的 Python 驱动需要额外安装:

后端 安装命令
RedisGlobalLock pip install redis
DjangoRedisGlobalLock pip install django-redis
EtcdGlobalLock pip install etcd3
ZookeeperGlobalLock pip install kazoo

这些驱动未声明在 globallock 的运行时依赖中,需使用者自行安装。

tenacity 兼容性

etcd3 0.12.0 需要 tenacity<8。如使用 etcd 后端,需安装兼容版本:

pip install 'tenacity<8' etcd3

Key 前缀策略

统一配置 global_lock_key_prefix(默认 _glocks:),各后端自动转换:

后端 实际 key 示例 说明
Redis _glocks:my_lock 直接使用原始前缀,: 是 Redis 的 namespace 分隔符
etcd _glocks/my_lock : 替换为 /,去掉前导 /(etcd3 Lock 内部添加 /locks/ 前缀)
ZooKeeper /_glocks/my_lock : 替换为 /,确保以 / 开头(ZooKeeper 路径要求)

如果锁名称中包含 :,该字符会保留不变(例如 lock_name = "event:test",Redis 中为 _glocks:event:test)。

ZooKeeper 后端注意事项

  • timeout 参数无效(锁不会自动释放)。
  • 进程被 kill -9 杀死后,其他进程约 10 秒后可重新获得锁。
  • 进程正常退出时,ZooKeeper 客户端会自动关闭(通过 atexit 注册清理)。

设计原理

架构

GlobalLockManager (工厂)
    │
    ├─ RedisGlobalLock ────── redis.Redis + ConnectionPool (缓存)
    ├─ DjangoRedisGlobalLock ─ django_redis.get_redis_connection
    ├─ EtcdGlobalLock ─────── etcd3.client (每个实例独立)
    └─ ZookeeperGlobalLock ── KazooClient (缓存) + atexit 清理

连接池缓存

  • Redis 的 ConnectionPool 通过 @cacheutils.simple_cache 缓存,同一进程中所有 RedisGlobalLock 实例共享一个连接池。
  • ZooKeeper 的 KazooClient 同样缓存,所有 ZookeeperGlobalLock 实例共享一个客户端连接。

开发指南

启动测试服务

# 启动所有缺失的服务
bash scripts/start-test-services.sh

# 查看状态
bash scripts/start-test-services.sh status

# 停止所有服务
bash scripts/start-test-services.sh stop

# 使用 docker 而非 podman
CONTAINER_ENGINE=docker bash scripts/start-test-services.sh start

运行测试

pip3 install -r pytest.requirements.txt

# 单元测试(无需外部服务)
python3 -m pytest tests/test_base.py tests/test_config.py tests/test_implementations.py tests/test_security.py

# 集成测试(需要对应服务)
python3 -m pytest tests/test_integration_redis.py
python3 -m pytest tests/test_integration_etcd.py
python3 -m pytest tests/test_integration_zookeeper.py

# 全部测试
python3 -m pytest tests/

构建发布

pip3 install build twine
python3 -m build
python3 -m twine upload dist/*

测试通过版本

  • Python 3.6 ~ 3.12

发布历史

v0.1.5

  • Breaking: 改用 pyproject.toml 打包,移除 setup.py
  • Bug fix: acquire() 现在会正确设置 is_locked 属性。
  • Bug fix: ZooKeeper _do_acquire 捕获 LockTimeout 返回 False,而非抛异常。
  • Bug fix: 修复 Django demo settings.py 中示例 app 被错误放在 MIDDLEWARE 的问题。
  • Bug fix: 修复 ZK 测试类名、docstring 复制粘贴错误。
  • Feature: 添加 KazooClient 进程退出自动关闭机制(atexit)。
  • Feature: 添加 __all__、类型注解。
  • Feature: 添加 key 前缀在各后端的一致性策略 (normalize_key_prefix_for_path)。
  • Feature: 添加 scripts/start-test-services.sh 一键启动测试服务。
  • Test: 新增 74 个单元测试(mock 方式,无需外部服务)。
  • Test: 新增 29 个集成测试(Redis/etcd/ZK 真实后端)。
  • Test: pytest markers 自动按服务可用性跳过 (redis_required, etcd_required, zookeeper_required)。
  • Security: 移除本地配置文件中硬编码的凭据。
  • Chore: 清理开发临时文件(t1.py, t1zk.py, t2etcd.py, t3redis.py)。

v0.1.4

  • 文档更新。

v0.1.3

  • 修正 globallock.django 默认设置。

v0.1.2

  • GlobalLockManager.lock() 方法参数可以在初始化时设置默认值。
  • 添加 globallock.django.get_default_global_lock_manager() 方法,允许在 Django 中便捷使用。

v0.1.1

  • 文档更新。

v0.1.0

  • 首次发布。
  • 支持 RedisGlobalLock、DjangoRedisGlobalLock、EtcdGlobalLock、ZookeeperGlobalLock。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

globallock-0.1.5.tar.gz (21.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

globallock-0.1.5-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file globallock-0.1.5.tar.gz.

File metadata

  • Download URL: globallock-0.1.5.tar.gz
  • Upload date:
  • Size: 21.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for globallock-0.1.5.tar.gz
Algorithm Hash digest
SHA256 8ab79c5ccc7bf45310a4336b81039526d197e906efbabf8062bc48140c8d4cbc
MD5 14ec65158b38071e34f05c8ca0bdbe46
BLAKE2b-256 593b615fe7f8ac879f41e872ecc675dc6957e46a1493f22f0a75f7589e09079d

See more details on using hashes here.

File details

Details for the file globallock-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: globallock-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 12.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for globallock-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 2ceb5e04c45835701e1c3cade1172ee6b660283fa85109aeb4a1f6d6399d1d03
MD5 40c30d1369ef86995f7973ce17c4a830
BLAKE2b-256 283118e30d007318bc57ce2ccdd961955ae97f4b3367dbdd2c6a0ed7d5d5e538

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page