Bash 通过上下键更有效的查找历史命令

我们知道在 bash 里,可以通过 “上下” 键来浏览最近执行过的命令历史纪录(history),我们也知道如果历史纪录太多的话可以通过 ctrl+r 来查找命令或者通过 history 命令来浏览历史命令。我们不知道的是(也许只有本人不知道~),还有一种神奇的办法可以更准确、有效的在历史命令纪录中查找自己想要的命令。

在自己的用户主目录(home directory)新建一个 .inputrc 文件:

$ vi ~/.inputrc
"\e[A": history-search-backward
"\e[B": history-search-forward
set show-all-if-ambiguous on
set completion-ignore-case on

退出 bash 后重新登陆,敲打一个字母或者几个字母,然后 “上下” 键,就会看到以这个字母搜索到的完整命令行。如果搜索到几个类似命令,通过上下键来切换,有点像 ctrl+r,但是更好用。

DMTCP 分布式多线程检查点工具

高性能计算/分布式计算等大量计算需要程序运行几天、几周甚至几个月,如果期间因为电力或者不可避免的问题导致程序中断会浪费大量的时间和人力,还有超级计算机在这段时间里运行的电力成本。我们没有遇到过电力问题,不过我们最近遇到的场景是实验室需要做强制安全检查,要求关闭所有电脑,所以我们需要一种工具能设置断点暂停程序、把状态保存到硬盘、再按照要求恢复,就像程序员用 IDE 调试程序一样,设置断点、单步跟踪(或恢复运行)。

在多主机、多线程的复杂分布式计算环境,给程序设置断点不是一件容易的事情,因为程序的某部分可能在其他主机上运行。DMTCP: Distributed MultiThreaded CheckPointing 是我们目前正在考察的一个工具之一,我们喜欢它的一个原因是它不需要修改 Linux 内核,不依赖内核和内核模块。

安装

先安装一些编译 DMTCP 需要用到的软件包:

$ sudo apt-get install build-essential

下载 DMTCP 源代码后,解压、配置、编译、安装:

$ wget http://ufpr.dl.sourceforge.net/project/dmtcp/dmtcp/1.2.7/dmtcp-1.2.7.tar.gz
$ tar zxvf dmtcp-1.2.7.tar.gz
$ cd dmtcp-1.2.7
$ make
$ sudo make install

我们先来看一个例子程序,转到 dmtcp-1.2.7 里的 test 目录运行 dmtcp1,这个例子很简单,按照顺序输出 1 2 3 … 数字:

$ cd test
$ ./dmtcp1
  1   2   3   4   5   6 ^C

接下来我们要试验的是,中断这个例子程序,然后看看能不能恢复它。步骤是:

  1. 启动控制端 dmtcp_coordinator;
  2. 用 dmtcp_checkpoint 运行这个 dmtcp1 程序;
  3. 强制中断 dmtcp1;
  4. 恢复运行 dmtcp1.

使用

开另外一个窗口或者 screen 运行控制端 dmtcp_coordinator,用 l 查看当前节点状态:

$ dmtcp_coordinator
dmtcp_coordinator starting...
    Port: 7779
    Checkpoint Interval: disabled (checkpoint manually instead)
    Exit on last client: 0
Type '?' for help.

?
COMMANDS:
  l : List connected nodes
  s : Print status message
  c : Checkpoint all nodes
  i : Print current checkpoint interval
      (To change checkpoint interval, use dmtcp_command)
  f : Force a restart even if there are missing nodes (debugging only)
  k : Kill all nodes
  q : Kill all nodes and quit
  ? : Show this message

l
Client List:
#, PROG[PID]@HOST, DMTCP-UNIQUEPID, STATE
[7845] NOTE at dmtcp_coordinator.cpp:1039 in onConnect; REASON='worker connected'
     hello_remote.from = b51cf8-7846-516fbedc(-1)

然后重新用 dmtcp_checkpoint 运行 dmtcp1 这个例子程序:

$ dmtcp_checkpoint ./dmtcp1
dmtcp_checkpoint (DMTCP + MTCP) 1.2.7
Copyright (C) 2006-2011  Jason Ansel, Michael Rieker, Kapil Arya, and
                                                       Gene Cooperman
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; see COPYING file for details.
(Use flag "-q" to hide this message.)

  1   2   3

