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 的扩展应用了,之前讲的主从.哨兵和集群都相当重要,也许小公司用不到集群这么复杂的架构,但是也要了解各知识点的原理,只要了解了原理,无论什么时候是有, ...
随机推荐
- Codeforces Round #383(div 2)
A.快速幂 B. 题意:求ai^aj=x的数对个数,x和a[]给定 分析:a^b=c,则a^c=b,所以求ai^x=aj的个数,枚举一遍即可 C. 题意:给你一个有向图,每个点的出边只有一条,求最小的 ...
- 【BZOJ 1016】【JSOI 2008】最小生成树计数
http://www.lydsy.com/JudgeOnline/problem.php?id=1016 统计每一个边权在最小生成树中使用的次数,这个次数在任何一个最小生成树中都是固定的(归纳证明). ...
- Oracle11g字符集AL32UTF8修改为ZHS16GBK详解
此问题发生在数据库迁移过程中.源数据库:自己笔记本上win7 64位系统的oracle11g个人版,字符集ZHS16GBK :目标数据库,HP的sqlserver2008 系统 64位数据库服务器,字 ...
- 进度条投票-W
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 特性 Attribute
特性就是一个类,必须是Attribute的子类 一般以Attribute结尾,然后在使用的时候,可以去掉这个结尾 可以在特性中声明字段.属性.方法.构造函数.委托.事件... [AttributeUs ...
- qrcode 生成验证码带文字
/** * 生成二维码 * * @param int $id * @param string $file * @param boolean $is_download */public function ...
- linux显示中文
设置centos显示中文 怎么设置Linux系统中文语言,这是很多小伙伴在开始使用Linux的时候,都会遇到一个问题,就是终端输入命令回显的时候中文显示乱码.出现这个情况一般是由于没有安装中文语言 ...
- ThinkPHP框架下的表单验证
之前的表单验证都是用js写的,这里也可以使用tp框架的验证.但是两者比较而言还是js验证比较好,因为tp框架验证会运行后台代码,这样运行速度和效率就会下降. 自动验证是ThinkPHP模型层提供的一种 ...
- JVM内存垃圾回收方法
1.概述 1.1.为什么要回收? 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断地分配内存空间而不进行回收.除非内存无限大,我们可以任性地分配而不回收,但是事实并非如此.所以,垃圾回收是必须 ...
- node-glob学习
node的glob模块允许你使用 *等符号, 来写一个glob规则,像在shell里一样,获取匹配对应规则的文件. 这个glob工具基于javascript.它使用了 minimatch 库来进行匹配 ...