sphinx实时索引架构现实 sphinx-server-config

原文链接:http://hi.baidu.com/zwfec/item/358295cf02189a16b77a249b

先说一下笔者曾经应对的情况:

 

每天数据更新量在几十万以上

 

每天PV为千万级以上

 

数据分布在多个数据库下,数据表相同,但更新频率有差异

 

根据实际情况,使用的硬件包括有多台数据库与索引服务器,索引服务器根据业务启用多个端口运行索引实例,避免单点并负载均衡。

 

 

 

建议环境:

 

数据库: 一台或多台(MySQL)

 

索引服务器:一台或多台(Sphinx)

 

负载均衡: NetScaler或F5(可选)

 

操作系统: Linux/FreeBSD

 

 

 

一、安装

 

安装比较简单,在此不再用多说了。

 

假设我们将sphinx安装在 /usr/local/webserver/sphinx

 

MySQL安装在 /usr/local/webserver/mysql

 

 

 

二、配置Sphinx

 

假设我们为了应对大数据量更新以及大的查询量,根据业务需要开启三个不同端口的sphinx实例,配置文件分别为 /usr/local/webserver/sphinx/etc/sphinx_[port].conf

 

为了保证列表页数据一致性,索引也必须是一致的,所以数据源最好使用同一台服务器(暂不考虑MySQL复制延时的问题),这样维护也比较方便。比如我们的数据源数据库服务器host是srcdb。

 

比如在sphinx_[port].conf配置中的source配置: sql_host = srcdb

 

如果需要切换数据库源,只要修改各索引服务器的/etc/hosts文件,将srcdb指向的IP更改即可。

 

另外,sphinx的配置文件编写,最好能利用好继承关系,这样可以写出更简洁更清淅的配置文件。

 

 

 

具体的配置在这不再赘述,下面我们来设计一个比较合理的索引架构。

 

 

 

三、索引组合方式

 

使用过Sphinx的朋友如果看过Sphinx的文档,应该对文档中的main + delta索引设计有印象。不过这种设计在应对大数据量并且数据更新比较频繁的应用时,明显会有很大的不足,特别表现在索引的实时性上。因为随着时间的推 移,在main不作变化的情况下,delta需要索引的数据量会越来越大,这样情况造成的影响一是建索引的时间会花费比较多,二是对数据库压力增大,三是 内网的网络开销增大,而且这些影响将与delta建索引的频率成正比。

 

针对这种情况,我们只需要将delta索引的数据尽量最小化就可以了,我们可以中间增加一个索引,组成main + today + last的索引方式。main索引即主索引可以每天更新一次(重建或合并均可),today索引保存的是当天的数据,N分钟重建一次,last索引索引的 是最新更新的数据,T秒更新一次,主要是将today上一次索引之后到当前时间的更新数据放入索引。所以last索引数据的时间与today索引重建的时 间间隔有关。假如today索引重建的时间间隔为10分钟,那么last索引就应该索引当前时间往前10分钟的数据。这样main + today + last组合起来的索引就将是完整的数据索引,而且因为last索引的数据量小,可以将重建的时间间隔降到最小,从理论上达到了实时索引的效果。

 

可以看出,main + today + last的索引组合方式,拆分逻辑主要找的是时间点,而不是文档ID,所以我们不能照搬Sphinx文档中利用ID拆分索引的方式(根据ID重建有可能会 因为一个很老的贴子更新了,而遍历大量是无用的数据)。每一行数据记录,应该有一个创建时间与更新时间(假设字段名为update_time),时间点主 要对update_time判断即可。

 

具体的配置在这也不用再赘述了。

 

 

 

四、索引的重建

 

main索引的更新,一天做一次即可。方式有重建或合并,都很简单,定时设置使用Linux的crontab就可以了。

 

假设我们每个端口有一个重建main索引的脚本,比如/usr/local/webserver/sphinx/bin/main_renew_[port].sh

 

我们在每一台索引服务器上做一下设置

 

 

 

[root@indexserv1 ~]# crontab -e

 

00 1 * * * /usr/local/webserver/sphinx/bin/main_renew_3312.sh

 

00 2 * * * /usr/local/webserver/sphinx/bin/main_renew_3313.sh

 

00 3 * * * /usr/local/webserver/sphinx/bin/main_renew_3314.sh

 

 

 

 

 

