Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

an agent for distributed memcacheq

branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

README

 
1 Mqagent的用途
Mqagent是为了适应分布式memcachq的需求,在magent基础上进行二次开发形成,因为其时专门为memcacheq服务的,因此我命名为mqagent。
其作为代理层,隔离了开发者和后端的多个memcachq server,使得后端对开发者透明,开发人员只需要和代理层,依据memcache的协议进行消息队列的get/set操作即可。


2 Mqagent使用流程
1、开发者申请一个消息队列名称,例如msg_deliver_email, 该消息队列主要用来处理异步发送邮件。
2、mqagent的维护者,需要根据开发者申请的消息队列的名称配置使用的后端的memcacheq的服务器的地址。例如:下面代码是mqagent配置文件中的【tasks】部分,主要配置 消息队列的名称和后端memcachq之间的映射关系。
	
[tasks]
sync_pre_process = 127.0.0.1:22201,127.0.0.1:22203
advance_sync_pre_process = 127.0.0.1:22201,127.0.0.1:22203
msg_deliver_email = 127.0.0.1:22024
此时kill -1 xxx, xxx为mqagent的pid号码,这样就可以reload新的配置了。
3、设置完成后,mqagent维护者返回给开发者配置好的mqagent的地址和端口号,及消息队列名称,二者基于下面介绍的协议就可以通信了。

3 Mqagent协议的设计
总体来说mqagent协议是基于memcache协议的,针对项目中的一些特殊需求,比如针对某个jid的消息队列需要保持时序的一致性。
因此我们对set协议进行了修改。
3.1 Set协议
<command name> <key> <flags> <exptime> <bytes>\r\n <data block>\r\n
- <command name> 是 set
    * set 意思是 “储存此数据”,这里是队列的push操作。
- <key> 是接下来的客户端所要求储存的数据的键值。
- <flags> 是在取回内容时,与数据和发送块一同保存服务器上的任意16位无符号整形(用十进制来书写)。客户端可以用它作为“位域”来存储一些特定的信息;它对服务器是不透明的。
	- <bytes> 是随后的数据区块的字节长度,不包括用于分野的“\r\n”。它可以是0(这时后面跟随一个空的数据区块)。
在这一行以后,客户端发送数据区块。	
<data block>\r\n
我们对set的key做了一个适配,既能支持无特殊要求时序性的队列,比如GSM的业务,也能支持对连接分析中需要保持某jid的操作的一致性。
<key>分解为<task_name/jid>
其中task_name为队列的名称。
jid为保持该jid的一致性 即为该jid的所有消息都放到该消息队列中。

3.2 Get协议
get <key>\r\n
其中key为消息队列的名称。
4 Mqagent的程序实现
4.1 配置文件
[General]
#max keep alive connections for one memcached server 
maxidle=20

#max connection from  all clients
maxconns=4096

#mqagent port;
port=11215

#use ketama consistence hash 
useketama=true

#daemon mode
daemon_mode=true

#logfile
logdir=/home/saint

[tasks]
sync_pre_process = 127.0.0.1:22201,127.0.0.1:22203
advance_sync_pre_process = 127.0.0.1:22201,127.0.0.1:22203
sync_link_deal = 127.0.0.1:22202
davance_sync_link_deal = 127.0.0.1:22204
其中配置文件中【General】模块是继承了magent来实现的,而【tasks】模块是mqagent独有的,主要配置 消息队列的名称和后端memcacheq之间的映射关系。
4.2 设计原理	
读取配置文件,将每一个tasks的item,作为一个key-value键值对存入到hash table中,使用者通过传递进来的mq_name就可以知道要使用哪些后端的机器。
Set命令,key中的task_name,如果key不包含jid,则根据时间和task_name生成的值执行一致性hash算法,寻找后端的memcacheq。如果含有jid则对jid进行一致性hash计算得到后端memcacheq服务器的地址。依据memcache协议,重写set命令,传递到真正的memcacheq服务器中去。
Get命令,相对比较简单,使用的是round-robin算法,每个get传入的key值为消息队列的名称。通过key找到hash table中的后端的memcacheq group,然后轮询的执行get命令
5 客户端编写示例(c)
1、仅支持memcached的协议下的get,set命令。
2、Get相对于队列的pop操作,set相当于队列的push操作。
3、可以借助现有的memcached的client的库来实现。
#include "mt.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<libmemcached/memcached.h>
int main(int argc,char *argv[])
{

    if(0)
    {
        fprintf(stderr,"Usage:%s %s %s",argv[0],"hostname","port");
        exit(1);
    }   
    memcached_st *memc;
    memcached_return rc;
    memcached_server_st *servers;
    
    memc = memcached_create(NULL);

    memcached_behavior_set(memc,MEMCACHED_BEHAVIOR_KETAMA,1);
    servers = memcached_server_list_append_with_weight(NULL,"localhost",11215,1,&rc);

    rc = memcached_server_push(memc,servers);
    memcached_server_free(servers);
    if(rc == MEMCACHED_SUCCESS)
        fprintf(stdout,"puse success\n");
    char *key = "sync_pre_process/wangminghua1126@sina.com";
    size_t lenval,rtv;
    uint32_t rtf;

    char *val10 = "0,0,sync_link_deal.gozap.com,sync_feed.gozap.com,king@gozap.com,liwei@gozap.com,<Data><eventDataId>0</eventDataId><eventAction>add</eventAction><CONN_guid action = \"add\">3</CONN_guid></Data>";
    
    int count = 0 ;
    while(++ count)
    { 
    //sleep(1); 
    printf("int %d\n",count);
    rc = memcached_set(memc,key,strlen(key),val10,strlen(val10),(time_t)0,(uint32_t)0);
    if(rc !=  MEMCACHED_SUCCESS)
        printf("errno %d, %s \n",rc, memcached_strerror(NULL,rc));
    else 
        printf("success...\n");
    
    }

    memcached_free(memc);   
}
6 地址
http://svn.gozap.com/svn/mqagent


	
7 TODO
1、 对修改配置后,发送reload信号的处理,目前只是支持了添加消息队列,对于消息队列的删除,及消息队列内部的更改,还没有完成。

Something went wrong with that request. Please try again.