回到控制端,l 一下就会看到多了条结点状态,dmtcp1 程序[进程号 7846]运行在主机名为 vpseedev 的主机上。

l
Client List:
#, PROG[PID]@HOST, DMTCP-UNIQUEPID, STATE
1, dmtcp1[7846]@vpseedev, b51cf8-7846-516fbedc, RUNNING

现在我们在控制端设置一个检查点(checkpoint),用 c 命令:

c
[7845] NOTE at dmtcp_coordinator.cpp:1315 in startCheckpoint; REASON='starting checkpoint, suspending all nodes'
     s.numPeers = 1
[7845] NOTE at dmtcp_coordinator.cpp:1317 in startCheckpoint; REASON='Incremented Generation'
     UniquePid::ComputationId().generation() = 1
[7845] NOTE at dmtcp_coordinator.cpp:643 in onData; REASON='locking all nodes'
[7845] NOTE at dmtcp_coordinator.cpp:678 in onData; REASON='draining all nodes'
[7845] NOTE at dmtcp_coordinator.cpp:684 in onData; REASON='checkpointing all nodes'
[7845] NOTE at dmtcp_coordinator.cpp:694 in onData; REASON='building name service database'
[7845] NOTE at dmtcp_coordinator.cpp:713 in onData; REASON='entertaining queries now'
[7845] NOTE at dmtcp_coordinator.cpp:718 in onData; REASON='refilling all nodes'
[7845] NOTE at dmtcp_coordinator.cpp:747 in onData; REASON='restarting all nodes'
[7845] NOTE at dmtcp_coordinator.cpp:919 in onDisconnect; REASON='client disconnected'
     client.identity() = b51cf8-7846-516fbedc

然后用 Ctrl + c 强制中断这个正在运行的 dmtcp1:

$ dmtcp_checkpoint ./dmtcp1
dmtcp_checkpoint (DMTCP + MTCP) 1.2.7
Copyright (C) 2006-2011  Jason Ansel, Michael Rieker, Kapil Arya, and
                                                       Gene Cooperman
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; see COPYING file for details.
(Use flag "-q" to hide this message.)

  1   2   3   4   5   6   7   8 ^C

这样在当前目录 test 下会生成一个临时文件用来保存程序镜像(稍后会看到就是通过这个文件来恢复程序的):

$ ls -l ckpt_dmtcp1_b51cf8-7846-516fbedc.dmtcp
-rw------- 1 vpsee vpsee 2532431 Apr 18 09:37 ckpt_dmtcp1_b51cf8-7846-516fbedc.dmtcp

用 dmtcp_restart 恢复就会看到 dmtp1 这个例子程序(从它中断的地方)继续运行了:

$ dmtcp_restart ckpt_dmtcp1_b51cf8-7846-516fbedc.dmtcp
dmtcp_checkpoint (DMTCP + MTCP) 1.2.7
Copyright (C) 2006-2011  Jason Ansel, Michael Rieker, Kapil Arya, and
                                                       Gene Cooperman
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; see COPYING file for details.
(Use flag "-q" to hide this message.)

  9  10  11  12 ^C

DMTCP 甚至允许我们把运行了一半的程序暂停、保存到硬盘、拷贝到其他服务器上、继续运行,很酷吧~

Xen 半虚拟化安装 NetBSD 虚拟机(domU)

很久以前我们开始提供 NetBSD 的 VPS,期间陆续有朋友写信询问怎么制作 NetBSD/FreeBSD 的半虚拟化(PV)Xen 镜像,今天以安装最新的 NetBSD 6.0.1 版本为例演示一下,随便说一下制作 FreeBSD PV 虚拟机方法是类似的。Xen 全虚拟化方式(HVM)安装 NetBSD 虚拟机就不说了,和安装其他操作系统 Linux, Windows 差不多,毕竟全虚拟化不用考虑内核,安装要简单得多。考虑到性能,半虚拟化依然是 Xen 的强项,所以我们的 VPS 都是采用半虚拟化的,不过随着硬件的发展和 CPU 厂商的大力支持,半虚拟化的优势正渐渐消失。