可以看到,main索引重建的时间有所不同,而且不管如何设置重建的时间,在时间跨过了0点之后main索引更新完之前,today索引应该要有一个处理 逻辑,不能只是创建每一天0点或拟定的拆分时间点之后的数据,否则就有可能在main索引更新完之前丢失一天的数据。这个处理逻辑可以写在source的 sql_query_range里,具体实现根据自身main索引重建的时间做设定。

 

 

 

上面的main索引重建,我们可以看到,使用的是linux的crontab来做的定时任务。现在我们讨论一下today索引的重建。

 

 

 

前面我们提过了,today索引10分钟更新一次。我们是不是也可以像main索引一样,使用crontab来做定时呢?假如只有一台索引服务器,理论上 是可以的。但是如果有多台索引服务器的话,索引服务器之间可能会有几秒的时间差异,而这点时间差异就有可能做成列表页数据不一致的情况。服务器时间差异是 一个问题,这个问题理论上可以使用ntpdate来弥补,但这不是一个好办法。另外,如果是同一端口下有许多的today索引,而数据是来自许多不同的数 据库,如果盲目地只是10分钟重建一次,那会造成有许多冗余的重建操作。比如,有一些数据表可能超过10分钟都没有更新,那重建索引无疑是浪费资源。由此 可以想到,last索引的重建也会有这样的问题。

 

 

 

为了将重建索引对服务器的性能损耗降到最低,我们应该要做到对每一个today、last索引是否需要重建作判断,只要是没有数据更新的,就不需要进行重建。并且为了避免服务器的时间差异,应该要让多台索引服务器同时进行重建。

 

 

 

 

 

 

 

五、实时的C/S应用

 

 

 

很容易,我们就可以想到C/S架构。每一台索引服务器作为Server端,负责接收重建指令并执行重建。使用一台服务器作为Client端,Client端主要负责对索引是否重建作判断,并根据索引分布规则同时对规则中的服务端发送重建指令。

 

 

 

我们定义一套很简单的规则,Server端接收的命令格式:[port]|[--rotate] [index] [index] [index] |

 

 

 

上面我们使用了”|”作为分割符,为了避免无用数据的干扰,指命后面最好有一个”|”。

 

 

 

 

 

(1)server端

 

 

 

我们可以看到sphinx/bin/下面有indexer、search、searchd,那么我们的server端就叫indexerd好了。

 

 

 

手工写一份indexerd.c源码,使用3333端口。

 

 

 

#include <stdio.h>

 

#include <stdlib.h>

 

#include <errno.h>

 

#include <string.h>

 

#include <sys/types.h>

 

#include <netinet/in.h>

 

#include <sys/socket.h>

 

#include <sys/wait.h>

 

 

 

#define SERV_PORT 3333

 

#define BACKLOG 15

 

#define MAXSIZE 1000

 

 

 

void split(char **arr, char *str, const char *del)

 

{

 

char *s = strtok(str, del);

 

while(s != NULL)

 

{

 

*arr++ = s;

 

s = strtok(NULL, del);

 

}

 

}

 

 

 

int main()

 

{

 

int sockfd,client_fd;

 

char *indexer_pre = "/usr/local/webserver/sphinx/bin/indexer --quiet --config /usr/local/webserver/sphinx/etc/sphinx_";

 

struct sockaddr_in my_addr;

 

struct sockaddr_in remote_addr;

 

//create socket

 

if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)

 

{

 

perror("socket create failed!");

 

exit(1);

 

}

 

 

 

//bind port

 

my_addr.sin_family      = AF_INET;

 

my_addr.sin_port        = htons(SERV_PORT);

 

my_addr.sin_addr.s_addr = INADDR_ANY;

 

bzero(&(my_addr.sin_zero),8);

 

if (bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1)

 

{

 

perror("bind error!");

 

exit(1);

 

}

 

 

 

//listen

 

if (listen(sockfd, BACKLOG) == -1)

 

{

 

perror("listen error");

 

exit(1);

 

}

 

printf("\n");

 

printf("Sphinx Indexer Daemon\nAuthor:Keeff <Keeff@bluekee.com>\n");

 

printf("Service running...");

 

printf("\n");

 

 

 

while (1)

 

