Redis是建立在TCP协议基础上的CS架构,客户端client对redis server采取请求响应的方式交互。

redis 乐观锁:也可理解为版本号比较机制,主要是说在读取数据逇时候同时读取其版本号,然后在写入的时候,进行版本号比较,如果一致,则表明此数据在监听期间未被改变,可以写入,如果不一致说明此数据被修改过,不能写入,否则会导致数据不一致的问题。

一般来说客户端从提交请求到得到服务器相应,需要传送两个tcp报文。

设想这样的一个场景,你要批量的执行一系列redis命令,例如执行100次get key,这时你要向redis请求100次+获取响应100次。如果能一次性将100个请求提交给redis server,执行完成之后批量的获取相应,只需要向redis请求1次,然后批量执行完命令,一次性结果,性能是不是会好很多呢?

答案是肯定的,节约的时间是客户端client和服务器redis server之间往返网络延迟的时间。这个时间可以用ping命令查看。

网络延迟高:批量执行,性能提升明显

网络延迟低(本机):批量执行,性能提升不明显

某些客户端(java和python)提供了一种叫做pipeline的编程模式用来解决批量提交请求的方式。

这里我们用python客户端来举例说明一下。

1、pipeline

网络延迟

client与server机器之间网络延迟如下,大约是30ms。

测试用例

分别执行其中的try_pipeline和without_pipeline统计处理时间。

# -*- coding:utf-8 -*-

import redis
import time
from concurrent.futures import ProcessPoolExecutor r = redis.Redis(host='10.93.84.53', port=6379, password='bigdata123') def try_pipeline():
start = time.time()
with r.pipeline(transaction=False) as p:
p.sadd('seta', 1).sadd('seta', 2).srem('seta', 2).lpush('lista', 1).lrange('lista', 0, -1)
p.execute()
print time.time() - start def without_pipeline():
start = time.time()
r.sadd('seta', 1)
r.sadd('seta', 2)
r.srem('seta', 2)
r.lpush('lista', 1)
r.lrange('lista', 0, -1)
print time.time() - start def worker():
while True:
try_pipeline() with ProcessPoolExecutor(max_workers=12) as pool:
for _ in range(10):
pool.submit(worker)

结果分析

try_pipeline平均处理时间:0.04659

without_pipeline平均处理时间:0.16672

我们的批量里有5个操作,在处理时间维度上性能提升了4倍!

网络延迟大约是30ms,不使用批量的情况下,网络上的时间损耗就有0.15s(30ms*5)以上。而pipeline批量操作只进行一次网络往返,所以延迟只有0.03s。可以看到节省的时间基本都是网路延迟。

2、pipeline与transation(事务)

pipeline不仅仅用来批量的提交命令,还用来实现事务transation。

这里对redis事务的讨论不会太多,只是给出一个demo。详细的描述你可以参见这篇博客。redis事务

细心的你可能发现了,使用transaction与否不同之处在与创建pipeline实例的时候,transaction是否打开,默认是打开的。

# -*- coding:utf-8 -*-

import redis
from redis import WatchError
from concurrent.futures import ProcessPoolExecutor r = redis.Redis(host='127.0.0.1', port=6379) # 减库存函数, 循环直到减库存完成
# 库存充足, 减库存成功, 返回True
# 库存不足, 减库存失败, 返回False
def decr_stock(): # python中redis事务是通过pipeline的封装实现的
with r.pipeline() as pipe:
while True:
try:
# watch库存键, multi后如果该key被其他客户端改变, 事务操作会抛出WatchError异常
pipe.watch('stock:count')
count = int(pipe.get('stock:count'))
if count > 0: # 有库存
# 事务开始
pipe.multi() # 这里起始位置???????????????
pipe.decr('stock:count')
# 把命令推送过去
# execute返回命令执行结果列表, 这里只有一个decr返回当前值
print pipe.execute()[0]
return True
else:
return False
except WatchError, ex:
# 打印WatchError异常, 观察被watch锁住的情况
print ex
pipe.unwatch() def worker():
while True:
# 没有库存就退出
if not decr_stock():
break # 实验开始
# 设置库存为100
r.set("stock:count", 100) # 多进程模拟多个客户端提交
with ProcessPoolExecutor(max_workers=2) as pool:
for _ in range(10):
pool.submit(worker)

出处:https://www.cnblogs.com/kangoroo/p/7647052.html

