近期項(xiàng)目需要一個(gè)mysql代理服務(wù)器,實(shí)現(xiàn)mysql協(xié)議代理和路由功能,形成簡單的mysql集群服務(wù)。現(xiàn)成的開源方案是mysql-proxy , 分析功能和源代碼后發(fā)現(xiàn)跟我們的應(yīng)用場景不太匹配,于是決定重新實(shí)現(xiàn)一個(gè)符合需求的mysql代理服務(wù)器,考慮到需要完美支持mysql協(xié)議,優(yōu)先選擇了libdrizzle庫, libdrizzle是開源項(xiàng)目drizzle中的協(xié)議庫,而drizzle可以看作mysql的分支版本,目前穩(wěn)定版本是7.1.36 , 下面主要是記錄使用libdrizzle中遇到的一些問題。
1. 關(guān)于nonblock模式的問題,現(xiàn)代應(yīng)用服務(wù)器典型架構(gòu)一般是使用reactor/proactor模式的事件驅(qū)動(dòng)模型,如何把libdrizzle和應(yīng)用服務(wù)器的驅(qū)動(dòng)模型很好的結(jié)合起來尤其重要, libdrizzle支持nonblock模式,獨(dú)立實(shí)現(xiàn)了事件驅(qū)動(dòng)機(jī)制,使用poll監(jiān)控網(wǎng)絡(luò)事件,具體在drizzle_con_wait()中實(shí)現(xiàn),然后通過drizzle_con_ready()遍歷產(chǎn)生事件的網(wǎng)絡(luò)連接,即drizzle_con_st對象,該接口難以與通常的網(wǎng)絡(luò)事件驅(qū)動(dòng)機(jī)制配合使用,性能也不太理想,具體用法可參見其自帶的樣例程序examples/client.cc , 也就是說libdrizzle的驅(qū)動(dòng)模型需要重新封裝成跟應(yīng)用服務(wù)器相匹配,才能真正發(fā)揮nonblock模式的性能。
2. drizzle_result_st對象初始時(shí)一些內(nèi)部數(shù)據(jù)沒有初始化,容易造成程序崩潰,因此需要修改構(gòu)造函數(shù),初始化所有內(nèi)部數(shù)據(jù)。涉及文件libdrizzle-2.0/structs.h 。相應(yīng)字段為field, field_buffer,row 。
3. libdrizzle中運(yùn)行時(shí)產(chǎn)生的內(nèi)部對象都以雙鏈表形式掛接在其上級對象中,例如drizzle_st對象中有個(gè)雙鏈表維護(hù)其創(chuàng)建的drizzle_con_st對象,類似地,drizzle_con_st對象中有個(gè)雙鏈表維護(hù)其創(chuàng)建的drizzle_result_st對象,所有的對象通過這種形式級聯(lián)管理,并且這些對象中保存著上下文相關(guān)的狀態(tài),這樣的實(shí)現(xiàn)方便資源管理,防止資源泄露,但在代理服務(wù)器中,請求和結(jié)果在不斷轉(zhuǎn)發(fā)過程中會形成大量的內(nèi)存拷貝,為了減少轉(zhuǎn)發(fā)過程中的內(nèi)存拷貝,需要把drizzle_result_st顯式的從drizzle_con_st中移除,當(dāng)數(shù)據(jù)發(fā)往客戶端完成后再刪除,因此增加了drizzle_result_detach()接口,用于從drizzle_con_st對象中移除drizzle_result_st對象 , 涉及文件libdrizzle-2.0/result.h , libdrizzle-2.0/result.cc 。
void drizzle_result_detach(drizzle_result_st *result)
{
if (result->con)
{
result->con->result_count--;
if (result->con->result_list == result)
result->con->result_list= result->next;
}
if (result->prev)
result->prev->next= result->next;
if (result->next)
result->next->prev= result->prev;
result->con = NULL ;
result->prev = NULL ;
result->next = NULL ;
}