{

 

int sin_size = sizeof(struct sockaddr_in);

 

if ((client_fd = accept(sockfd, (struct sockaddr*)&remote_addr,&sin_size)) == -1)

 

{

 

perror("Accept error!");

 

continue;

 

}

 

 

 

int pid;

 

pid = fork();

 

if ( !pid )

 

{

 

char indexer_shell[1500];

 

strcpy(indexer_shell, indexer_pre);

 

int rval;

 

char receive_string[MAXSIZE];

 

if ((rval = read(client_fd, receive_string, MAXSIZE)) < 0)

 

{

 

perror("Reading stream error!");

 

continue;

 

}

 

 

 

char *param_arr[3];

 

const char *del = "|";

 

split(param_arr, receive_string, del);

 

 

 

if ( strstr(param_arr[0],";") != NULL || strstr(param_arr[0],"`") != NULL || strstr(param_arr[1],";") != NULL || strstr(param_arr[1],"`") != NULL)

 

{

 

//send msg to client

 

char *msg = "Bad command!" ;

 

if (send(client_fd, msg, strlen(msg), 0) == -1) perror("send error!");

 

close(client_fd);

 

exit(0);

 

}

 

 

 

strcat(indexer_shell, param_arr[0]);

 

strcat(indexer_shell, ".conf ");

 

strcat(indexer_shell, param_arr[1]);

 

system(indexer_shell);

 

//send msg to client

 

char* msg = "Indexer running...";

 

if (send(client_fd, msg, strlen(msg), 0) == -1) perror("send error!");

 

close(client_fd);

 

exit(0);

 

}

 

close(client_fd);

 

waitpid(pid, NULL, 0);

 

}

 

return 0;

 

}

 

 

 

 

 

indexerd.c保存到每一台索引服务器的/usr/local/webserver/sphinx/bin/下,然后编译

 

 

 

[root@indexserv1 bin]# gcc -o indexerd indexerd.c

 

 

 

 

 

在每台索引服务器上启动indexerd

 

 

 

[root@indexserv1 bin]# nohup ./indexerd > /dev/null &

 

 

 

 

 

检查一下服务是否启用

 

 

 

[root@indexserv1 bin]# netstat -nlp|grep 3333

 

tcp        0      0 0.0.0.0:3333                0.0.0.0:*                   LISTEN      31676/indexerd

 

 

 

可以看到indexerd已经正常启用了。

 

 

 

 

 

(2) client端的指令发送器

 

 

 

指令发送器不负责任何逻辑处理,只负责向服务端发送指令

 

 

 

我们把它命名为indexer_send

 

 

 

现在编写一份indexer_send.c的源码

 

 

 

#include <stdio.h>

 

#include <stdlib.h>

 

#include <errno.h>

 

#include <string.h>

 

#include <sys/types.h>

 

#include <netinet/in.h>

 

#include <sys/socket.h>

 

#include <sys/wait.h>

 

 

 

#define SERVPORT 3333

 

#define MAXDATASIZE 1500

 

 

 

int main(int argc, char* argv[])

 

