支持海量域名的dns架构

环境 操作系统: Redhat 5.2 64位

dns服务器:bind9.5.0-p1

数据库: mysql5.1

1. 缘起

公司前些年成为了域名注册商,起初采用一个zone文件存放一个zone配置的传统方式。后了解zone的增长量将会非常大,在n个百万级。在进行了测试和使用一段时间后,发现当zone数量巨大的情况下,采用传统的zone文件存放zone配置,存在着很大的问题。如将所有域名都放在同一服务器上,在需要重新启动bind时,花费的时间惊人,从下图看出当zone的数量达到30万时,载入时间已经需要近1小时,这显然是不能接受的

 

后经过权衡,决定以10万为分界,毎10万域名使用一主一辅2台服务器。这种结构尽管有一些不方便,但因为传统的方式稳定性好、查询效率高,所以也用了一段时间。然而当zone的数量到了60多万时,服务器达到了14台,终于觉得不能容忍这种方式了,因为一、太浪费服务器了,二、管理非常不方便,于是乎决心寻找替代的方案

2. 方案选择

在查找一些资料之后,毋庸置疑,基于bind的DLZ(dynamic load zone)是首选。但在DLZ支持的诸多后台数据库中,并不是起初就选择mysql的。bind的查询效率可以达到2万~3万每秒,在DLZ官方,性能评测只有Berkerly DB的查询效率可以达到4000至12000 bps每秒,比较接近bind的原始查询效率,而其他的mysql什么的都只有600~800每秒,Berkerly DB的优势非常明显,因此起初试图使用Berkerly DB作为后台数据库,但最终还是选择了mysql,主要原因如下:

  • 使用Berkerly DB的资料非常少
  • 使用Berkerly DB不支持类似mysql的sql语句,而仅仅支持api接口,测试和使用门槛比较高
  • 没有熟悉Berkerly DB的人员支持,而mysql有同部门的DBA支持 = 性能问题 =

在初步确定采用mysql作为数据库之后,必需要解决查询效率的问题,否则就很难真正投入生产环境。mysql作为后台的查询效率经测试在600-800之间,而我们预期的查询效率必需要达到3k~4k。该结构为什么会慢呢?主要原因就是采用mysql作为后台数据库时,bind不能起用多线程,只能采用单进程。而毎查询一个域名需要执行3~5条sql,所有的sql只能串行处理,所以效率才这么低。解决办法:

  • 修改DLZ源码,将单进程改为多线程

该方法经一位熟悉C的同事验证,不可行。(也许CU有大虾能搞定的,那就更方便易行了)

  • 在bind和mysql之间加一层cache

在我们的结构中,zone数量非常大,单个域名在短时间被重复查询的几率并不高,分析认为该方法不是特别适合我们的结构,因此未进行测试

  • 人造“多线程

查询效率低的关键原因是串行,因此我们试图人为的实现并行,经过测试后发现可以通过起多个named进程的方式,实现该想法。最终是服务器起8个地址,每个地址单独起一个named。起8个named之后的查询效率如下图,我们可以看出,单个named的查询效率随着named数量的增加从700多降至400,特别是到后期下降趋势很不明显。总体性能从700升至3200左右,两台dns服务器可达到6000多,完全可以满足我们的需要:

 

3. 框架结构

这个系统的结构最前端是两台F5的负载均衡设备(这原来就有),后面是两台dns服务器,每台起8个named进程,分别连至后台的mysql数据库。F5的每个vip对应每台dns服务器4个进程,这样整个系统没有任何单点。任何一台设备down了bouquet不影响使用。结构图如下:

 

4. 安装配置

4.1. 首先安装mysql(不然bind找不到mysql,无法安装mysql的dlz插件)

4.1.1. 创建OS帐号

#添加mysql组和用户,之所以指定为601,主要是为了方便各台服务器之间权限统一

  1. groupadd -g 601 mysql   
  2. useradd -c “mysql software owner” -g mysql -u 601 mysql 

4.1.2. 目录结构准备

