一个基于mysql构建的队列表
通常大家都会使用redis作为应用的任务队列表,redis的List结构,在一段进行任务的插入,在另一端进行任务的提取。
任务的插入
$redis->lPush("key:task:list",$task);
任务的提取
$tasks = $redis->RPop("key:task:list",0,-1);
可是大家想,如何使用mysql来实现一个队列表呢?
映入大家脑海的一个典型的模式是一个表包含多种类型的记录:未处理记录,已处理记录,正在处理记录等。一个或者多个消费者线程在表中查询未处理的记录,然后声称正在处理这个任务,处理完成之后,再讲记录更新为已处理状态。
这个典型的模式,存在两个问题;1:随着队列表越来越大,查找未处理记录的速度会越来越慢。2:频繁的加锁会让多个消费者线程增加竞争。
首先我们来创建一个表
create table unsent_emails{
id int not null primary key auto_increment,
status enum("unsent","claimed","sent"),
owner int unsigned not null default 0,
ts timestamp,
key (owner,status,ts)
};
该表的列owner用来存储当前正在处理这个记录的连接id,由函数 CONNECTION_ID()返回的连接id或者线程id。如果这个记录当前被没有被处理,则该值为0
我们在 owner status ts上面做了索引的处理,所以查找未处理的记录会很快。
通过我们会采用 select for update的方式来标记待处理的记录,方法如下
begin;
select id from unsent_emails
where owner = 0 and status = 'unsent'
limit 10 for update;
-- result 10,20,33
update unsent_emails
set status = 'claimed',owner = CONNECTION_ID()
where id in (10,20,33);
commit;
select的时候,使用了两个索引,应该会很快。问题出在select 和 update两个查询之间的间隙,这里的加锁会让其他相同的查询全部阻塞。
如果我们采用update then select的方式,那么效果就会更加高效,代码如下
set autocommit=1;
commit;
update unsent_emails
set statue = 'claimed',owner = CONNECTION_ID()
where owner = 0 and status = 'unsent'
limit 10;
set autocommit=0;
select id from unsent_emails
where owner = CONNECTION_ID() and status = 'claimed';
根本无需使用select去查找哪些记录还没有处理。客户端协议会告诉你更新了几条记录,就可以知道这次需要处理多少条记录。
这样是不是解决了上面的第二个问题,select for update的模式的加锁会增加多个消费队列的竞争问题。
其实所有的select for update 都可以替换为 update then select模式。
问题还没有结束,还有一种情况需要处理,就是比如正在处理任务的进程异常退出了,那么对应的进程正在处理的任务也就变为僵尸任务了。如何避免这种情况的发生呢?
所以我们还是需要一个新的定时器或者线程来定时检测并且update,将那些僵尸任务的记录更新到原始状态,就可以了。
僵尸任务的定义必须符合两点,1:任务被搁置了很久,比如十分钟,而通常一个任务只需要10秒就可以处理完;2:任务的owner(线程id或者连接id)已经不存在,只需要执行show processlist就可以获取当前正在工作的线程id了。代码如下
update unsent_emails
set owner = 0,status = 'unsent'
where owner not in (10,20,33,44) and status = 'claimed'
and ts < current_timestamp - interval 10 minute;
一个基于mysql构建的队列表就完成了。
当然,最好的办法就是将任务队列从数据库中迁移出来。redis真是一个很好的队列容器,当然也可以使用ssdb(基于leveldb,内存占用更少)。
读 高性能mysql 笔记
一个基于mysql构建的队列表的更多相关文章
- 一个基于Asterisk构建的VOIP应用软件:Elastix介绍
Elastix 是一种应用软件,它整合了适用于那些基于 Asterisk 的 PBX 的最好工具,并将它们集成为单一的.易用的接口.同时,它增加了自己的工具集,以及允许创建第三方模块来使 Elasti ...
- 如何设计一个基于mysql的消息系统
https://segmentfault.com/a/1190000012255186
- 基于MySQL协议的数据库中间层项目Atlas - 360团队
一.简介 Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了 ...
- 利用Dockerfile构建一个基于CentOS 7镜像
利用Dockerfile构建一个基于CentOS 7,包括java 8, tomcat 7,php ,mysql+mycat的镜像. Dockerfile内容如下: FROM centosMAINTA ...
- 开源低代码平台开发实践二:从 0 构建一个基于 ER 图的低代码后端
前后端分离了! 第一次知道这个事情的时候,内心是困惑的. 前端都出去搞 SPA,SEO 们同意吗? 后来,SSR 来了. 他说:"SEO 们同意了!" 任何人的反对,都没用了,时代 ...
- 使用 XMPP 构建一个基于 web 的通知工具——转
Inserting of file(使用 XMPP 构建一个基于 web 的通知工具.docx) failed. Please try again. http://www.ibm.com/develo ...
- 构建一个基于 Spring 的 RESTful Web Service
本文详细介绍了基于Spring创建一个“hello world” RESTful web service工程的步骤. 目标 构建一个service,接收如下HTTP GET请求: http://loc ...
- 一个基于php+mysql的外卖订餐网站(带源码)
订饭组 一个基于php+mysql的外卖订餐网站,包括前端和后台.源码地址 源码演示地址:http://dingfanzu.com 商家后台系统:http://dingfanzu.com/admin ...
- Spring MVC第一课:用IDEA构建一个基于Spring MVC, Hibernate, My SQL的Maven项目
作为一个Spring MVC新手最基本的功夫就是学会如何使用开发工具创建一个完整的Spring MVC项目,本文站在一个新手的角度讲述如何一步一步创建一个基于Spring MVC, Hibernate ...
随机推荐
- Js函数的概念、作用、创建、调用!
一.函数是用来帮助我们封装.调用代码的最方便的工具! 二.函数的创建方法有三种: 三.函数的创建方式有3种,调用方式也不是单一的,调用方式有4种! 1.作为一个函数去调用 函数名+();(函 ...
- ajax知识整理
HTTP服务 1.服务器 服务器类型 服务类型:文件服务器.数据库服务器.邮件服务器.Web服务器等: 操作系统:Linux服务器.Windows服务器等: 应用软件:Apache服务器.Nginx ...
- SQL Server最近怎样了
SQL Server最近怎样了 又到年终了,大家都作最后冲刺 最近园子里真的多了很多口水帖,无论大家争论得多么激烈,时间依然滴答滴答地过,争论完之后我们依然要继续埋头苦干 为年终奖.为明年做准备 这里 ...
- [译]MVC网站教程(一):多语言网站框架
本文简介 本博文介绍了 Visual Studio 工具生成的 ASP.NET MVC3 站点的基本框架:怎样实现网站的语言的国际化与本地化功能,从零开始实现用户身份认证机制,从零开始实现用户注册机制 ...
- Google分布式构建软件之三:分布式执行构建步骤
注:本文英文原文在google开发者工具组的博客上[需要FQ],以下是我的翻译,欢迎转载,但请尊重作者版权,注名原文地址. 之前两篇文章分别介绍了Google 分布式软件构建系统Blaze相关的为了提 ...
- 初试ASP.NET Web API/MVC API(附Demo)
写在前面 HTTP RESTful 创建Web API 调用Web API 运行截图及Demo下载 ASP.NET Web API是一个框架,可以很容易构建达成了广泛的HTTP服务客户端,包括浏览 ...
- 七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理
系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递 七天学会ASP.NET MVC (三)— ...
- ls /usr/linkapp 没反应
ls /usr/linkapp ll /usr/linkapp 都是一样无反应 没有任何反应, ctrl + c / ctrl + d 都不行 但是 ls /usr/linkapp/ | wc - ...
- avascript中的this与函数讲解
徐某某 一个半路出家的野生程序员 javascript中的this与函数讲解 前言 javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域.并且,大 ...
- 《深入浅出Nodejs》—— 读后总结
这一个月过去了三分之二,加上之前看过这本书三分之一,这才算是看完. 虽然看完一遍,但是这本书内容很深,以后肯定是还要继续翻阅的..... 什么是Nodejs Nodejs有几个特性:异步IO,事件驱动 ...