{

 

if ( argv[1] == NULL )

 

{

 

printf("Sphinx Indexer Sender\nAuthor:Keeff <Keeff@bluekee.com>\nUsage:\n/path/to/indexer_send [ip] \"[port]|[--rotate] [index] [index]|\" [-debug]\n");

 

exit(1);

 

}

 

int sockfd, recvbytes;

 

char buf[MAXDATASIZE];

 

struct hostent *host;

 

struct sockaddr_in serv_addr;

 

 

 

if (( sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

 

{

 

perror("socket error!");

 

exit(1);

 

}

 

bzero(&serv_addr,sizeof(serv_addr));

 

serv_addr.sin_family    = AF_INET;

 

serv_addr.sin_port      = htons(SERVPORT);

 

serv_addr.sin_addr.s_addr= inet_addr(argv[1]);

 

 

 

if (connect(sockfd, (struct sockaddr *)&serv_addr,sizeof(struct sockaddr)) == -1)

 

{

 

perror("connect error!");

 

exit(1);

 

}

 

 

 

write(sockfd, argv[2], strlen(argv[2]));

 

//debug

 

if ( argv[3] != NULL && strcmp("-debug",argv[3]) == 0 )

 

{

 

printf("command: %s\n",argv[2]);

 

if ((recvbytes = recv(sockfd, buf, MAXDATASIZE,0)) == -1)

 

{

 

perror("recv error!");

 

exit(1);

 

}

 

buf[recvbytes] = '\0';

 

printf("Response: %s",buf);

 

}

 

close(sockfd);

 

return 0;

 

}

 

 

 

 

 

编译

 

 

 

[root@indexclient bin]# gcc -o indexer_send indexer_send.c

 

 

 

 

 

调试发送器,假设一台索引服务器IP为192.168.1.111,其中的3312端口下有类似beijing_store_today,shanghai_store_today的索引

 

 

 

[root@indexclient bin]#./indexer_send 192.168.1.111 "3312|--rotate beijing_store_today shanghai_store_today |" -debug

 

command: 3312|--rotate beijing_store_today shanghai_store_today |

 

Response: Indexer running...

 

 

 

可以看到,indexerd返回了执行重建的消息,说明indexerd与indexer_send都能正常使用。

 

 

 

 

 

(3) client端

 

 

 

today索引的client程序我们命名为today_indexer

 

 

 

last索引的client程序我们命名为last_indexer

 

 

 

 

 

我们先写一份简单的today_indexer.c源码

 

 

 

#include <stdlib.h>

 

#include <stdio.h>

 

#include <string.h>

 

#include <unistd.h>

 

#include <mysql.h>

 

 

 

#define INTERVAL 600

 

 

 

int main(int argc, char *argv[] )

 

{

 

if ( argv[1] == NULL )

 

{

 

printf("Sphinx today Indexer\nAuthor:Keeff <Keeff@bluekee.com>\nUsage:\n/path/to/today_indexer 3312 3313 3314 -debug\n\n");

 

exit(1);

 

}

 

 

 

MYSQL *conn;

 

MYSQL_RES *res;

 

MYSQL_ROW row;

 

 

 

//数据库配置

 

char *server   = "srcdb";

 

char *user     = "srcdbuser";

 

char *password = "srcdbpass";

 

char *database = "mysql";

 

 

 

//debug

 

int  debug = 0;

 

 

 

char *exec_script  = "/usr/local/webserver/sphinx/bin/indexer_send";

 

char cmd_del[] = "|";

 

char cmd_pre[] = "--rotate ";

 

char cmd_post[] = "&|";

 

 

 

char *port_3312 = "3312";

 

char *port_3313 = "3313";

 

char *port_3314 = "3314";

 

 

 

char cmd_3312[5] = "";

 

char cmd_3313[5] = "";

 

char cmd_3314[5] = "";

 

 

 

strcpy(cmd_3312, port_3312);

 

strcpy(cmd_3313, port_3313);

 

strcpy(cmd_3345, port_3314);

 

 

 

strcat(cmd_3312, cmd_del);

 

strcat(cmd_3313, cmd_del);

 

strcat(cmd_3314, cmd_del);

 

 

 

strcat(cmd_3312, cmd_pre);

 

strcat(cmd_3313, cmd_pre);

 

strcat(cmd_3314, cmd_pre);

 

 

 

char real_exec_script[100];

 

strcpy(real_exec_script, exec_script);

 

strcat(real_exec_script, " ");

 

 

 

while ( 1 )

 

{

 

//指令开关

 

int  run_3312 = 0;

 

int  run_3313 = 0;

 

int  run_3314 = 0;

 

 

 

char shell_3312[1500] = "";

 

char shell_3313[1500] = "";

 

char shell_3314[1500] = "";

 

 

 

strcpy(shell_3312, cmd_3312);

 

strcpy(shell_3313, cmd_3313);

 

strcpy(shell_3314, cmd_3314);

 

 

 

conn = mysql_init(NULL);

 

if (!mysql_real_connect(conn, server,user, password, database, 0, NULL, 0))

 

{

 

fprintf(stderr, "%s\n", mysql_error(conn));

 

exit(1);

 

}

 

mysql_query(conn,"SET SESSION query_cache_type=off");

 

mysql_query(conn,"SET NAMES utf8");

 

if (mysql_query(conn, "SELECT table_schema, table_name FROM information_schema.tables WHERE table_name IN ('store','flea','job') AND unix_timestamp(update_time) > unix_timestamp()-615"))

 

{

 

fprintf(stderr, "%s\n", mysql_error(conn));

 

exit(1);

 

}

 

res = mysql_use_result(conn);

 

while ((row = mysql_fetch_row(res)) != NULL)

 

{

 

for(int i=0; i<argc; i++ )

 

{

 

if ( argv != NULL )

 

{

 

if ( strcmp("-debug",argv) == 0 )

 

{

 

debug = 1;

 

}

 

 

 

if ( strcmp("3312",argv) == 0 )

 

{

 

if ( strcmp( "store", row[1] ) == 0 )

 

{

 

run_3312 = 1;

 

strcat(shell_3312,row[0]);

 

strcat(shell_3312,"_");

 

strcat(shell_3312,row[1]);

 

strcat(shell_3312,"_today ");

 

}

 

}

 

 

 

if ( strcmp("3313",argv) == 0 )

 

{

 

if ( strcmp( "flea", row[1] ) == 0 )

 

{

 

run_3313 = 1;

 

strcat(shell_3313,row[0]);

 

strcat(shell_3313,"_");

 

strcat(shell_3313,row[1]);

 

strcat(shell_3313,"_today ");

 

}

 

}

 

 

 

if ( strcmp("3314",argv) == 0 )

 

{

 

if ( strcmp( "job", row[1] ) == 0 )

 

{

 

run_3314 = 1;

 

strcat(shell_3314,row[0]);

 

strcat(shell_3314,"_");

 

strcat(shell_3314,row[1]);

 

strcat(shell_3314,"_today ");

 

}

 

}

 

}

 

}

 

}

 

 

 

mysql_free_result(res);

 

mysql_close(conn);

 

 

 

//execute shell

 

if ( run_3312 == 1 )

 

{

 

char exec_3312[1500] = "";

 

strcpy(exec_3312, real_exec_script);

 

strcat(exec_3312, "192.168.1.111 \"");

 

strcat(exec_3312, shell_3312);

 

strcat(exec_3312, cmd_post);

 

strcat(exec_3312, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3312);

 

strcat(exec_3312, " -debug");

 

}

 

system(exec_3312);

 

 

 

strcpy(exec_3312, real_exec_script);

 

strcat(exec_3312, "192.168.1.112 \"");

 

strcat(exec_3312, shell_3312);

 

strcat(exec_3312, cmd_post);

 

strcat(exec_3312, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3312);

 

strcat(exec_3312, " -debug");

 

}

 

system(exec_3312);

 

}

 

 

 

if ( run_3313 == 1 )

 

{

 

char exec_3313[1500] = "";

 

strcpy(exec_3313, real_exec_script);

 

strcat(exec_3313, "192.168.1.113 \"");

 

strcat(exec_3313, shell_3313);

 

strcat(exec_3313, cmd_post);

 

strcat(exec_3313, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3313);

 

strcat(exec_3313, " -debug");

 

}

 

system(exec_3313);

 

 

 

strcpy(exec_3313, real_exec_script);

 

strcat(exec_3313, "192.168.1.114 \"");

 

strcat(exec_3313, shell_3313);

 

strcat(exec_3313, cmd_post);

 

strcat(exec_3313, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3313);

 

strcat(exec_3313, " -debug");

 

}

 

system(exec_3313);

 

}

 

 

 

