Distributed lock manager, support many types of backend, e.g. redis, django-redis, etcd, zookeeper...
Project description
globallock
统一接口的分布式锁管理器,支持 Redis、Django-Redis、etcd、ZooKeeper 四种后端。
名称
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_CLASS、DJANGO_REDIS_GLOBAL_LOCK_CLASS、ETCD_GLOBAL_LOCK_CLASS、ZOOKEEPER_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 |
timeout、sleep、blocking、blocking_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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ab79c5ccc7bf45310a4336b81039526d197e906efbabf8062bc48140c8d4cbc
|
|
| MD5 |
14ec65158b38071e34f05c8ca0bdbe46
|
|
| BLAKE2b-256 |
593b615fe7f8ac879f41e872ecc675dc6957e46a1493f22f0a75f7589e09079d
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ceb5e04c45835701e1c3cade1172ee6b660283fa85109aeb4a1f6d6399d1d03
|
|
| MD5 |
40c30d1369ef86995f7973ce17c4a830
|
|
| BLAKE2b-256 |
283118e30d007318bc57ce2ccdd961955ae97f4b3367dbdd2c6a0ed7d5d5e538
|