近期项目需要一个mysql代理服务器,实现mysql协议代理和路由功能,形成简单的mysql集群服务。现成的开源方案是mysql-proxy , 分析功能和源代码后发现跟我们的应用场景不太匹配,于是决定重新实现一个符合需求的mysql代理服务器,考虑到需要完美支持mysql协议,优先选择了libdrizzle库, libdrizzle是开源项目drizzle中的协议库,而drizzle可以看作mysql的分支版本,目前稳定版本是7.1.36 , 下面主要是记录使用libdrizzle中遇到的一些问题。
1. 关于nonblock模式的问题,现代应用服务器典型架构一般是使用reactor/proactor模式的事件驱动模型,如何把libdrizzle和应用服务器的驱动模型很好的结合起来尤其重要, libdrizzle支持nonblock模式,独立实现了事件驱动机制,使用poll监控网络事件,具体在drizzle_con_wait()中实现,然后通过drizzle_con_ready()遍历产生事件的网络连接,即drizzle_con_st对象,该接口难以与通常的网络事件驱动机制配合使用,性能也不太理想,具体用法可参见其自带的样例程序examples/client.cc , 也就是说libdrizzle的驱动模型需要重新封装成跟应用服务器相匹配,才能真正发挥nonblock模式的性能。
2. drizzle_result_st对象初始时一些内部数据没有初始化,容易造成程序崩溃,因此需要修改构造函数,初始化所有内部数据。涉及文件libdrizzle-2.0/structs.h 。相应字段为field, field_buffer,row 。
3. libdrizzle中运行时产生的内部对象都以双链表形式挂接在其上级对象中,例如drizzle_st对象中有个双链表维护其创建的drizzle_con_st对象,类似地,drizzle_con_st对象中有个双链表维护其创建的drizzle_result_st对象,所有的对象通过这种形式级联管理,并且这些对象中保存着上下文相关的状态,这样的实现方便资源管理,防止资源泄露,但在代理服务器中,请求和结果在不断转发过程中会形成大量的内存拷贝,为了减少转发过程中的内存拷贝,需要把drizzle_result_st显式的从drizzle_con_st中移除,当数据发往客户端完成后再删除,因此增加了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 ;
}