#编辑自己的配置文件my.cnf和log以及innodb的相关目录

  1. mkdir /usr/local/mysql 
  2. mkdir /usr/local/mysql/sock 
  3. mkdir /usr/local/mysql/log  
  4.  
  5. su - mysql 
  6. mkdir /home/mysql/mysqldata 
  7. mkdir /home/mysql/mysqldata/binlog 
  8. mkdir /home/mysql/mysqldata/mydata 
  9. mkdir /home/mysql/mysqldata/innodb_ts 
  10. mkdir /home/mysql/mysqldata/innodb_log 
  11. mkdir /home/mysql/mysqldata/tmpdir  
  12.  
  13. exit   
  14. mkdir /data 
  15. ln -s /home/mysql/mysqldata /data/mysqldata  
  16.  
  17. chown -R mysql:mysql /usr/local/mysql/log 
  18. chown -R mysql:mysql /usr/local/mysql/sock 
  19. chown -R mysql:mysql /data/mysqldata 
  20. chown -R mysql:mysql /data/mysqldata/mydata 
  21. chown -R mysql:mysql /data/mysqldata/binlog 
  22. chown -R mysql:mysql /data/mysqldata/innodb_ts 
  23. chown -R mysql:mysql /data/mysqldata/innodb_log 
  24. chown -R mysql:mysql /data/mysqldata/tmpdir  

4.1.3. 编译安装源码

  1. make clean 

#这里的config参数可以根据数据库相关需求稍作调整

  1. ./configure –prefix=/usr/local/mysql \  
  2.  –without-debug \  
  3.  –without-bench \  
  4.  –disable-shared \  
  5.  –enable-thread-safe-client \  
  6.  –enable-assembler \  
  7.  –enable-profiling \  
  8.  –with-mysqld-ldflags=-all-static \  
  9.  –with-client-ldflags=-all-static \  
  10.  –with-charset=latin1 \  
  11.  –with-extra-charset=utf8,gbk \  
  12.  –with-innodb \  
  13.  –with-csv-storage-engine \  
  14.  –with-federated-storage-engine \  
  15.  –with-mysqld-user=mysql \  
  16.  –without-embedded-server \  
  17.  –with-server-suffix=-community \  
  18.  –with-unix-socket-path=/usr/local/mysql/sock/mysql.sock \   
  19. with-mysqld-libs=-lmtmalloc \  
  20.  
  21. make make install 

#准备my.cnf文件需要注意的几个目录配置:

  1. log-error=/usr/local/mysql/log/error.log   
  2. log_slow_queries=/usr/local/mysql/log/slow_query.log   
  3. datadir=/data/mysqldata/mydata tmpdir=/data/mysqldata/tmpdir   
  4. bin-log=/data/mysqldata/binlog/mysql-bin   
  5. innodb_data_home_dir=/data/mysqldata/innodb_ts   
  6. innodb_log_group_home_dir=/data/mysqldata/innodb_log 

其他相关参数进行针对性调整将准备好的my.cnf配置文件cp一份到/etc/my.cnf

创建系统表并修改目录权限

  1. cd /usr/local/mysql  
  2. bin/mysql_install_db –user=mysql –socket=/usr/local/mysql/sock/mysql.sock   
  3. chown -R root .   
  4. chgrp -R mysql .   
  5. chown -R mysql sock   
  6. chown -R mysql log 

4.1.4. 启动

  1. bin/mysqld_safe –socket=/usr/local/mysql/sock/mysql.sock –user=mysql & 

4.2. 安装bind

4.2.1. 创建用户

  1. useradd -d /etc/namedb -s /bin/false named 

4.2.2. 创建var目录并修改权限

  1. mkdir -p /var/named 
  2. chown -R named:named /etc/namedb 
  3. chown -R named:named /var/named 

4.2.3. 编译安装

  1. tar -xzvf bind-9.5.0-p1.tar.gz   
  2. ./configure –prefix=/opt/named.9.5.0-p1 –sysconfdir=/etc/namedb –with-dlz-mysql=yes –enable-largefile 

 注:采用mysql做后台数据库,千万不能用–enable-threads选项启用多线程,网上有一些朋友使用mysql做后台,谈到bind会莫名中断服务,大部分都是因为打开了多线程。

4.2.4. 修改/etc/init.d/named文件

