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 的扩展应用了,之前讲的主从.哨兵和集群都相当重要,也许小公司用不到集群这么复杂的架构,但是也要了解各知识点的原理,只要了解了原理,无论什么时候是有, ...
随机推荐
- CocoaPods 的简单快速安装方法
CocoaPods 的简单快速安装方法(Setting up CocoaPods master repo 卡着不动,是因为淘宝镜像已经不能用了. 一.git clone方法安装cocoapods 镜像 ...
- Jmeter学习笔记ONE
最近想学一些关于性能测试方面的知识,其实之前已经初步了解了Jmeter工具,它是一个轻量级的性能测试工具,开源并且免费,相比于Loadrunner来说用起来更简便. JMeter 可以用于对服务器.网 ...
- IE下get传中文乱码的问题 -- 解决方案 (js)
W3school 函数 JavaScript 全局对象 定义和用法 encodeURI() 函数可把字符串作为 URI 进行编码. 语法 encodeURI(URIstring) 参数 描述 URIs ...
- MYSQL批量修改表前缀与表名sql语句
修改表名 ALTER TABLE 原表名 RENAME TO 新表名; 一句SQL语句只能修改一张表 show tables; 1. SELECT CONCAT( 'ALTER TABLE ', ta ...
- 2016总结&2017计划
2016总结 总体而言,上半年比较勤快,下半年偷懒了.下半年仔细看了Barfoot的书<state estimation for robotics>,收获很大. 2017计划 目前打算写以 ...
- 文件共享锁定数溢出-IWorkspaceEdit.StopEditing
在批量保存Feature至本地mdb的时候,当Feature的数量超过一定的值(该值不确定是不是Access文件的MaxLocksPerFile值,因为当MaxLocksPerFile为9500时,F ...
- form表单提交时,action怎么带参数
<html> <title>form</title> <script type="text/javascript"> functio ...
- JavaScript备忘录
提取字符串substring(start,end)substr(start [, length ])JavaScript substr() 方法 --
- 网站引入了css样式文件能访问,就是没有效果
今天后端的同事遇到这么个问题,引入了外部css文件也能访问,就是页面上没有效果. 大概是下面这个样子: css引入如下: 我非常的纳闷,说真的我还没遇到过这种情况,UI是可以运行的,一点事都没有... ...
- php-7.1.0 rpm包制作
nginx-1.8.0 rpm包制作见上篇文章:http://www.cnblogs.com/xiaoming279/p/6251149.html spec文件 Name: php Version: ...