这里演示的是安装 NetBSD domU,如果想了解安装 NetBSD dom0 的话看这里:在 NetBSD 上安装和配置 Xen.

准备

新建一个目录,然后下载一些东西,netbsd-INSTALL_XEN3_DOMU.gz 是安装 NetBSD 时候用的内核,netbsd-XEN3_DOMU.gz 是运行 NetBSD 用的内核,不要弄混了;NetBSD-6.0.1-amd64.iso 是我们需要的安装光盘。

$ mkdir netbsd
$ cd netbsd

$ wget http://ftp.netbsd.org/pub/NetBSD/NetBSD-6.0.1/iso/NetBSD-6.0.1-amd64.iso

$ wget http://ftp.netbsd.org/pub/NetBSD/NetBSD-6.0.1/amd64/binary/kernel/netbsd-INSTALL_XEN3_DOMU.gz
$ wget http://ftp.netbsd.org/pub/NetBSD/NetBSD-6.0.1/amd64/binary/kernel/netbsd-XEN3_DOMU.gz

安装

首先制作一个大小为 5GB 的硬盘:

$ dd if=/dev/zero of=netbsd.disk bs=1024k count=1 seek=5000

然后新建一个 Xen domU 配置文件,并输入以下内容,:

$ vi netbsd
name = "netbsd"
memory = "256"
kernel = "/home/vpsee/netbsd/netbsd-INSTALL_XEN3_DOMU.gz"
disk = [ 'file:/home/vpsee/netbsd/netbsd.disk,xvda,w', 'file:/home/vpsee/netbsd/NetBSD-6.0.1-amd64.iso,ioemu:hdc:cdrom,r' ]
vif = [ 'bridge=xenbr0' ]
vcpus = "1"

使用 root 帐号启动这个名为 netbsd 的虚拟机开始 NetBSD 安装过程,这一步需要注意的是在选择安装介质的时候选择从 CD-ROM 安装并使用设备名 xbd0a (device [xbd1a]: xbd0a):

$ su

# xm create netbsd -c

NetBSD 安装界面如下,顺着屏幕提示安装即可,没有难度:

google apps directory sync

安装完毕后关闭这个虚拟机,修改 netbsd 的 Xen 配置文件,然后用新的配置文件启动虚拟机:

# xm destroy netbsd

# vi netbsd
name = "netbsd"
memory = "256"
kernel = "/home/vpsee/netbsd/netbsd-XEN3_DOMU.gz"
disk = [ 'file:/home/vpsee/netbsd/netbsd.disk,xvda,w' ]
vif = [ 'bridge=xenbr0' ]
vcpus = "1"

# xm create netbsd
Using config file "./netbsd".
Started domain netbsd

虚拟机启动后用 xm list 确认一下,然后就可以从控制台登陆 NetBSD 虚拟机了:

# xm list
Name                                      ID Mem(MiB) VCPUs State   Time(s)
Domain-0                                   0     1024     4 r----- 279689.0
netbsd                                   242      256     1 -b----      0.6

# xm console netbsd

剩下的配置 NetBSD 环境、IP 地址等这里就不用赘述了~

迁移 LDAP 用户到 Google Apps 平台

人手和精力不足的情况下自己维护邮件服务器实在是件头疼的事情,我们打算把这件吃力不讨好的事交给 Google,有免费的 Google Apps for Education 为啥要自己弄呢?Gmail 要比自己搭建的 SquirrelMail 和 roundcube 界面好用多了,而且还有免费的 Google Docs, Google Drive, Google Chat 可用,非常适合我们现在的情况。

我们的用户信息都保存在一台 LDAP 服务器上,要把全部用户信息(用户名、密码、Email、电话等)迁移到 Google Apps 的话需要迁移工具(没人想手动输入500个用户和电话!)。自己用 Python-LDAP 和 Google Apps Administrative APIs 写个 LDAP 到 Google Apps 的转换工具应该不难,不过要更懒一点,找现成工具。。。

