ipset是处理大规模IP黑名单的最优方案,因其哈希结构实现O(1)查找,而纯iptables线性匹配十万规则最坏需遍历五万次,导致CPU飙升、延迟激增;应选用匹配的hash:ip或hash:net类型,显式设置hashsize与maxelem,并用restore批量导入及swap原子更新。

直接用 iptables -s 加十万条规则会严重拖慢系统——每次匹配都要线性扫描,平均查五万次,CPU飙升、延迟激增,还容易触发 conntrack 抖动。真正高效的做法是用 ipset 构建哈希集合,让 iptables 只做一次 O(1) 查表。
选对类型并设足容量
黑名单若全是单个 IPv4 地址,用 hash:ip;若含网段(如 192.0.2.0/24),必须改用 hash:net。类型选错会导致无法匹配或内存浪费。创建时必须显式指定容量:
-
maxelem至少比实际 IP 数多 10%(如 10 万条设为120000) -
hashsize建议设为略大于元素数的 2 的幂(如16384或65536),避免哈希冲突降速
示例命令:ipset create blacklist hash:ip hashsize 65536 maxelem 120000
批量导入不走循环,用 restore 一步到位
别用 while read ip; do ipset add ...——每行一次 shell 启动和系统调用,十万条可能耗几分钟。正确方式是生成标准 restore 文件:
- 文件开头写
create blacklist hash:ip hashsize 65536 maxelem 120000 - 后续每行
add blacklist 192.0.2.1(不能有空行或注释) - 执行
ipset restore -f blacklist.ipset,几秒完成
导入后可用ipset test blacklist 192.0.2.1随机抽检验证
iptables 规则要放对位置且加载正确模块
- 必须加载内核模块:
modprobe ip_set_hash_ip,并写入/etc/modules持久化 - 规则必须插在
INPUT或FORWARD链顶部:iptables -I INPUT -m set --match-set blacklist src -j DROP -
-m set不可省略,否则报错No chain/target/match by that name - 若日志中出现
::ffff:192.0.2.1这类 IPv4 映射地址,需先清洗再导入,IPv4 集合不匹配 IPv6
零停机更新,用 swap 替换旧集合ipset flush + ipset add 会导致清空瞬间所有黑名单 IP 全部通行。安全做法是:
- 后台构建新名单,存为
blacklist_new.ipset,执行ipset restore -f blacklist_new.ipset - 原子切换:
ipset swap blacklist blacklist_new(毫秒完成,无放行窗口) - 切完立刻
ipset destroy blacklist_new释放内核资源
注意:两个集合类型和参数必须完全一致,否则 swap 报错Set cannot be swapped: different types


















