• 使用SquirrelMQ打造一个千万级数据更新量的应用


    原文:http://blog.sina.com.cn/s/blog_7530db6f0100uo4c.html


        我们知道微博的访问量是非常大的,一秒钟可能有成千上万的人发布微博或者删除微博,所以数据库要承受的压力非常大,这样就可能导致数据库并发量太大而操作失败。


        那么,我们考虑一下,可不可以把所有的插入操作一步一步的完成呢?也就是说等到第一个插入操作完成再做第二个插入操作呢?要实现这种情况,我们可以使用消息队列。消息队列的作用就是把大量并发操作变成线性操作。那么我们怎么使用消息队列来完成呢?如下图:

     

    从图上可以看出,我们把所有的数据库操作都发送到消息队列中,然后让消息队列来进行对数据库的操作。因为消息队列是一条一条消息进行的,所以并不会对数据库造成高并发的操作。


    一,SquirrelMQ使用

    下面,我们介绍使用SquirrelMQ消息队列来完成上面所说的应用吧。

    1)  安装Lua。

    2)  首先下载编译SquirrelMQ:

    #> wget http://squirrel-message-queue.googlecode.com/files/squirrel-with-lua-v1.2.zip

    #> tar –zxvf squirrel-with-lua-v1.2.zip

    #> cd squirrel-with-lua-v1.2

    #> make


    2) 修改SquirrelMQ配置(squirrel.conf文件):

    # 侦听端口

    listingPort 6061


    # 最大可以使用内存数(单位:字节)

    memoryLimitUsed 524288000


    # 多长时间进行存储数据到硬盘(防止down机时数据丢失,单位为秒)

    secondsToSaveDisk 30


    # 多少次数据变化才进行存储数据到硬盘(防止写数据过于频繁)

    chagesToSaveDisk 30


    # 客户端连接多长时间不操作自动关闭(单位为秒)

    clientExpiredTime 60


    # 多长时间运行一次cron(单位为毫秒)

    cronLoops 5000


    # 是否开启Lua处理线程

    enableLuaThread 1


    # 是否使用守护进程模式运行

    daemonize 0


    我们根据自己的需求来修改配置,特别说明一下的是,当开启Lua处理线程时,我们可以编写Lua脚本来处理队列(在cron/main.lua)。这样就可以让服务器本身来处理消息队列的数据,而不用另外写一个cron程序来处理。下面我们会介绍。


    3) 运行SquirrelMQ:

    #> ./squirrel –c squirrel.conf


    二,使用客户端API

    SquirrelMQ提供一个PHP访问的API,在php/squirrel.class.php。我们可以使用这个API文件轻松地访问SquirrelMQ。

    这个API文件把所有访问SquirrelMQ的操作封装成一个类,叫Squirrel,在使用时直接new一个Squirrel的对象即可,如下:


    <?php

    include("squirrel.class.php");

    $smq = new Squirrel('127.0.0.1', 6061);

    $smq->push_tail("INSERT INTO mytable(uid, username, password)VALUES(NULL, 'liexusong', '123456');");

    ?>

    这样,我们就可以把一条消息插入到消息队列了。我们可以使用size()方法来获取SquirrelMQ的消息条数:


    <?php

    include("squirrel.class.php");

    $smq = new Squirrel('127.0.0.1', 6061);

    $size = $smq->size();

    echo "The SquirrelMQ size: $size";

    ?>


    SquirrelMQ支持的API有:

    1)插入到队列的头部:

    $smq->push_head($message);


    2)插入到队列的尾部:

    $smq->push_tail($message);


    3)取得队列的第一条消息,并从队列中删除:

    $message = $smq->pop_head();


    4)取得队列的最后一条消息,并从队列中删除:

    $message = $smq->pop_tail();


    5)取得队列的第n条消息,并且从队列中删除:

    $message = $smq->pop_index($index);


    6)取得队列的第一条消息,但不从队列中删除:

    $message = $smq->get_head();


    7)取得队列的最后一条消息,但不从队列中删除:

    $message = $smq->get_tail();


    8)取得队列的第n条消息,但不从队列中删除:

    $message = $smq->get_index($index);


    9)取得队列的大小:

    $size = $smq->size();


    10)取得队列的状态:

    $stat = $smq->stat();


    三,使用Lua处理队列

    SquirrelMQ的一个令人兴奋的特性就是支持使用Lua处理队列中的消息,下面我们来介绍一下这个功能。

    要 开启Lua处理线程,需要在配置文件中把enableLuaThread设置为1。这样SquirrelMQ就会开启Lua处理线程。我们可以在 cron/main.lua文件中编写我们的Lua代码来处理队列中的消息。在cron/main.lua文件中,必须编写一个__main__的函 数,SquirrelMQ就是以这个函数作为入口,如:


    function __main__()

    ......

    end




    在__main__函数中,我们可以使用一些SquirrelMQ提供的API函数取得队列中的消息,如smq_pop_head()和smq_pop_tail()等。__main__函数可以这样写:


    require "luasql.mysql"


    function __main__()

        env = luasql.mysql()

        con = env:connect("database", "username", "password", "127.0.0.1", 3306)


        while true do

           local ok, sql = smq_pop_head()

           if ok then

               res = con:execute(sql)

           end

        end


        con:close()

        env:close()

    end


    记住,SquirrelMQ提供的API都是阻塞的,也就是说,当队列为空时,API会阻塞知道队列有消息可以获取为止,这样做的目的是为了尽量减少Lua线程的运行时间。

    在上面例子中,我们使用smq_pop_head()来取得队列的第一条消息,然后执行此消息(con:execute(sql))。


    SquirrelMQ提供给Lua线程使用的API有:

    *         ok, item = smq_pop_head()

    *         ok, item = smq_pop_tail()

    *         ok, item = smq_pop_index()

    *         ok, item = smq_get_head()

    *         ok, item = smq_get_tail()

    *         ok, item = smq_get_index()

    *         size = smq_queue_size()

    *         ok = smq_push_head(item)

    *         ok = smq_push_tail(item)


    上面的API对应PHP客户端的API。


    介绍完 SquirrelMQ的使用,你可能会觉得这样做会不利于MySQL的并发处理。的确,如果你只搭建一台消息队列服务器的话会有这种情况,但是,如果你搭 建了100或者1000台消息队列服务器,然后把所有的请求均匀地分发到每台服务器上,在通过消息队列服务器并发对MySQL进行操作。


    我们除了可以使用消息队列来减轻对数据库的压力之外,还可以做很多类似的事情,例如一个网站实时生成图片缩略图(如facebook),那么就可以把生成缩略图的操作存入到消息队列,然后让消息队列一个个处理。


    另外SquirrelMQ的效率比Redis要高,而且内存碎片比Redis要少。

  • 相关阅读:
    如何用Java编写一段代码引发内存泄露
    获取一天的开始时间和结束时间
    servlet,jsp,tomcat,jdk对应版本关系,如何查看jsp和servlet版本信息
    什么是元数据?
    什么是Device ID?
    如何查看移动设备标识码
    手机wifi的mac地址是什么??
    MD5摘要
    落地页和离线广告
    广告行业一些常用物料的尺寸
  • 原文地址:https://www.cnblogs.com/cnsanshao/p/2337930.html
Copyright © 2020-2023  润新知