使用gprof工具,可以测出dhcp的性能瓶颈在mdb.c中的lease_enqueue函数。该函数的功能就是维护地址池内部的不同状态下的地址链表,这些链表都必须根据时间排序的。目的是每次遍历都从最老的lease开始。

排序代码:

/* Insertion sort the lease onto the appropriate queue. */
for (; lp ; lp = lp->next) {
    if (lp -> sort_time >= comp -> sort_time)
        break;
    prev = lp;
}

假设,我们配置了一个有几十万个IP的地址池,并且这些地址都是可分配的地址。那么它们都会被放到pool->free的链表中,每次维护链表进行排序的时候就会耗费很长时间。

很可惜,很多人发现这个问题,并且也反应给isc-dhcp官方,但是貌似没有得到什么好的解决办法。我也折腾了一段时间,偶然想到这些状态的地址链表都是被地址池包含的,如果控制每个地址池内部的地址个数,是不是会有情况?

传统的dhcpd.conf文件:

subnet 192.0.0.0 mask 192.255.255.255 {
    option routers 192.0.0.1;
    default-lease-time 600;
    max-lease-time 7200;
    pool {
        range 192.0.0.1 192.4.255.255
    }
}

如果这样配置,分配地址的并发性能只能十几个每秒。

我把这个大地址池拆分成小地址池,每个小地址池内部包含1024个地址,配置文件改为:

subnet 192.0.0.0 mask 192.255.255.255 {
    option routers 192.0.0.1;
    default-lease-time 600;
    max-lease-time 7200;
    pool {
        range 192.0.0.1 192.0.3.255
    }
    pool {
        range 192.0.4.0 192.0.7.255
    }
    pool {
        range 192.0.8.0 192.0.11.255
    }
    ……
}

果然,并发性能提高了很多,能达到每秒500个左右。

另外,把lease文件放到共享内存中也能提高不少性能,毕竟对内存的读写比硬盘快多了。


(同时也依赖服务器的硬件配置,不过这个影响不是致命的。呵呵……)