【原創】modb 功能設計之「支持部分MySQL客戶端協議」-1


      在 《 modb 功能設計之「支持多消費者單生產者」 》中說到:須要有一個單獨的線程來處理 sql 語句。本文就針對「 支持部分 MySQL 客戶端協議」作第一部分講述。

      最初的想法是,rabbitmq 客戶端從 queue 消費到了包含 sql 語句的消息後,須要提取並分析該 sql 後,經過 MySQL 協議再要求數據庫執行該 sql 語句。這就要求我這個 demo 必須實現了 MySQL 客戶端側所需的協議部分。要實現這個,有三種途徑:  
  • 利用公司已有的 dbi 的庫實現 MySQL 訪問
  • 基於 mysqlclient 庫作開發實現 MySQL 客戶端側協議
  • 本身實現 MySQL 客戶端側須要的協議
個人選擇:
      不打算用公司的 dbi 庫,首先,該庫基於了其餘的公司庫,而我並不想使用;其次,該庫封裝的也不是很好,以前我還查出了 4 處崩潰,不排除還有其餘問題;最後,該庫其實也是在 mysqlclient 上作的封裝,和上面第 2條實際上是同樣的。因此,最終我決定選擇第 2 種方式,本身搞個「山頭」出來。
PS:其實開始的時候也想過採用上面的第 3 種方式,本身從底層開始實現如何支持 MySQL 客戶端協議,結果「呵呵」了,難度和工做量不是通常的大~~
 

肯定基於什麼來作開發後,該作下一步目標選擇了:
  • 直接使用 mysqlclient 提供的 API 實現常規阻塞式調用能知足個人要求麼?
  • 是否須要基於 libevent 實現事件驅動式的調用模式?難度大麼? 
  • 是否有合適的開源 MySQL 客戶端實現來啓發個人思路?供我參考? 
      不要覺得我啥都知道,能夠坦白的講,作這個開發以前,我對上述的問題一無所知,不過我從不擔憂本身的學習能力, 因而乎開始各類搜索……

能夠參考的客戶端實現(彷佛)有:

4.5. MySQL Client Programs
4.5.1. mysql — The MySQL Command-Line Tool
4.5.2. mysqladmin — Client for Administering a MySQL Server
4.5.3. mysqlcheck — A Table Maintenance Program
4.5.4. mysqldump — A Database Backup Program
4.5.5. mysqlimport — A Data Import Program
4.5.6. mysqlshow — Display Database, Table, and Column Information
4.5.7. mysqlslap — Load Emulation Client

      其中 mysql、mysqladmin、mysqlshow 和 mysqlslap 看起來很值得研究。 因而開始研究如何在 Linux下用 C 語言 API 鏈接 MySQL 數據庫。

      在 MySQL 官網上找到了以下內容,對基於 MySQL C API 實現客戶端應用程序的說明(我的總結)
================================
22.8.1. MySQL C API Implementations

MySQL C API 爲客戶端應用程序提供了用於和 MySQL server 通訊使用的基於 C 的 API。
提供了兩種版本的庫供使用:libmysqlclient(客戶端版本)和 libmysqld(嵌入式服務器版本)。

在 Unix (以及 Unix-like)系統上,靜態庫爲 libmysqlclient.a,動態庫爲 libmysqlclient.so 。
帶 _r 後綴的庫的含義:在 MySQL 5.5 之前,帶 _r 後綴的庫爲 thread-safe (re-entrant) 的庫,不然,則不是。而在 MySQL 5.5 版本以後,帶不帶 _r 後綴都是 thread-safe (re-entrant) 的庫了,因此理論上講,已經不須要帶 _r 的庫了。

22.8.2. Simultaneous MySQL Server and MySQL Connector/C Installations
這個主要講同時安裝 MySQL server 和 MySQL Connector/C 的問題,和我要搞的事情無關

22.8.3. Example C API Client Programs
這個本應該給出如何使用 C API 來編寫客戶端程序的,可是其只是告訴你能夠參考 client 文件夾下的源碼。大概掃了一下,能夠參考的,且代碼量較小的是 mysqlshow.c 。

22.8.4. Building and Running C API Client Programs
這個主要講如何構建和運行 C API 的客戶端程序了,主要分爲3部分說明:

22.8.4.1. Building C API Client Programs
示例說明如何編譯客戶端程序
shell> gcc -c `mysql_config --cflags` progname.c
shell> gcc -o progname progname.o `mysql_config --libs`

22.8.4.2. Writing C API Threaded Client Programs
討論如何在調用 C API 的時候保證線程安全

22.8.4.3. Running C API Client Programs
避免因爲系統升級致使的頭文件 mysql.h 和庫 libmysqlclient.a 的不匹配問題,出現問題則須要使用新的頭文件和庫從新編譯。若依賴動態庫,當出現主版本好變動的時候(如 libmysqlclient.so.17 到 libmysqlclient.so.18),則須要從新編譯。

22.8.5. C API Data Structures
這裏開始介紹各類數據結構(略)
================================

      好吧,反正哪個對我來講都是陌生的,那麼就研究其中的 mysqlshow 試試看。 首先要乾的事情就是,本身要能成功編譯 mysqlshow 。

(...省略中間過程當中的唧唧歪歪...)