if ( run_3314 == 1 )

 

{

 

char exec_3314[1500] = "";

 

strcpy(exec_3314, real_exec_script);

 

strcat(exec_3314, "192.168.1.115 \"");

 

strcat(exec_3314, shell_3314);

 

strcat(exec_3314, cmd_post);

 

strcat(exec_3314, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3314);

 

strcat(exec_3314, " -debug");

 

}

 

system(exec_3314);

 

 

 

strcpy(exec_3314, real_exec_script);

 

strcat(exec_3314, "192.168.1.116 \"");

 

strcat(exec_3314, shell_3314);

 

strcat(exec_3314, cmd_post);

 

strcat(exec_3314, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3314);

 

strcat(exec_3314, " -debug");

 

}

 

system(exec_3314);

 

}

 

 

 

sleep( INTERVAL );

 

}

 

}

 

 

 

由源码可以看出,通过查询information_schema.tables,我们可以获知数据表的最后更新时间。我在这里举的例子是这样的,比如有商 铺信息的表,表名是store,数据库分别是beijing,shanghai,shenzhen…等许多许多个全国不面的城市库。3312端口下的 索引就是商铺的索引,main索引名称如beijing_store,shanghai_store的形式,today索引的名称则如 beijing_store_today,shanghai_store_today的形式,last索引的名称则如 beijing_store_last,shanghai_store_last的形式。 如此规则,3313端口下是二手交易,也是类似beijing_flea,beijing_flea_today,beijing_flea_last的 形式。3314端口下的招聘信息也一样。即是[db_name]_[table_name]为main索引名, [db_name]_[table_name]_today为today索引名,[db_name]_[table_name]_last为last索引 名.

 

 

 