Google 为帮助我们这些懒人和企业用户把数据迁到云端开发了不少工具,Google Apps Directory Sync 正是我们要找到,一个用于同步 LDAP 活动目录到 Google Apps 的好工具。

步骤

1、首先登陆到 Google Apps 平台,在自己帐号里的 Domain settings 的 User settings 页面选择 “Enable provisioning API”;

google apps directory sync

2、下载 Windows 或 Linux 版本的 Google Apps Directory Sync 工具并安装;

3、打开 Google Apps Directory Sync 工具,在里面依次配置 General Settings, Google Apps Configuration, LDAP Configuration, User Accounts, Notifications 等,LDAP 配置支持 MS Active Directory, OpenLDAP, Lotus Domino,我们的 LDAP 服务器用的是 OpenLDAP;

4、如果一切正常,在 Sync 里的 Validation Results & Sync 会看到 “打勾” 状态;

5、在真正同步(Sync & apply changes)之前先模拟(Simulate sync)一遍,点击下面蓝色的 “Simulate sync” 会出来结果报告;

google apps directory sync

6、查看上面的模拟结果,如果符合自己的要求的话就可以点击红色的 “Sync & apply changes” 开始实际操作了。

几个常用 Linux 桌面/窗口管理器的内存占用对比

A Memory Comparison of Light Linux Desktops 这篇文章比较了几个常用 Linux 桌面/窗口管理器的内存占用情况,个人使用的比较多的超轻量级窗口管理器 dwm 只占用 1MB,Fluxbox 占用 16MB,XFCE 占用 70MB,平铺窗口管理器里面最受欢迎的 xmonad 没有被提及。

大家喜欢用什么桌面/窗口管理器呢?

桌面/窗口管理器 内存占用
wm2 0.7MB
dwm 1MB
Ratpoison 1MB
JWM 3MB
i3 3MB
Blackbox 3MB
IceWM 4.5MB
Openbox 7MB
Window Maker 7MB
awesome 9MB
FVWM 13MB
Fluxbox 16MB
E17 35MB
LXDE 36MB
XFCE 70MB
Gnome 3 155MB
Unity 192MB
KDE 201MB

如何在 Xen dom0 下判断 domU 的硬盘使用率?

在 Xen 环境下我们可以很容易在 dom0 上通过 xm top 命令得到 domU 的当前运行状态信息,比如 domU 的 CPU 使用率,占用内存,IO 读写,网络等,但是无法知晓 domU 硬盘的使用情况,用了多少 inode、多少空间,还剩多少,是否快爆满、是否应该通知客户升级 Xen 硬盘等。这时候需要一种办法能得到 domU 上的硬盘信息,不一定要特别准确,只要不太离谱就行。我们使用 dumpe2fs 这个工具来打印客户的硬盘使用率,需要注意的是这个工具只针对 ext2/ext3/ext4 文件系统格式有效,也就是说只能用在那些使用 ext2/3/4 文件系统的 domU 中。

如果 Xen domU 使用的是文件格式的镜像:

# dumpe2fs -h /var/vps/images/vpsee.img
dumpe2fs 1.39 (29-May-2006)
Filesystem volume name:   
Last mounted on:          
Filesystem UUID:          e1f1f647-2098-4cfa-a1a3-9a44d4f93348
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal resize_inode dir_index filetype needs_recovery sparse_super large_file
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              2567264
Block count:              5120256
Reserved block count:     256012
Free blocks:              2674639
Free inodes:              1018476
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      621
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         16352
Inode blocks per group:   511
Filesystem created:       Sat Nov  7 06:25:55 2009
Last mount time:          Sat Sep  8 13:37:54 2012
Last write time:          Sat Sep  8 13:37:54 2012
Mount count:              3
Maximum mount count:      21
Last checked:             Fri Mar 23 12:34:20 2012
Check interval:           15552000 (6 months)
Next check after:         Wed Sep 19 12:34:20 2012
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:		  128
Journal inode:            8
First orphan inode:       1242758
Default directory hash:   tea
Directory Hash Seed:      a62d3cd5-9789-49bf-86c7-efee3d0286d4
Journal backup:           inode blocks
Journal size:             128M

如果 Xen domU 使用的是 LVM 格式的镜像:

# dumpe2fs -h /dev/vol-vps/vpsee_img 

从上面的 Inode count, Block count, Free blocks, Free inodes, Block size 等就可以判断出硬盘的使用率情况。

用 NetHogs 监控 Linux 每个进程的网络使用情况

有时候我们客户会发现服务器或 VPS 网络慢,进一步发现大量带宽被占用,一些客户到这里为止就不知道怎么办了。有什么简单办法能找出哪个程序(或者进程)占用了带宽呢?Linux 监控流量的小工具不少,如 iftop, iptraf, ifstat, darkstat, bwm-ng, vnstat 等,大都是统计和监控网卡流量的。今天介绍的 NetHogs 有点特别,可以监控每个进程的网络带宽占用情况。

在 Ubuntu/Debian 上安装 nethogs:

$ sudo apt-get install nethogs

在 CentOS/RHEL 上安装 nethogs:

# yum install nethogs

运行 nethogs:

# nethogs

# nethogs eth0

nethogs

定制 Ubuntu 安装盘

最近在准备一个关于高性能计算方面的 workshop,需要50台笔记本,这样每个人在 workshop 上都可以自己动手实践和学习。给50台笔记本安装系统是个体力活,因为全部要 WiFi,无线网卡又无法做 PXE 开机启动(市面上支持无线网卡启动的好像很少),那种通过 PXE 启动的办法就行不通,所以我们的 Cobbler 服务器也派不上用场。现在考虑的办法是自制基本的 Ubuntu 系统、做10个 U 盘、修改 BIOS 后用 USB 启动安装,安装完毕后再通过 Puppet 统一管理50台笔记本,这样可以灵活应对 workshop 中间可能出现的变化,比如某时候需要安装 Java 环境、集体修改密码等。

自己定制 Ubuntu 安装盘有很多现成工具,Ubuntu Customization Kit 和 Ubuntu Builder 是用的较多的两个,我们这里选用 Ubuntu Builder. 使用这类工具之前我们都需要一个原版的 Ubuntu ISO(ubuntu-12.04.2-desktop-amd64.iso),这样才能在此基础上做定制。

安装和运行:

$ sudo add-apt-repository ppa:f-muriana/ubuntu-builder
$ sudo apt-get update
$ sudo apt-get install ubuntu-builder

$ ubuntu-builder

可以定制的选项不是很多,选择我们要定制的 ISO、选择要安装的桌面环境(窗口管理器)、编辑一下 sources.list 使用我们内部的源(这样50台笔记本同时升级和安装软件都快很多)、安装一些我们要的软件包(比如 openssh-server, puppet 在 Ubuntu 12.04 Desktop 版本中没有默认安装。)等等。

ubuntu builder

定制完成后点击 Build 就会开始创建新的 Ubuntu ISO,build 完成后会在 /home/ubuntu-builder 目录下出现一个新的 iso 文件,这个文件就是刚刚定制的 Ubuntu 安装 ISO 文件,可以用 VirtualBox 试一下是否可用,然后刻成 CD/DVD 或者 USB 盘就可以了。

在 Ubuntu 上安装 SLURM 集群资源管理器

SLURM 是一个类似 Sun Grid Engine (SGE) 的开源分布式资源管理软件,用于超级计算机和大型计算节点集群,可高度伸缩和容错。SUN 被卖给 Oracle 后,好用的 SGE 变成 Oracle Grid Engine 并且从 6.2u6 版本开始成为商业软件了(可以免费使用90天),所以我们不得不另寻其他的开源替代方案,SLURM 是上次在德班高性能会议的时候一位陌生人介绍的,听上去不错。

SLURM 通过一对冗余集群控制节点(冗余是可选的)来管理集群计算节点,是由一个名为 slurmctld 的管理守护程序实现的,slurmctld 提供了对计算资源的监视、分配和管理,并将进入的作业序列映射和分发到各个计算节点上。每个计算节点也有一个守护程序 slurmd,slurmd 管理在其上运行的节点,监视节点上运行的任务、接受来自控制节点的请求和工作、将工作映射到节点内部等等。图示如下:

slurm architecture