自建工程目錄以下
[root@Betty mysql_client_test]# ll 
總計 116 
-rw-r--r-- 1 root root   4130 10-25 14:33 client_priv.h 
-rw-r--r-- 1 root root   2124 10-25 15:01 my_default.h 
-rw-r--r-- 1 7161 wheel 25393 10-25 15:03 mysqlshow.c 
-rw-r--r-- 1 root root   1686 10-25 15:01 welcome_copyright_notice.h 
[root@Betty mysql_client_test]#

成功編譯 html

[root@Betty mysql_client_test]# gcc mysqlshow.c -o mysqlshow `mysql_config --cflags` `mysql_config --libs` -DDBUG_OFF  
[root@Betty mysql_client_test]# ll 
總計 116 
-rw-r--r-- 1 root root   4130 10-25 14:33 client_priv.h 
-rw-r--r-- 1 root root   2124 10-25 15:01 my_default.h 
-rwxr-xr-x 1 root root  66953 10-25 16:23 mysqlshow 
-rw-r--r-- 1 7161 wheel 25393 10-25 15:03 mysqlshow.c 
-rw-r--r-- 1 root root   1686 10-25 15:01 welcome_copyright_notice.h 
[root@Betty mysql_client_test]#

執行 mysql

[root@Betty mysql_client_test]# ./mysqlshow --help 
./mysqlshow  Ver 9.10 Distrib 5.6.10, for Linux (x86_64) 
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 

Oracle is a registered trademark of Oracle Corporation and/or its 
affiliates. Other names may be trademarks of their respective 
owners. 

Shows the structure of a MySQL database (databases, tables, and columns). 

Usage: ./mysqlshow [OPTIONS] [database [table [column]]] 

If last argument contains a shell or SQL wildcard (*,?,% or _) then only 
what's matched by the wildcard is shown. 
If no database is given then all matching databases are shown. 
If no table is given, then all matching tables in database are shown. 
If no column is given, then all matching columns and column types in table 
are shown. 

Default options are read from the following files in the given order: 
/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf  
The following groups are read: mysqlshow client 
The following options may be given as the first argument: 
--print-defaults        Print the program argument list and exit. 
--no-defaults           Don't read default options from any option file, 
                        except for login file. 
--defaults-file=#       Only read default options from the given file #. 
--defaults-extra-file=# Read this file after the global files are read. 
--defaults-group-suffix=# 
                        Also read groups with concat(group, suffix) 
--login-path=#          Read this path from the login file. 
  --bind-address=name IP address to bind to. 
  -c, --character-sets-dir=name  
                      Directory for character set files. 
  --default-character-set=name  
                      Set the default character set. 
  --count             Show number of rows per table (may be slow for non-MyISAM 
                      tables). 
  -C, --compress      Use compression in server/client protocol. 
  -#, --debug[=name]  Output debug log. Often this is 'd:t:o,filename'. 
  --debug-check       Check memory and open file usage at exit. 
  --debug-info        Print some debug info at exit. 
  --default-auth=name Default authentication client-side plugin to use. 
  -?, --help          Display this help and exit. 
  -h, --host=name     Connect to host. 
  -i, --status        Shows a lot of extra information about each table. 
  -k, --keys          Show keys for table. 
  -p, --password[=name]  
                      Password to use when connecting to server. If password is 
                      not given, it's solicited on the tty. 
  --plugin-dir=name   Directory for client-side plugins. 
  -P, --port=#        Port number to use for connection or 0 for default to, in 
                      order of preference, my.cnf, $MYSQL_TCP_PORT, 
                      /etc/services, built-in default (3306). 
  --protocol=name     The protocol to use for connection (tcp, socket, pipe, 
                      memory). 
  -t, --show-table-type  
                      Show table type column. 
  -S, --socket=name   The socket file to use for connection. 
  -u, --user=name     User for login if not current user. 
  -v, --verbose       More verbose output; you can use this multiple times to 
                      get even more verbose output. 
  -V, --version       Output version information and exit. 

Variables (--variable-name=value) 
and boolean options {FALSE|TRUE}  Value (after reading options) 
--------------------------------- ---------------------------------------- 
bind-address                      (No default value) 
character-sets-dir                (No default value) 
default-character-set             auto 
count                             FALSE 
compress                          FALSE 
debug-check                       FALSE 
debug-info                        FALSE 
default-auth                      (No default value) 
host                              (No default value) 
status                            FALSE 
keys                              FALSE 
plugin-dir                        (No default value) 
port                              0 
show-table-type                   FALSE 
socket                            (No default value) 
user                              (No default value) 
[root@Betty mysql_client_test]#

      確實和源碼編譯 MySQL 獲得的 mysqlshow 一致,到此暫時走出了研究 MySQL 客戶端實現的第一步。能夠稍微總結一下了: sql

  • 直接使用 MySQL C API 來編寫程序是阻塞的仍是非阻塞的? 
  • MySQL C API 可以和 libevent 結合在一塊兒麼? 或者說哪些 API 能夠?
  • 是否須要基於 libevent 的 MySQL 協議實現?

上述問題須要綜合總體設計來給結論(讀者本身先思考下)。

=== 未完待續 ===
相關文章
相關標籤/搜索