today_indexer的作用就是每隔10分钟,查询information_schema.tables,只要是在10分钟(可以多加十几秒)有更新的,就分端口拼接today索引名称,然后同时向服务端发送重建指令。

 

 

 

现在编译today_indexer

 

 

 

[root@indexclient bin]# gcc -o today_indexer today_indexer.c `/usr/local/mysql/bin/mysql_config --cflags --libs` --std=c99

 

 

 

启用today_indexer

 

[root@indexclient bin]#nohup ./today_indexer 3312 3313 3314 > /dev/null &

 

 

 

 

 

用同样的方法,我们写一个last_indexer程序

 

last_indexer.c源码

 

 

 

#include <stdlib.h>

 

#include <stdio.h>

 

#include <string.h>

 

#include <unistd.h>

 

#include <mysql.h>

 

 

 

#define INTERVAL 10

 

 

 

int main(int argc, char *argv[] )

 

{

 

if ( argv[1] == NULL )

 

{

 

printf("Sphinx last Indexer\nAuthor:Keeff <Keeff@bluekee.com>\nUsage:\n/path/to/last_indexer 3312 3313 3314 -debug\n\n");

 

exit(1);

 

}

 

 

 

MYSQL *conn;

 

MYSQL_RES *res;

 

MYSQL_ROW row;

 

 

 

//数据库配置

 

char *server   = "srcdb";

 

char *user     = "srcdbuser";

 

char *password = "srcdbpass";

 

char *database = "mysql";

 

 

 

//debug

 

int  debug = 0;

 

 

 

char *exec_script  = "/usr/local/webserver/sphinx/bin/indexer_send";

 

char cmd_del[] = "|";

 

char cmd_pre[] = "--rotate ";

 

char cmd_post[] = "&|";

 

 

 

char *port_3312 = "3312";

 

char *port_3313 = "3313";

 

char *port_3314 = "3314";

 

 

 

char cmd_3312[5] = "";

 

char cmd_3313[5] = "";

 

char cmd_3314[5] = "";

 

 

 

strcpy(cmd_3312, port_3312);

 

strcpy(cmd_3313, port_3313);

 

strcpy(cmd_3345, port_3314);

 

 

 

strcat(cmd_3312, cmd_del);

 

strcat(cmd_3313, cmd_del);

 

strcat(cmd_3314, cmd_del);

 

 

 

strcat(cmd_3312, cmd_pre);

 

strcat(cmd_3313, cmd_pre);

 

strcat(cmd_3314, cmd_pre);

 

 

 

char real_exec_script[100];

 

strcpy(real_exec_script, exec_script);

 

strcat(real_exec_script, " ");

 

 

 

while ( 1 )

 

{

 

//指令开关

 

int  run_3312 = 0;

 

int  run_3313 = 0;

 

int  run_3314 = 0;

 

 

 

char shell_3312[1500] = "";

 

char shell_3313[1500] = "";

 

char shell_3314[1500] = "";

 

 

 

strcpy(shell_3312, cmd_3312);

 

strcpy(shell_3313, cmd_3313);

 

strcpy(shell_3314, cmd_3314);

 

 

 

conn = mysql_init(NULL);

 

if (!mysql_real_connect(conn, server,user, password, database, 0, NULL, 0))

 

{

 

fprintf(stderr, "%s\n", mysql_error(conn));

 

exit(1);

 

}

 

mysql_query(conn,"SET SESSION query_cache_type=off");

 

mysql_query(conn,"SET NAMES utf8");

 

if (mysql_query(conn, "SELECT table_schema, table_name FROM information_schema.tables WHERE table_name IN ('store','flea','job') AND unix_timestamp(update_time) > unix_timestamp()-615"))

 

{

 

fprintf(stderr, "%s\n", mysql_error(conn));

 

exit(1);

 

}

 

res = mysql_use_result(conn);

 

while ((row = mysql_fetch_row(res)) != NULL)

 

{

 

for(int i=0; i<argc; i++ )

 

{

 

if ( argv != NULL )

 

{

 

if ( strcmp("-debug",argv) == 0 )

 

{

 

debug = 1;

 

}

 

 

 

if ( strcmp("3312",argv) == 0 )

 

{

 

if ( strcmp( "store", row[1] ) == 0 )

 

{

 

run_3312 = 1;

 

strcat(shell_3312,row[0]);

 

strcat(shell_3312,"_");

 

strcat(shell_3312,row[1]);

 

strcat(shell_3312,"_last ");

 

}

 

}

 

 

 

if ( strcmp("3313",argv) == 0 )

 

{

 

if ( strcmp( "flea", row[1] ) == 0 )

 

{

 

run_3313 = 1;

 

strcat(shell_3313,row[0]);

 

strcat(shell_3313,"_");

 

strcat(shell_3313,row[1]);

 

strcat(shell_3313,"_last ");

 

}

 

}

 

 

 

if ( strcmp("3314",argv) == 0 )

 

{

 

if ( strcmp( "job", row[1] ) == 0 )

 

{

 

run_3314 = 1;

 

strcat(shell_3314,row[0]);

 

strcat(shell_3314,"_");

 

strcat(shell_3314,row[1]);

 

strcat(shell_3314,"_last ");

 

}

 

}

 

}

 

}

 

}

 

 

 

mysql_free_result(res);

 

mysql_close(conn);

 

 

 

//execute shell

 

if ( run_3312 == 1 )

 

{

 

char exec_3312[1500] = "";

 

strcpy(exec_3312, real_exec_script);

 

strcat(exec_3312, "192.168.1.111 \"");

 

strcat(exec_3312, shell_3312);

 

strcat(exec_3312, cmd_post);

 

strcat(exec_3312, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3312);

 

strcat(exec_3312, " -debug");

 

}

 

system(exec_3312);

 

 

 

strcpy(exec_3312, real_exec_script);

 

strcat(exec_3312, "192.168.1.112 \"");

 

strcat(exec_3312, shell_3312);

 

strcat(exec_3312, cmd_post);

 

strcat(exec_3312, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3312);

 

strcat(exec_3312, " -debug");

 

}

 

system(exec_3312);

 

}

 

 

 

