关于bind-dlz介绍:http://bind-dlz.sourceforge.net/
DLZ(Dynamically Loadable Zones)与传统的BIND9不同,BIND的不足之处:
而Bind-dlz 即将帮你解决这些问题,对Zone文件操作也更方便了,直接对数据库操作,可以很方便扩充及开发管理程序。
bind-dlz的相关配置就不说了,网上一大堆,推荐两个:
bind9+dlz+mysql配置好正常使用没什么问题,但是当使用了一段时间(都是隔夜)之后再次解析之前的域名发现解析不了,查看日志/var/log/messages,发现如下错误信息:
localhost named[42406]: mysql driver unable to return result set for findzone query
经查询资料得知是因为dlz在连接mysql之后,由于连接的空闲时间达到mysql的最大空闲时间,被mysql强行断开导致无法再从mysql获取数据。关键是DLZ在断开之后不会重连,这就不得不重启named服务重新与mysql建立连接了。
但明显这个办法不靠谱,想到的解决方案大概有下面几种:
更换数据库暂时不考虑;修改mysql的wait_timeout也不能解决根本问题;第3个就不说了;第四个我试了下,写了一个脚本定时请求bind解析域名,想让连接不超时,但是最后证明这种办法不行,不知道是不是方式不对;最后一种是实在没有办法了,硬着头皮打开了源码。。。
。。。好吧,没有想象中的那么难,找到bind-9.6.0-P1/contrib/dlz/drivers/dlz_mysql_driver.c,大致读了下,配合资料 C中MySQL自动重新连接(部分zz),在dlz_mysql_driver.c的mysql_create函数中加入了重连的代码,完整函数内容:
/*% * create an instance of the driver. Remember, only 1 copy of the driver's * code is ever loaded, the driver has to remember which context it's * operating in. This is done via use of the dbdata argument which is * passed into all query functions. */static isc_result_tmysql_create(const char *dlzname, unsigned int argc, char *argv[], void *driverarg, void **dbdata){ isc_result_t result; dbinstance_t *dbi = NULL; char *tmp = NULL; char *dbname = NULL; char *host = NULL; char *user = NULL; char *pass = NULL; char *socket = NULL; int port; MYSQL *dbc; char *endp; int j; unsigned int flags = 0; //新增部分:定义了一个value char value = 1; UNUSED(driverarg); UNUSED(dlzname); ... tmp = getParameterValue(argv[1], "space="); if (tmp != NULL) { if (strcasecmp(tmp, "ignore") == 0) flags = flags | CLIENT_IGNORE_SPACE; isc_mem_free(ns_g_mctx, tmp); } //新增部分:重连的代码 /* reconnect to mysql */ result = mysql_options((MYSQL *)dbi->dbconn, MYSQL_OPT_RECONNECT, (char *)&value); if( result != 0 ) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "mysql_options reconnect failed!"); result = ISC_R_FAILURE; goto full_cleanup; } dbc = NULL; host = getParameterValue(argv[1], "host="); user = getParameterValue(argv[1], "user="); pass = getParameterValue(argv[1], "pass="); socket = getParameterValue(argv[1], "socket="); for (j=0; dbc == NULL && j < 4; j++) dbc = mysql_real_connect((MYSQL *) dbi->dbconn, host, user, pass, dbname, port, socket, flags); /* let user know if we couldn't connect. */ if (dbc == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "mysql driver failed to create " "database connection after 4 attempts"); result = ISC_R_FAILURE; goto full_cleanup; } ...}
附上mysql关于c语言的官方文档: https://dev.mysql.com/doc/refman/5.6/en/mysql-real-connect.html
改完之后重新编译安装就好了,经过测试,第二天来发现域名仍然可以正常解析。问题暂时解决,后面再观察一下。