redis lua
需求是在缓存最近一周内用户所有消息列表,考虑用Redis 存储;为每个存储一个独立Sorted Set,value 为消息体,Score 为MessageId,用以实现增量消息同步。
问题就来了:Sorted Set 怎么清理?
-设计内存容量只允许放一周内最新的,太久了缓存意义不大,太浪费。
-再者存在百万级/s群发请求,不允许写入时触发清理。
理想模型:如果使用磁盘则使用MyIsam堆表,数据按照顺序写入,再建立以uid为索引,删除却是完全顺序的。内存里面的话Hash 表 + RB 树两个维度索引,RB树可按照时间顺序清理。
解决方案:
- 写入第一条时,设置一周过期时间
判断是否第一条:zadd key 0 0 value score 返回2 说明第一条,1 不是第一条,只是多一条0的数据
- 用户每天第一次登陆,触发一次清理
清理需要遍历Sorted Set上,消息一般不小,浪费io流量了,所以考虑采用lua 脚本实现。
- 这样保证,通过pipeline只是高并发写入,同时保证活跃用户一周内消息都在内存(不活跃不保证),清理简单
清理脚本如下:
local ltime =
local dels =
local lefts =
local list = redis.call("ZRANGE", KEYS[], , -)
if(list[] == nil) then
return {-, }
end
for _,v in ipairs(list) do
if lefts == then
ltime = struct.unpack('<i', v)
if ltime < tonumber(KEYS[]) then
dels = dels +
else
lefts = lefts +
end
else
lefts = lefts +
end
end
if lefts > tonumber(KEYS[]) then
dels = dels + (lefts - tonumber(KEYS[]))
lefts = tonumber(KEYS[])
end
if lefts == then
ltime =
redis.call("DEL", KEYS[])
elseif dels > then
redis.call("ZREMRANGEBYRANK", KEYS[], , dels)
end
return {dels, ltime}
写入的消息前4byte 为little-endian 的UnixTime,Redis lua 支持struct,很简单解析出(当然也支持cjson,但速度要差一些).
清理过期数据,并返回最后一条写入的时间,应用根据返回时间适当延长过期时间。
这里因为考虑每个人消息一般不会太多,所以全部遍历,多的话可考虑分部分遍历,如10条10条来,最新的就不会被不必要的取出来了,怎么说遍历大Set还是较慢的。
clear_msgs(Uid, MaxLen, ExpireSec) ->
ToExpires = utime() - ExpireSec,
{ok, [Dels, LTime]} =
eredis:q(pooler(Uid), [<<"EVAL">>, clear_script(), <<"3">>,
?KEY_LIST(Uid), MaxLen, ToExpires]),
{ok, binary_to_integer(Dels), binary_to_integer(LTime)}.
性能:此段脚本在我机器上速度2.5w/s(列表长度10), 相比get 7w/s。速度很快,也节省网络流量。
script load
此段脚本有700多字节,每次执行会带来不少网络流量;但对性能影响较小,内部对于eval 会先sha1 脚本,从缓存获取生成好的lua 方法执行。
当然最好使用script load,节省脚本传输、脚本的sha1计算,就行存储过程一样执行。
luajit:
github讨论过 ,redis lua,相比nginx_lua 更像数据库存储过程,提供事务性的多个相关性操作,是否使用jit区别不大;
支持的库也很有限base、table、string、math、debug、cjson、struct、cmsgpack,能够做的事情不多,也尽量别把太多逻辑用lua写。
redis.log 方法:
调试大段的lua脚本,这个方法还是挺管用的。
相关参考:
官方说明:http://oldblog.antirez.com/post/scripting-branch-released.html
源码分析:http://blog.nosqlfan.com/html/4099.html
redis lua的更多相关文章
- 像调试java一样来调试Redis lua
高并发的系统中,redis的使用是非常频繁的,而lua脚本则更是锦上添花.因为lua脚本本身执行的时候是一个事务性的操作,不会掺杂其他外部的命令,所以很多关键的系统节点都会用redis+lua来实现一 ...
- Redis Lua脚本调试
从版本3.2开始,Redis包含一个完整的Lua调试器,可以用来使编写复杂Redis脚本的任务更加简单. 由于Redis 3.2仍处于测试阶段,请unstable从Github 下载Redis 的分支 ...
- 限流(三)Redis + lua分布式限流
一.简介 1)分布式限流 如果是单实例项目,我们使用Guava这样的轻便又高性能的堆缓存来处理限流.但是当项目发展为多实例了以后呢?这时候我们就需要采用分布式限流的方式,分布式限流可以以redis + ...
- 【连载】redis库存操作,分布式锁的四种实现方式[四]--基于Redis lua脚本机制实现分布式锁
一.redis lua介绍 Redis 提供了非常丰富的指令集,但是用户依然不满足,希望可以自定义扩充若干指令来完成一些特定领域的问题.Redis 为这样的用户场景提供了 lua 脚本支持,用户可以向 ...
- Redis进阶应用:Redis+Lua脚本实现复合操作
一.引言 Redis是高性能的key-value数据库,在很大程度克服了memcached这类key/value存储的不足,在部分场景下,是对关系数据库的良好补充.得益于超高性能和丰富的数据结构,Re ...
- spring boot:redis+lua实现顺序自增的唯一id发号器(spring boot 2.3.1)
一,为什么需要生成唯一id(发号器)? 1,在分布式和微服务系统中, 生成唯一id相对困难, 常用的方式: uuid不具备可读性,作为主键存储时性能也不够好, mysql的主键,在分库时使用不够方便, ...
- spring boot:redis+lua实现生产环境中可用的秒杀功能(spring boot 2.2.0)
一,秒杀需要具备的功能: 秒杀通常是电商中用到的吸引流量的促销活动方式 搭建秒杀系统,需要具备以下几点: 1,限制每个用户购买的商品数量,(秒杀价格为吸引流量一般会订的很低,不能让一个用户全部抢购到手 ...
- Redis Lua脚本完全入门
1. 前言 Redis是高性能的KV内存数据库,除了做缓存中间件的基本作用外还有很多用途,比如胖哥以前分享的Redis GEO地理位置信息计算.Redis提供了丰富的命令来供我们使用以实现一些计算.R ...
- Redis+LUA整合使用
.前言 从本章节开始我们就开始讲解一些 Redis 的扩展应用了,之前讲的主从.哨兵和集群都相当重要,也许小公司用不到集群这么复杂的架构,但是也要了解各知识点的原理,只要了解了原理,无论什么时候是有, ...
随机推荐
- jsp的九大内置对象
九大内置对象 jsp servlet 对象名 类型 使用范围 request HttpServletRequest 请求 浏览器--->服务器 response HttpServletRes ...
- selector 使用说明
android:state_pressed=["true" | "false"]//是否触摸 android:state_focused=["true ...
- iOS App上架流程(2016详细版)
iOS App上架流程(2016详细版) 原文地址:http://www.jianshu.com/p/b1b77d804254 感谢大神整理的这么详细 一.前言: 作为一名iOSer,把开发出来的Ap ...
- 关于FloatingActionButton
由于FloatingActionButton本质上是ImageView,跟ImageView相关的就不介绍,这里重点介绍新加的几个属性. app:fabSize:FloatingActionButto ...
- win10使用技巧之如何打出偏僻字母
一.背景 有时需要在打出一些希腊字母,诸如ɛ.μ等字符,如果输入法不支持该怎么办呢?在很多国产拼音软件中,都会提供扩展方便用户寻找这类字符,但是如果用户换过一款软件,可能要在一定时间找到这些字符就没那 ...
- JS:window.onload的使用
1.最简单的调用方式 直接写到html的body标签里面,如: (html) (body onload="func()") (/body) (/html) 2.在JS语句调用 (s ...
- cocoapods安装
什么是cocoapods CocoaPods是一个用来帮助我们管理第三方依赖库的工具.它可以解决库与库之间的依赖关系,下载库的源代码,同时通过创建一个Xcode的workspace来将这些第三方库和我 ...
- Javascript字节转换
//文件大小转换 function bytesToSize(bytes) { if (bytes === 0) return '0 B'; var k = 1024; sizes = ['B', 'K ...
- Python报错UnicodeDecodeError: ascii codec can t decode byte 0xe0 ...解决方法
用命令(python setup.py install)安装webpy时候总是报错 在网上搜索到的解决方法如下: 1. 这是Python 2 mimetypes的bug 2. 需要将Python2.7 ...
- django进阶
路由系统 简而言之,django的路由系统作用就是使views里面处理数据的函数与请求的url建立映射关系.使请求到来之后,根据urls.py里的关系条目,去查找到与请求对应的处理方法,从而返回给客户 ...