赞
踩
历史原因,一直使用 libev 作为服务底层;异步框架虽然性能比较高,但新人使用门槛非常高,而且串行的逻辑被打散为状态机,这也会严重影响生产效率。
用同步方式实现异步功能,既保证了异步性能优势,又使得同步方式实现源码思路清晰,容易维护,这是协程的优势。带着这样的目的学习微信开源的一个轻量级网络协程库:libco 。
文章来源: [libco] 协程库学习,测试连接 mysql
libco 是轻量级的协程库,看完下面几个帖子,应该能大致搞懂它的工作原理。
带着问题学习 libco:
将 libco 的源码结构展开,这样方便理清它的内部结构关系。
/* 数据库信息。 */ typedef struct db_s { std::string host; int port; std::string user; std::string psw; std::string charset; } db_t; /* 协程任务。 */ typedef struct task_s { int id; /* 任务 id。 */ db_t* db; /* 数据库信息。 */ MYSQL* mysql; /* 数据库实例指针。 */ stCoRoutine_t* co; /* 协程指针。 */ } task_t; /* 协程处理函数。 */ void* co_handler_mysql_query(void* arg) { co_enable_hook_sys(); ... /* 同步方式写数据库访问代码。 */ for (i = 0; i < g_co_query_cnt; i++) { g_cur_test_cnt++; /* 读数据库 select。 */ query = "select * from mytest.test_async_mysql where id = 1;"; if (mysql_real_query(task->mysql, query, strlen(query))) { show_error(task->mysql); return nullptr; } res = mysql_store_result(task->mysql); mysql_free_result(res); } ... } int main(int argc, char** argv) { ... /* 协程个数。 */ g_co_cnt = atoi(argv[1]); /* 每个协程 mysql query 次数。 */ g_co_query_cnt = atoi(argv[2]); /* 数据库信息。 */ db = new db_t{"127.0.0.1", 3306, "root", "123456", "utf8mb4"}; for (i = 0; i < g_co_cnt; i++) { task = new task_t{i, db, nullptr, nullptr}; /* 创建协程。 */ co_create(&(task->co), NULL, co_handler_mysql_query, task); /* 唤醒协程。 */ co_resume(task->co); } /* 循环处理协程事件逻辑。 */ co_eventloop(co_get_epoll_ct(), 0, 0); ... }
在 Centos 系统,查看 hook 是否成功,除了测试打印日志,其实还有其它比较直观的方法。
用 strace 查看底层的调用,我们看到 mysql_real_connect
内部的 connect,被 hook 成功,connect 前,被替换为 libco 的 connect 了。socket 在 connect 前,被修改为 O_NONBLOCK
。
# strace -s 512 -o /tmp/libco.log ./test_libco 1 1
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 4
fcntl(4, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
上神器 gdb,在 co_hook_sys_call.cpp 文件的 read 和 write 函数下断点。
命中断点,查看函数调用堆栈,libco 在 Centos 系统能成功 hook 住 mysqlclient 的阻塞接口。
#0 read (fd=fd@entry=9, buf=buf@entry=0x71fc30, nbyte=nbyte@entry=19404) at co_hook_sys_call.cpp:299
#1 0x00007ffff762b30a in read (__nbytes=19404, __buf=0x71fc30, __fd=9) at /usr/include/bits/unistd.h:44
#2 my_read (Filedes=Filedes@entry=9, Buffer=Buffer@entry=0x71fc30 "", Count=Count@entry=19404, MyFlags=MyFlags@entry=0)
at /export/home/pb2/build/sb_0-37309218-1576675139.51/rpm/BUILD/mysql-5.7.29/mysql-5.7.29/mysys/my_read.c:64
#3 0x00007ffff7624966 in inline_mysql_file_read (
src_file=0x7ffff78424b0 "/export/home/pb2/build/sb_0-37309218-1576675139.51/rpm/BUILD/mysql-5.7.29/mysql-5.7.29/mysys/charset.c",
src_line=383, flags=0, count=19404, buffer=0x71fc30 "", file=9)
at /export/home/pb2/build/sb_0-37309218-1576675139.51/rpm/BUILD/mysql-5.7.29/mysql-5.7.29/include/mysql/psi/mysql_file.h:1129
#4 my_read_charset_file (loader=loader@entry=0x7ffff7ed7270, filename=filename@entry=0x7ffff7ed7320 "/usr/share/mysql/charsets/Index.xml",
myflags=myflags@entry=0) at /export/home/pb2/build/sb_0-37309218-1576675139.51/rpm/BUILD/mysql-5.7.29/mysql-5.7.29/mysys/charset.c:383
从测试结果看,单进程单线程,多个协程是“同时”进行的,“并发”量也随着协程个数增加而增加,跟测试预期一样。
这里只测试协程的"并发性",实际应用应该是用户比较多,每个用户的 sql 命令比较少的。
# ./test_libco 1 10000
id: 0, test cnt: 10000, cur spend time: 1.778823
total cnt: 10000, total time: 1.790962, avg: 5583.591448
# ./test_libco 2 10000
id: 0, test cnt: 10000, cur spend time: 2.328348
id: 1, test cnt: 10000, cur spend time: 2.360431
total cnt: 20000, total time: 2.373994, avg: 8424.620726
# ./test_libco 3 10000
id: 0, test cnt: 10000, cur spend time: 2.283759
id: 2, test cnt: 10000, cur spend time: 2.352147
id: 1, test cnt: 10000, cur spend time: 2.350272
total cnt: 30000, total time: 2.370038, avg: 12658.024719
用 libco 在项目(co_kimserver)里,简单造了个连接池。Linux 压力测试单进程 10w 个协程,每个协程读 10 个 sql 命令(相当于 100w 个包),并发处理能力 8k/s,在可接受范围内。
详细请参考:《[co_kimserver] libco mysql 连接池》
# ./test_mysql_mgr r 100000 10
total cnt: 1000000, total time: 125.832877, avg: 7947.048692
火焰图参考:如何生成火焰图
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/174287
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。