ipset是应对大规模ip黑名单性能最优方案,因其用哈希等高效结构实现o(1)查找,而纯iptables线性匹配10万规则时最坏需遍历全部,显著拖慢吞吐、增加cpu负载。

直接用 iptables -s 加十万条规则会拖垮服务器——每次数据包进来都要平均比对 5 万次,CPU 占用飙升、吞吐骤降、连接延迟明显。真正可行的方案是用 ipset 把所有 IP 归入一个高效集合,iptables 只需一条规则查一次哈希表,匹配速度几乎不随数量增长。
选对类型和参数,避免运行时溢出
创建集合时必须显式指定容量,否则默认仅支持 65536 个元素,十万 IP 必然报错 “Set is full”:
-
单 IP 黑名单:用
hash:ip类型,查询最快,适合纯 IPv4 地址列表ipset create blacklist hash:ip maxelem 120000 -
含网段的黑名单:改用
hash:net,能同时容纳192.168.1.1和203.0.113.0/24ipset create blacklist hash:net maxelem 120000 - 可额外加
hashsize 4096优化哈希桶数量,减少冲突(非必需但推荐)
批量导入要快且稳,别用循环 add
逐行执行 ipset add 会反复 fork shell 进程,十万次调用极慢还容易超时。正确做法是生成标准 restore 格式文件后一次性加载:
- 准备文本
blacklist.ipset,内容形如:create blacklist hash:ip maxelem 120000add blacklist 1.1.1.1add blacklist 2.2.2.2
……(每行一个add) - 执行:
ipset restore -f blacklist.ipset - 导入后立刻验证:
ipset list blacklist | head -n 5看前几条是否在,ipset list blacklist | grep "Number of entries"确认总数
iptables 规则位置和模块不能错
即使集合建好了,iptables 引用不对也完全不生效:
- 必须加载
ip_set和ip_set_hash_ip(或ip_set_hash_net)内核模块:modprobe ip_set_hash_ip,并写入/etc/modules持久化 - 规则中必须带
-m set模块,否则报错 “No chain/target/match by that name”:iptables -I INPUT -m set --match-set blacklist src -j DROP -
-I INPUT表示插入最前面;若已有-j ACCEPT在它之前,这条 DROP 就永远不触发
动态更新不丢包,靠 swap 实现原子切换
直接 ipset flush blacklist 再重加,清空瞬间所有黑名单 IP 都会放行——攻击流量就趁虚而入。安全做法是双集合 + swap:
- 后台构建新集合:
ipset create blacklist_new hash:ip maxelem 120000ipset restore -f new_blacklist.ipset - 毫秒级原子切换:
ipset swap blacklist blacklist_new - 旧集合自动变空,立即销毁释放内存:
ipset destroy blacklist_new - 注意:两个集合类型和 family(inet/inet6)必须完全一致,否则 swap 失败