关键部分如下:

  1. [ -f /opt/named/sbin/named ] || exit 0  
  2.  
  3. [ -f /etc/namedb/named.conf.11 ] || exit 0  
  4.  
  5. # See how we were called.  
  6. case "$1" in  
  7.   start)  
  8.         # Start daemons.  
  9.       echo -n "Starting named: "  
  10.       daemon /opt/named/sbin/named -c /etc/namedb/named.conf.11 -u named  
  11.       daemon /opt/named/sbin/named -c /etc/namedb/named.conf.12 -u named  
  12.       daemon /opt/named/sbin/named -c /etc/namedb/named.conf.13 -u named  
  13.       daemon /opt/named/sbin/named -c /etc/namedb/named.conf.14 -u named  
  14.       daemon /opt/named/sbin/named -c /etc/namedb/named.conf.15 -u named  
  15.       daemon /opt/named/sbin/named -c /etc/namedb/named.conf.16 -u named  
  16.       daemon /opt/named/sbin/named -c /etc/namedb/named.conf.17 -u named  
  17.       daemon /opt/named/sbin/named -c /etc/namedb/named.conf.18 -u named 

4.2.5. named.conf配置

关键部分如下,替代了原来对每一个zone的配置:

  1. dlz "Mysql zone" {  
  2.    database "mysql  
  3.    {host=localhost dbname=dns user=dns pass=12345678}  
  4.    {SELECT zone FROM records WHERE zone = '%zone%'}  
  5.    {SELECT ttl, type, mx_priority, data  
  6.     FROM records  
  7.     WHERE zone = '%zone%' AND host = '%record%' AND type <> 'SOA' AND type <> 'NS'}  
  8.    {SELECT ttl, type, data, primary_ns, resp_contact, serial, refresh, retry, expire, minimum  
  9.     FROM records  
  10.     WHERE zone = '%zone%' AND type='NS'}  
  11.    {SELECT ttl, type, host, mx_priority, data, resp_contact, serial, refresh, retry, expire, minimum  
  12.     FROM records  
  13.     WHERE zone = '%zone%' AND type <> 'NS'}";  
  14. }; 

5. 可扩展性

该结构的可扩展性非常好,可采用的方式如下:

  • 在单台服务器上增加named的数量
  • 增加物理服务器,作为新节点添加到负载均衡设备里
  • 增加授权的dns服务器,例如:原授权dns服务器为ns1.test.com,ns2.test.com,我们可将授权dns增加到4台为ns1.test.com,ns2.test.com、ns3.test.com,ns4.test.com,通过在ns3.test.com,ns4.test.com后搭建同样的架构系统,可大大增加系统的查询能力,同时将该架构放置在不同的地理位置,还可以实现dns的灾备、冗余。
  • 如果mysql的压力大,也随时可以扩充mysql的节点。分担mysql的压力。

6. 使用现状

目前dns上的zone数量为约90万,查询速率为500,系统的load不到1,启动可以在秒级完成,并且已稳定运行近两个月。现在的架构,dns和mysql在同一物理机上,仅仅需要两台服务器,而这个数据量按原来的架构需要18台服务器,同时维护非常不便。

注:

1、dns一开始会有启动报错:

  1. #service named start  
  2. Starting named: /opt/named/sbin/named: error while loading shared libraries: 

2、libmysqlclient.so.15: cannot open shared object file: No such file or directory                     [FAILED]
  解决办法:
  a、编辑/etc/ld.so.conf 将mysql的lib目录加入

  1. include ld.so.conf.d/*.conf  
  2. usr/local/mysql/lib/mysql/ 

  b、执行ldconfig 命令

3、dns是否关闭递归查询,对该结构的查询效率有一定影响。因为关闭递归会少执行n多sql语句。

本日志由 flyinweb 于 2009-09-25 15:54:48 发表,目前已经被浏览 3902 次,评论 0 次;

作者添加了以下标签: DNS架构

引用通告:http://www.517sou.net/Article/263/Trackback.ashx

评论订阅:http://www.517sou.net/Article/263/Feeds.ashx

评论列表

    暂时没有评论
(必填)
(必填,不会被公开)