if ( run_3313 == 1 )

 

{

 

char exec_3313[1500] = "";

 

strcpy(exec_3313, real_exec_script);

 

strcat(exec_3313, "192.168.1.113 \"");

 

strcat(exec_3313, shell_3313);

 

strcat(exec_3313, cmd_post);

 

strcat(exec_3313, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3313);

 

strcat(exec_3313, " -debug");

 

}

 

system(exec_3313);

 

 

 

strcpy(exec_3313, real_exec_script);

 

strcat(exec_3313, "192.168.1.114 \"");

 

strcat(exec_3313, shell_3313);

 

strcat(exec_3313, cmd_post);

 

strcat(exec_3313, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3313);

 

strcat(exec_3313, " -debug");

 

}

 

system(exec_3313);

 

}

 

 

 

if ( run_3314 == 1 )

 

{

 

char exec_3314[1500] = "";

 

strcpy(exec_3314, real_exec_script);

 

strcat(exec_3314, "192.168.1.115 \"");

 

strcat(exec_3314, shell_3314);

 

strcat(exec_3314, cmd_post);

 

strcat(exec_3314, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3314);

 

strcat(exec_3314, " -debug");

 

}

 

system(exec_3314);

 

 

 

strcpy(exec_3314, real_exec_script);

 

strcat(exec_3314, "192.168.1.116 \"");

 

strcat(exec_3314, shell_3314);

 

strcat(exec_3314, cmd_post);

 

strcat(exec_3314, "\"");

 

if ( debug == 1 )

 

{

 

printf("%s\n",exec_3314);

 

strcat(exec_3314, " -debug");

 

}

 

system(exec_3314);

 

}

 

 

 

sleep( INTERVAL );

 

}

 

}

 

 

现在编译last_indexer

 

 

[root@indexclient bin]# gcc -o last_indexer last_indexer.c `/usr/local/mysql/bin/mysql_config --cflags --libs` --std=c99

 

 

如果需要调试

 

[root@indexclient bin]#./last_indexer 3312 3313 3314 -debug

 

 

 

这样,如果你的网站数据更新频繁,很快你将看到调试信息

 

 

启用last_indexer

 

 

[root@indexclient bin]#nohup ./last_indexer 3312 3313 3314 > /dev/null &

 

 

六、结束

 

 

 

至此,实时索引架构基本上已经是完成,只需要在查询代码里将三个索引都写上即可。

 

写得比较仓促,有不对的地方,请朋友们指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值