Python Redis pipeline操作(秒杀实现)
设想这样的一个场景,你要批量的执行一系列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)

Python Redis pipeline操作(秒杀实现)的更多相关文章
- Python Redis pipeline操作
Redis是建立在TCP协议基础上的CS架构,客户端client对redis server采取请求响应的方式交互. 一般来说客户端从提交请求到得到服务器相应,需要传送两个tcp报文. 设想这样的一个场 ...
- Python Redis pipeline操作和Redis乐观锁保持数据一致性
Redis是建立在TCP协议基础上的CS架构,客户端client对redis server采取请求响应的方式交互. redis 乐观锁:也可理解为版本号比较机制,主要是说在读取数据逇时候同时读取其版本 ...
- Python --Redis Hash操作
一.Redis Hash操作 Redis 数据库hash数据类型是一个string类型的key和value的映射表,适用于存储对象.Redis 中每个 hash 可以存储 232 - 1 键值对(40 ...
- Python Redis常用操作(持续更新)
目录 1.Redis简介 2.Redis部署 3.Redis API应用 4.String操作 1.Redis简介 redis是业界主流的key-value,nosql数据库之一.和Memcached ...
- python:redis简单操作
一,安装redis-py pip install redis easy_install redis 二,简单用法 import redis # 连接redis服务器 def conn_redis(): ...
- python redis list操作
LPUSH list_name value [value ...] Prepend one or multiple values to a list 从左侧插入值,最早插入的值在最右边 LPUSHX ...
- Python Redis 常用操作
delete(*names) # 根据删除redis中的任意数据类型 exists(name) # 检测redis的name是否存在 keys(pattern='*') # 根据模型获取redis的n ...
- python连接redis、redis字符串操作、hash操作、列表操作、其他通用操作、管道、django中使用redis
今日内容概要 python连接redis redis字符串操作 redis之hash操作 redis之列表操作 redis其他 通用操作,管道 django中使用redis 内容详细 1.python ...
- java、python及jmeter操作redis(接口自动化必备)
redis是nosql数据库之一,其存储结构简单,提供高性能服务,所以在架构中是很常用的. 在做接口自动化测试过程中,有时也会涉及到redis,比如:发送短信验证码,我们做接口自动化测试,如何模拟发送 ...
随机推荐
- 61. Search for a Range【medium】
61. Search for a Range[medium] Given a sorted array of n integers, find the starting and ending posi ...
- BootstrapValidator 解决多属性被同时校验问题《转》
问题描述:在使用bootstrapValidator插件校验表单属性,当表单属性过多需要每行并列多个属性 ,会出现校验第一个属性,发现整行被校验的效果 ,这不是我们工作想要的效果.如图: 问题分析:因 ...
- 利用ascx输出knockoutjs的模板
项目里面的UI模板在一个页面中有2K多行了.需要增加新的UI样式.问题来了.加上js代码,几乎是变成了不可维护的状态.增加和修改都需要用ctrl+f的方式找到对应的模板,然后进行处理.很容易出错.突然 ...
- K - Large Division 判断a是否是b的倍数。 a (-10^200 ≤ a ≤ 10^200) and b (|b| > 0, b fits into a 32 bit signed integer). 思路:取余;
/** 题目:K - Large Division 链接:https://vjudge.net/contest/154246#problem/K 题意:判断a是否是b的倍数. a (-10^200 ≤ ...
- Android Studio--NDK编译C代码为.so文件,JNI调用
前言: 从Android Studio开始,就支持jni和.so库调用了. 环境: Windows 7+Android Studio2.1.2+NDK版本:android-ndk-r10e 准备工作: ...
- dm8148 开发之---4路解码器tvp5158
通过采用自动对比度控制与视频噪声过滤技术的全新 TVP515x 器件,采集4通道视频,可带来优异图像质量并实现市场领先的视频解码性能德州仪器 (TI) 宣布推出可实现优异图像质量的新型 TVP5158 ...
- 我买网B轮融资成功,五周年豪掷千万回馈会员
对中粮我买网而言,近期的B轮融资应该算是最大的好消息了------8月1日,中粮我买网在京宣布完毕B轮融资.金额高达1亿美元.被称为"食品电商史上最大融资".据悉,本次融资 ...
- 利用微信小程序实现web监控界面
1.实现思路 利用小程序去调用公司zabbix的接口获取网站监控数据并展示出来. 2.准备阶段 1.小程序公众号 2.企业号 3.zabbix接口 3.实现过程
- sql server case when then
http://blog.csdn.net/wuxiaokaixinguo/article/details/8895187
- ASP.NET动态网站制作(30)-- WEBService
前言:继续讲正则表达式,然后介绍一下webservice. 内容: 1.匹配QQ号的正则表达式:^[1-9]\d{4,10}$:匹配手机号的正则表达式:^(0|86)?(13|14|15|18)[0- ...