官方网站提供的 Super Quick Start 安装文档一点都不 quick,看了头大。以下步骤使用两台服务器演示:主机名为 slurm00 的服务器用作控制节点;主机名为 slurm01 的服务器用作计算节点。

在控制节点和计算结点分别安装 slurm 包,这个包里面既含有控制节点需要的 slurmctld 也含有计算结点需要的 slurmd:

# apt-get install slurm-llnl

控制节点和计算结点之间需要通信,通信就需要认证,slurm 支持两种认证方式:Brent Chun’s 的 authd 和 LLNL 的 MUNGE,MUNGE 是专为高性能集群计算打造的,这里我们选用 MUNGE,生成 key 后启动 munge 认证服务:

# /usr/sbin/create-munge-key
Generating a pseudo-random key using /dev/urandom completed.

# /etc/init.d/munge start

使用 SLURM Version 2.3 Configuration Tool 在线配置工具生成配置文件,然后把配置文件拷贝控制节点以及各个计算结点的 /etc/slurm-llnl/slurm.conf(是的,控制节点和计算结点使用同一个配置文件)。

有了配置文件和启动了 munge 服务后就可以在控制节点启动 slurmctld 服务了:

# /etc/init.d/slurm-llnl start
 * Starting slurm central management daemon slurmctld                             [ OK ]

把控制节点生成的 munge.key 拷贝到各个计算结点:

# scp /etc/munge/munge.key ubuntu@slurm01:/etc/munge/

登陆计算节点后启动 munge 服务(注意需要改变 munge.key 的 owner 和 group 为 munge,否则会启动失败)和 slurmd 服务:

# ssh ubuntu@slurm01

# chown munge:munge munge.key 
# /etc/init.d/munge start
 * Starting MUNGE munged                                                           [ OK ]

# slurmd

在控制节点上(slurm00)测试一下是否顺利连接到计算结点(slurm01),并且简单运行一个程序 /bin/hostname 看看效果吧:

# sinfo 
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
debug*       up   infinite      1   idle slurm01

# srun -N1 /bin/hostname 
slurm01

ssh_exchange_identification: Connection closed by remote host 可能的问题

今天 ssh 登陆一台服务器的时候报错:

$ ssh [email protected]
ssh_exchange_identification: Connection closed by remote host

单看这个错误信息没有啥用,因为可能有多种情况都会导致这一信息,多数时候用 ssh -vvvvv 也 debug 不到啥有用的东西出来。一般来说有这么几种情况和解决办法:

1、检查 /etc/hosts.deny 和 /etc/hosts.allow 里面是否屏蔽了某些帐户;
2、删除 ~/.ssh/known_hosts 里面的相关服务器条目试一下;
3、Debian 上 /var/run/sshd/ 的所属问题导致 SSH 不能启动
4、在某些发行版上升级 glibc 或 openssl 等软件包以后需要重启一下 sshd;
5、由于 ssh 试探或者 ssh 连结数太多,/etc/ssh/sshd_config 里面的 MaxStartups 默认参数配置不够用;
6、欢迎补充 …

这里遇到的就是“情况5”,控制台直接登陆服务器后检查 /var/log/secure 发现大量未经授权和失败的连接,典型的 ssh brute force 试探导致。先看一下帮助文件,看看 MaxStartups 10:30:60 是啥意思:

# man sshd_config
...
     MaxStartups
             ...
         Alternatively, random early drop can be enabled by specifying the
         three colon separated values “start:rate:full” (e.g. "10:30:60").
         sshd(8) will refuse connection attempts with a probability of
         “rate/100” (30%) if there are currently “start” (10) unauthenti-
         cated connections.  The probability increases linearly and all con-
         nection attempts are refused if the number of unauthenticated con-
         nections reaches “full” (60).
...

MaxStartups 默认设置是 10:30:60,意思是从第10个连接开始以30%的概率(递增)拒绝新连接,直到连接数达到60为止,可能因为 ssh ddos/brute force 触发了这个 MaxStartups 设置。根据当前 ssh 连接用户和服务器情况解决办法是,把这个值加大、在 /etc/hosts.allow 里只加上授权用户、或者使用 DenyHosts, Fail2ban 等工具屏蔽掉攻击源。