Python Redis pipeline操作和Redis乐观锁保持数据一致性的更多相关文章

  1. redis的高级事务CAS(乐观锁)

    Optimistic locking using check-and-set(乐观锁) 乐观锁介绍:watch指令在redis事物中提供了CAS的行为.为了检测被watch的keys在是否有多个cli ...

  2. Redis中的事务及乐观锁的实现

    介绍 Redis中的事务(transaction)是一组命令的集合.     事务同命令一样都是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行.     Redis事务的实现需要用 ...

  3. Redis 事物、悲观、乐观锁 (详细)

    1,概论 事物这东西相信大家都不陌生吧,在学习Spring,Mybatis等框架中, 只要是涉及到数据存储和修改的,都会有事物的存在, 废话就不多说了下面我们来简单的介绍下Redis事物以及锁. 2, ...

  4. Python Redis pipeline操作

    Redis是建立在TCP协议基础上的CS架构,客户端client对redis server采取请求响应的方式交互. 一般来说客户端从提交请求到得到服务器相应,需要传送两个tcp报文. 设想这样的一个场 ...

  5. Python Redis pipeline操作(秒杀实现)

    设想这样的一个场景,你要批量的执行一系列redis命令,例如执行100次get key,这时你要向redis请求100次+获取响应100次.如果能一次性将100个请求提交给redis server,执 ...

  6. ServiceStack.Redis常用操作 - 事务、并发锁_转

    一.事务 使用IRedisClient执行事务示例: using (IRedisClient RClient = prcm.GetClient()) { RClient.Add("key&q ...

  7. ServiceStack.Redis常用操作 - 事务、并发锁

    一.事务 使用IRedisClient执行事务示例: using (IRedisClient RClient = prcm.GetClient()) { RClient.Add("key&q ...

  8. 文成小盆友python-num11-(2) python操作Memcache Redis

    本部分主要内容: python操作memcache python操作redis 一.python 操作 memcache memcache是一套分布式的高速缓存系统,由LiveJournal的Brad ...

  9. python通过连接池连接redis,操作redis队列

    在每次使用redis都进行连接的话会拉低redis的效率,都知道redis是基于内存的数据库,效率贼高,所以每次进行连接比真正使用消耗的资源和时间还多.所以为了节省资源,减少多次连接损耗,连接池的作用 ...

随机推荐

  1. ios中tableview侧栏的折叠

    #import "ViewController.h" #define Ksmall 40.0f #define Klarge 80.0f #define KNoOpen @&quo ...

  2. 如何找到Firefox的收藏夹,就像IE一样,出现在网页的侧面

    firefox有这个插件,安装后就可以 http://addons.mozine.cn/firefox/19/   All-In-OneSidebar ? 概述   All-In-OneSidebar ...

  3. 路由器下CLI界面

    CLI(command-line interface,命令行界面)是指可在用户提示符下键入可执行指令的界面. CLI是Command Line Interface的缩写,即命令行界面.CLI界面是所有 ...

  4. fedora下安装运行keil uVision 4 (MDK v4.7)

    先准备好mdk4.73.exe和和谐文件. 1.安装 wine 1.7 添加ppa sudo add-apt-repository ppa:ubuntu-wine/ppa      安装wine 1. ...

  5. Git 查看提交历史(分布式版本控制系统)

    1.查看提交历史 在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史.完成这个任务最简单而又有效的工具是 git log 命令. $ git log commit ca82a6dff8 ...

  6. 转如何用九条命令在一分钟内检查Linux服务器性能?

    一.uptime命令 $ uptime :: up :,   user,  load average: 30.02, 26.43, 19.02 这个命令可以快速查看机器的负载情况.在Linux系统中, ...

  7. Intent----android中的伟大邮差

    在android中,intent就像是一个邮差,辛勤高效的在各个组件之间来回穿梭.我们可以通过它启动一个Activity或者Service,或者是发送给广播组件,又或者是与后台的Service进行通信 ...

  8. Java与C++Socket通讯注意事项

    c++与java进行socket通信时注意事项 原文链接: http://my.oschina.net/ypimgt/blog/106439 因为java发送的都是网络字节序(big-endium), ...

  9. Debian本地镜像长时间不更新

    一.执行apt-get update 使用一个长期未更新的本地源,得到错误的提示: Release file for ... is expired. Updates for this reposito ...

  10. 基于Android平台的会议室管理系统具体设计说明书

    会议室管理系统具体设计说明书 第一部分  引言 1.编写目的 本说明对会议室管理系统项目的各模块.页面.脚本分别进行了实现层面上的要求和说明. 软件开发小组的产品实现成员应该阅读和參考本说明进行代码的 ...