分布式锁

工作中遇到困难,数据可视化时,我需要12月的数据,数据会去获取12次,临时将数据存到缓存,以让接下来的请求直接从缓存获取数据。
但是当来了10个请求,10个请求有可能都会去获取1月份的数据,这时 对于数据库来说,有些请求就浪费了。


这使我想到了分布式锁,对每个月的数据标识,进行加锁

 

原理

 

Redis 的分布式锁服务

这里提一下,避免死锁的问题。下面以 Redis 的锁服务为例(参考 Redis 的官方文档

SET resource_name my_random_value NX PX 30000

SET NX 则设置
1、Clinet A

 

如果此时B,C需要同时去写数据库,那就出现问题了
解决方法:
  乐观锁,过滤条件是锁对应的value 比方说: xxxxx_version: 5
  每次写数据库时同时更新数据库version版本


# 如果是这样,那还要分布式锁干嘛,直接乐观锁不就好了嘛。
UPDATE table_name SET xxx = #{xxx}, version=version+1 where version =#{version};
关键是业务无法使用乐观锁


如果使用 CAS 这样的方式(无锁方式)来更新数据,那么我们是不需要使用分布式锁服务的,而后者可能是需要的。

 

需要分清楚:我们使用来修改某个共享数据的还是用来不同进程间的同步或是互斥的。
前者是不需要使用分布式锁的。

在释放锁时,要检查自己拿到的锁,和现在锁是不是还是一把

 

PYTHON

 

import redis
conn = redis.Redis(host="127.0.0.1", port=6379)
print(conn.set("cunchu", "x123213x", ex=100, nx=True))
设置成功,返回True, 否则返回None

"""
Set the value at key ``name`` to ``value``
``ex`` sets an expire flag on key ``name`` for ``ex`` seconds.
``px`` sets an expire flag on key ``name`` for ``px`` milliseconds.
``nx`` if set to True, set the value at key ``name`` to ``value`` only
    if it does not exist.
``xx`` if set to True, set the value at key ``name`` to ``value`` only
    if it already exists.
"""

 

from redlock import RedLockFactory
factory = RedLockFactory(
    connection_details=[
        {'host': 'xxx.xxx.xxx.xxx'},
        {'host': 'xxx.xxx.xxx.xxx'},
        {'host': 'xxx.xxx.xxx.xxx'},
        {'host': 'xxx.xxx.xxx.xxx'},
    ])

with factory.create_lock("distributed_lock"):
    do_something()

with factory.create_lock("another_lock"):
    do_something()
from redlock import RedLock, lock
import time
import random
import redis

conn = redis.Redis(host="127.0.0.1", port=6379)

a = {
    '2019-05': 1,
    '2019-01': 1,
    '2019-02': 1,
    '2019-03': 1,
    '2019-06': 1,
    '2019-04': 1,
    '2019-07': 1,
}

# # 、随便哪一个,  锁,出错换一个,成功从中pop元素
while a:
    key = list(a.keys())
    random.shuffle(key)
    a2 = key[0]
    try:
        with RedLock(a2 + '_lock'):
            cunchu = a2 + 'xxxxxxxxxxxxxx'
            res = conn.get(cunchu)
            if res:
                print(a2, '来自缓存', res)
            else:
                xx = str(time.time())
                print(a2, '设置', xx)
                conn.set(cunchu, xx, ex=100)
            a.pop(a2)
    except lock.RedLockError as e:
        print(a2, '已锁')
View Code

 

posted @ 2020-06-05 20:51  慕沁  阅读(197)  评论(0)    收藏  举报