日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

isql 测试mysql连接_[libco] 协程库学习,测试连接 mysql

發布時間:2023/11/29 数据库 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 isql 测试mysql连接_[libco] 协程库学习,测试连接 mysql 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

歷史原因,一直使用 libev 作為服務底層;異步框架雖然性能比較高,但新人學習和使用門檻非常高,而且串行的邏輯被打散為狀態機,這也會嚴重影響生產效率。

用同步方式實現異步功能,既保證了異步性能優勢,又使得同步方式實現源碼思路清晰,容易維護,這是協程的優勢。帶著這樣的目的學習微信開源的一個輕量級網絡協程庫:libco 。

1. 概述

libco 是輕量級的協程庫,看完下面幾個帖子,應該能大致搞懂它的工作原理。

2. 問題

帶著問題學習 libco:

搞清這幾個概念:阻塞,非阻塞,同步,異步,鎖。

協程是什么東西,與進程和線程有啥關系。

協程解決了什么問題。

協程在什么場景下使用。

協程切換原理。

協程切換時機。

協程需要上鎖嗎?

libco 主要有啥功能。(協程管理,epoll/kevent,hook)

3. libco 源碼結構布局

將 libco 的源碼結構展開,這樣方便理清它的內部結構關系。

4. mysql 測試

測試目標:測試 libco 協程性能,以及是否能將 mysqlclient 同步接口進行異步改造。

測試系統:CentOS Linux release 7.7.1908 (Core)

測試源碼:github。

4.1. 測試源碼

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58/* 數據庫信息。 */

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);

...

}

5. hook

在 Centos 系統,查看 hook 是否成功,除了測試打印日志,其實還有其它比較直觀的方法。

5.1. strace

用 strace 查看底層的調用,我們看到 mysql_real_connect 內部的 connect,被 hook 成功,connect 前,被替換為 libco 的 connect 了。socket 在 connect 前,被修改為 O_NONBLOCK 。

1

2

3

4

5# 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 inprogress)

5.2. gdb

上神器 gdb,在 co_hook_sys_call.cpp 文件的 read 和 write 函數下斷點。

命中斷點,查看函數調用堆棧,libco 在 Centos 系統能成功 hook 住 mysqlclient 的阻塞接口。

1

2

3

4

5

6

7

8

9

10#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

6. 壓測結果

從測試結果看,單進程單線程,多個協程是“同時”進行的,“并發”量也隨著協程個數增加而增加,跟測試預期一樣。

這里只測試協程的”并發性”,實際應用應該是用戶比較多,每個用戶的 sql 命令比較少的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14# ./test_libco 1 10000

id: 0, testcnt: 10000, cur spend time: 1.778823

total cnt: 10000, total time: 1.790962, avg: 5583.591448

# ./test_libco 2 10000

id: 0, testcnt: 10000, cur spend time: 2.328348

id: 1, testcnt: 10000, cur spend time: 2.360431

total cnt: 20000, total time: 2.373994, avg: 8424.620726

# ./test_libco 3 10000

id: 0, testcnt: 10000, cur spend time: 2.283759

id: 2, testcnt: 10000, cur spend time: 2.352147

id: 1, testcnt: 10000, cur spend time: 2.350272

total cnt: 30000, total time: 2.370038, avg: 12658.024719

7. mysql 連接池

用 libco 共享棧簡單造了個連接池,在 Linux 壓力測試單進程 10w 個協程,每個協程讀 10 個 sql 命令(相當于 1000w 個包),并發處理能力 8k/s,在可接受范圍內。

1

2# ./test_mysql_mgr r 100000 10

total cnt: 1000000, total time: 125.832877, avg: 7947.048692

壓測源碼(github)。

mysql 連接池簡單實現(github)。

壓測發現每個 mysql 連接只能獨立運行在固定的協程里,否則大概率會出現問題。

libco hook 技術雖然將 mysqlclient 阻塞接口設置為非阻塞,但是每個 mysqlclient 連接,必須一次只能處理一個命令,像同步那樣!非阻塞只是方便協程切換到其它空閑協程進行工作,充分利用原來阻塞等待的時間。而且 mysqlclient 本來就是按照同步的邏輯來寫的,一個連接,一次只能處理一個包,不可能被你設置為非阻塞后,一次往 mysql server 發 N 個包,這樣肯定會出現不可預料的問題。

libco 協程切換成本不高,主要是 mysqlclient 耗費性能,參考火焰圖。

壓測頻繁地申請內存空間也耗費了不少性能(參考火焰圖的 __brk),嘗試添加 jemalloc 優化,發現 jemalloc 與 libco 一起用在 Linux 竟然出現死鎖!!!

8. 小結

通過學習其他大神的帖子,走讀源碼,寫測試代碼,終于對協程有了比較清晰的認知。

測試 libco,Centos 功能正常,但 MacOS 下不能成功 Hook 住 mysqlclient 阻塞接口。

libco 是輕量級的,它主要應用于高并發的 IO 密集型場景,所以你看到它綁定了多路復用模型。

雖然測試效果不錯,如果你考慮用 libco 去造一個 mysql 連接池,還有不少工作要做。

libco 很不錯,所以我選擇 golang 🐶。

9. 參考

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的isql 测试mysql连接_[libco] 协程库学习,测试连接 mysql的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。