RAID及软RAID

2014-11-06 • 技术文章

RAID是“Redundant Array of Independent Disk”的缩写,诞生于1987年,由美国加州大学伯克利分校提出。简单地解释,就是将N台硬盘通过RAID Controller结合成虚拟单台大容量的硬盘使用。RAID最大的优点是提高传输速率和提供容错功能。其中RAID 2、3、4较少实际应用,RAID 5已经涵盖了所需的功能,因此RAID 2、3、4大多只在研究领域有实作,而实际应用上则以RAID 5为主,RAID 6也常见。

RAID 0:连续数据块以轮询的方式写到全部的磁盘上,并行交叉存取,缩短了IO请求的排队时间,最少要2块盘来做,无容错性。

RAID 1:就是做镜像,最少两块盘来做,冗余容错,支持并发读。

RAID 10:即RAID 0和RAID 1的方案一起上,即分布又镜像。优点是同时拥有RAID 0的超凡速度和RAID 1的数据高可靠性,但是CPU占用率同样也更高,而且磁盘的利用率比较低。

RAID 2:在位粒度级别分布,用海明码做校验,适用于大量顺序访问,成本高,实现复杂,基本上不用。

RAID 3:在字节粒度级别分布,使用简单的奇偶校验,单块盘存放校验信息,最少3块盘来实现,容许坏掉一块。对于大量的连续数据可提供很好的传输率,但对于随机数据来说,奇偶校验盘会成为写操作的瓶颈。

RAID 4:在块粒度级别分布,用一块盘来做校验,也是很少使用。

RAID 5:块粒度级别分布,不单独指定奇偶盘,校验信息循环分布在每个盘上,容错性更好。读/写指针可同时对阵列设备进行操作,提供了更高的数据流量。更适合于小数据块和随机读写的数据。容许坏掉1块。有“写损失”,即每一次写操作将产生四个实际的读/写操作,其中两次读旧的数据及奇偶信息,两次写新的数据及奇偶信息。

RAID 6:块粒度级别分布,两份校验信息,容许坏2块盘。

软RAID:一种通过操作系统实现的RAID方式。

参考资料与扩展阅读

http://zh.wikipedia.org/wiki/RAID

短连接、长连接与keep-alive

2014-10-30 • 技术文章

短连接与长连接

通俗来讲,浏览器和服务器每进行一次通信,就建立一次连接,任务结束就中断连接,即短连接。相反地,假如通信结束(如完成了某个HTML文件的信息获取)后保持连接则为长连接。在HTTP/1.0中,默认使用短连接。从HTTP/1.1起,默认使用长连接,这样做的优点是显而易见的,一个网页的加载可能需要HTML文件和多个CSS或者JS,假如每获取一个静态文件都建立一次连接,那么就太浪费时间了,而在保持连接的情况下,继续GET即可。

对于频繁请求资源的客户来说,较适用长连接。但连接数最好进行限制,防止建立太多连接拖累服务端。一般浏览器对一个网站的连接是有限制的几个,所以网站会将资源部署在多个域名上以实现浏览器同时请求。

短/长连接应当在TCP连接的范畴中来讨论。有人常说HTTP的短连接和长连接如何如何,但是HTTP只是一个应用层协议,又是无状态的,最终实质性的保持连接还是得靠传输层,即TCP。

举个例子,NginX作为代理的一种常见配置方式是在NginX与客户端之间的连接使用长连接,NginX与后端服务器之间的连接使用短连接。

keep-alive

我们使用浏览器的开发者工具查看网络请求和响应信息时经常在HTTP请求头部看到Connection: keep-alive,一般的浏览器都会带着个头去请求数据,假如有特殊需求可以用Connection: close断开。HTTP头部的Connection也不一定就被客户端或服务端老老实实地遵循,毕竟各有各的考虑,尤其是在HTTP/1.0这还只是个实验性的功能,而在HTTP/1.1默认长连接于是没有对长连接做特殊的规定。

长连接也不能无限期地长,服务端有可能在头部放Keep-Alive,其中timeout等于一个值来规定保持连接的秒数,还可以用max来规定多少次请求后断开。如果没有说明怎么断开,主动发起四次握手也可以实现连接的断开。

现在有一个问题就是HTTP的keep-alive与TCP的keep-alive到底是什么关系。其实这是两种不同的机制,可以认为没有什么关系。HTTP在头部的Connection中声明keep-alive可以告诉对方要长连接不立即断开,但是TCP的keep-alive则是一种检查对方是否仍旧和自己保持着连接的机制以避免自作多情半开放的连接。假如发出一个探测段,成功收到响应,这证明连接正常保持;假如发出一个探测段一段时间后,一个响应都没收到,对方可能已挂断、机器异常或网络异常;假如对方收到探测段但重置,说明原来的连接已经因为某些原因挂断,目前是因为未进行三次握手新建立连接而被挂断。

参考资料

http://stackoverflow.com/.../relation-between-http-keep-alive-duration-and-tcp-timeout-duration

http://www.cnblogs.com/cswuyg/p/3653263.html

http://www.cnblogs.com/sunada2005/p/3304593.html

Spring Security框架的一些琐碎基本配置备忘

2014-10-20 • 技术文章

XML配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:security="http://www.springframework.org/schema/security" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/security   
        http://www.springframework.org/schema/security/spring-security-3.2.xsd">
    <!-- **跨目录,*不跨目录匹配 -->
    <security:http auto-config="false" pattern="/admin/**" use-expressions="true" 
        access-denied-page="/error.html" authentication-manager-ref="adminAuthManager" 
        entry-point-ref="loginUrlAuthenticationEntryPoint">
        <!-- access: permitAll denyAll isFullyAuthenticated() hasAnyRole() hasRole()... -->
        <security:intercept-url pattern="/admin/*" access="permitAll"/>
        <!-- 自定义过滤器,可以在其中实现验证码等必要的配置 -->
        <security:custom-filter ref="adminCaptchaFilter" position="FORM_LOGIN_FILTER"/>
        <!-- 注销登出配置 -->
        <security:logout invalidate-session="true" logout-success-url="/admin/?msg=out" logout-url="/admin/signout" />
        <security:session-management>
            <security:concurrency-control error-if-maximum-exceeded="false" max-sessions="1" />
        </security:session-management>
    </security:http>
    <!-- 登录配置 -->
    <bean id="loginUrlAuthenticationEntryPoint" 
        class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
        <property name="loginFormUrl" value="/admin/?msg=auth"/>
    </bean>
    <bean id="adminCaptchaFilter" class="org.tehon.eg.adminCaptchaFilter">
        <property name="filterProcessesUrl" value="/amdin/signin"/>
        <property name="authenticationManager" ref="adminAuthManager"/>
        <property name="authenticationSuccessHandler" ref="adminAuthSuccessHandler"/>
        <property name="authenticationFailureHandler" ref="adminAuthFailureHandler"/>
        <property name="allowSessionCreation" value="true"/>
    </bean>
    <security:authentication-manager id="adminAuthManager">
        <!-- 自定义用户信息、密码加密策略 -->
        <security:authentication-provider user-service-ref="adminDetailService">
            <security:password-encoder ref="PD" />
        </security:authentication-provider>
    </security:authentication-manager>
    <!-- 密码加密,实现encode(CharSequence)和matches(CharSequence,String) -->
    <bean id="PD" class="org.tehon.eg.PasswordDigest" />
    <bean id="adminDetailService" class="org.tehon.eg.adminAuthService" />
    <!-- 自定义实现登录成功的一些处理 -->
    <bean id="adminAuthSuccessHandler" class="org.tehon.eg.adminAuthSuccessHandler">
        <property name="defaultTargetUrl" value="/admin/index.jsp"/>
    </bean>
    <!-- 自定义实现登录失败的一些处理 -->
    <bean id="adminAuthFailureHandler" class="org.tehon.eg.adminAuthFailureHandler">
        <property name="defaultFailureUrl" value="/admin/?msg=fail"/>
    </bean>
    <!-- 自定义错误提示信息 -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <!-- 文件名,不加扩展名 -->
                <value>spring-sec-msg_zh_CN</value>
            </list>
        </property>
    </bean>
</beans>

自定义User

写一个类继承org.springframework.security.core.userdetails.User,在其中加一些需要的成员及其getter/setter,实现新的构造函数。

1
2
3
4
5
private String name;
public adminUser(String email, String pwd, boolean a1, boolean a2, boolean a3, boolean a4, Collection<GrantedAuthority> a, String name) {
    super(email, pwd, a1, a2, a3, a4, a);
    this.name = name;
}

自定义UserDetailsService

写一个类实现UserDetailsService,Override其loadUserByUsername(String)方法。

1
2
3
4
5
6
7
8
9
10
11
@Override
public UserDetails loadUserByUsername(String email) throws BadCredentialsException {
    Admin admin = adminDao.queryByEmail(email);
    AdminUser userDetail = null;
    if(admin != null){
        userDetail = new AdminUser(...);
    } else {
        throw new BadCredentialsException("登录邮箱地址无效,请确认!");
    }
    return userDetail;
}

角色权限

Spring Security中有很多各种各种的对象,但阅读其源代码可以发现大多是一堆堆的String。比如对角色而言,我们可以把String类型传入直接构造。这里的角色和HttpServletRequest中的Role是相通的。

1
2
Collection<GrantedAuthority> gas = new ArrayList<GrantedAuthority>();
gas.add(new SimpleGrantedAuthority("ROLE_SUPERUSER"));

自定义实现验证码

写一个类继承org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter,Override其attemptAuthentication方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
        HttpServletResponse response) throws AuthenticationException {
 
    String requestCaptcha = request.getParameter("j_captcha").toLowerCase();
    String genCaptcha = (String)request.getSession().getAttribute("captcha");
 
    // 验证码验证完一次后销毁
    request.getSession().setAttribute("captcha", null);
 
    if(StringUtils.isBlank(requestCaptcha) || StringUtils.isBlank(genCaptcha) || !genCaptcha.equals(requestCaptcha)){
        throw new AuthenticationServiceException("验证码错误!");
    }
 
    return super.attemptAuthentication(request, response);
}

大学课程基础知识整理:数据库原理

2014-10-10 • 技术文章

前言

大学行将结束,部分课程知识在未来还会应用到,特此整理为本系列博文,不求具体深入,点到为止。

键、最小依赖集和无损分解的判断

设R的属性集为U,X是U的一个子集。如果X→U在R上成立,则称X为R的一个超键。如果X→U在R上成立,但X是可能是最小的子集,则X为候选键。

最小依赖集应满足:最小集闭包=集合闭包,每个FD的右边都是单属性,最小集中没有冗余的FD,左边没有冗余的属性。最小依赖集不一定唯一。求法:拆成右边都是单属性的形式,删去冗余。

R有n个属性和k个分解集,做k行n列表,若属性在集中则标aj,否则标bij,对FD X→Y,如果表格中有两行在X值上相等,在Y值上不相等,那么这两行的Y值改成相同的值,若修改后的表有一行全是a,则无损。

三大范式与反范式

第一范式:如果关系模式R的每个关系r的属性值都是不可分的原子值,则称R为1NF。如R(NAME, MAIL),若一个人有多个邮箱,则要出现多个元组以便存储。

第二范式:在1NF基础上,每个非主属性完全函数依赖于候选键,则称R为2NF。旨在消除局部依赖。求法举例:R(WXYZ),主键是WX,R上存在X→Z的局部依赖,则分解为R1(XZ)和R2(WXY)。

第三范式:在1NF基础上,每个非主属性都不传递依赖于R的候选键,则称R是3NF。求法举例:R(WXY),主键是W,R上存在X→Y的传递依赖,这分解为R1(XY)和R2(WX),X依赖于R1

反范式:不严格按照范式化的设计,避免关联的存在,如果不存在关联,这对大部分查询最差的情况(如全表扫描,数据量比内存大)比关联要快一些,可以避免随机IO,提高性能。

事务

ACID:原子性,一致性,隔离性,持久性。

检查点机制:最后一个检查点前提交的不必管,最后一个检查点前未提交但故障前提交的重做,故障前未提交的撤销。REDO正向跑日志,UNDO逆向扫描日志。

丢失更新:读了同一个值,先后更改,先更改的被覆盖。

读脏数据:没有COMMIT却被另一个事务读到。

不一致:某事务进行中在读到某个数据前,另一事务已经对该数据的值提交了更新。

锁这个话题,联系到实践可能会非常复杂,这里仅仅简单依照基本理论介绍X所(排它锁,写锁)和S锁(共享锁,读锁)。

X锁独占,别的事务谁也不许加锁。数据加S锁后,仍允许其它事务加S锁,但所有的S锁释放掉前,决不允许任何事务加X锁。

活锁:一直等待却始终等不到封锁机会,如优先级太低,任何事务优先级都更高,轮不着其加锁。排队可以避免这种问题。

死锁:互相等待对方释放自己要的资源。必要时可以干掉一个不重要的事务来解决。

饿死:很多事务频繁地加S锁,总是没有都释放的时候,永远加不上X锁。

可串行化:某种并发执行结果与某一串行调度执行的结果一致,则称这种并发执行的调度为可串行化的调度。

行锁:Oracle和InnoDB提供,Oracle的行锁加在行对象上,InnoDB加在索引这个数据结构上,所以InnoDB加行锁必须要有索引这个前提。国产的达梦数据库也支持行锁。

为了避免资源竞争产生死锁,在S锁和X锁之外还有一种U锁(更新锁,意向锁)。首先判断一个事务中是否需要对数据进行写操作,如果需要则在一开始就加排它锁。

隔离级别

可串行化(Serializable):允许并发,排队走。

可重复读(Repeated Read,RR):只允许事务读已提交的数据,并且在两次读同一个数据时不允许其它事务修改它。应用了读写锁,读锁不能被写锁升级,读读可并行。这是InnoDB默认的隔离级别,通过Next-key锁策略防止幻读,提到这里还会有一些奇奇怪怪的不易发现的死锁问题值得研究,在此不再展开。

读提交数据(Read Committed,RC):允许读已提交的数据,但不要求RR。应用了读写锁,读锁能被写锁升级,读读并行,读写并行,但写读不能并行。这是Oracle默认的隔离级别。

读未提交数据(Read Uncommitted,RU):允许读未提交的数据,最低的一致性级别。只加写锁,读不加锁。读读、读写、写读都并行。

以上是SQL92标准的几个隔离级别,但目前主流的数据库一般采用了快照隔离(Snapshot Isolation)、多版本并发控制(MVCC)机制,针对读多写少情景优化,可在事务进行过程中从回滚段中找相应版本的状态读取数据,隔离级别很高,并行度可达到甚至超过RU级别。

此外,还可以了解一下,Oracle的SCN、MySQL的Trx_id是怎么回事。

表的联接

内联接(INNER JOIN):结果为两个联接表中的匹配行的联接。

左外联接(LEFT OUTER JOIN):包括左表全部行,右表不满足的NULL之。右外联接不再赘述。

完全外联接(FULL OUTER JOIN):根据左外联接和右外联接应该明白了。

交叉联接(CROSS JOIN):返回的是笛卡尔积,即所有可能的行组合。

NEST LOOP:有两个表,驱动表和被驱动表。驱动表做一次遍历,被驱动表做多次遍历。返回第一条记录速度很快,不需要排序。可以使用非等值连接。MySQL支持NEST LOOP。

SORT MERGE:两个表地位一样,要先排序,然后进行合并,返回记录集。排序首先在内存中进行,能在内存中完成的叫In-Memory Sort;如果需要借助磁盘缓冲,叫External Sort。MySQL不支持。

HASH JOIN:对驱动表的连接字段进行哈希操作,再依次对被驱动表每条记录的连接字段执行相同的哈希函数,和驱动表的哈希结果进行匹配。内存消耗远小于SORT MERGE,也不需要密集的CPU操作,普遍优于SORT MERGE算法。MySQL官方版本暂不支持,但MariaDB已经支持。

半联接:针对IN、EXISTS等,在进行连接查询的时候,内层如果有相应的记录及返回一个TRUE,而不需要访问余下的行,如果内层表特别巨大的时候将会大大节省时间。系统参数控制或HINT控制(semijion-强制使用;no_semijion-不使用;nl_sj-进行嵌套半联接;hash_sj-进行散列半联接;merge_sj-进行排序半联接)。半联接条件是语句必须使用in(=any)或exists,语句必须在in或exists中有子查询,使用exists必须使用关联子查询,in或者exists字句不能在OR分支中。

反联接:原理和半连接一样,在not in和not exists中使用。有一点要注意,如果NOT IN 的时候子查询返回有NULL值。系统参数控制或HINT控制(antijoin-强制使用;nl_aj-进行嵌套反联接;hash_aj-进行散列反联接;merge_aj-进行排序反联接)。反联接条件为语句必须使用NOT IN (!=ALL) 或NOT EXISTS,语句必须在NOT IN或NOT EXISTS子句有一个子查询,NOT IN或NOT EXISTS子句不能包含在OR分支中,NOT EXISTS子句中的子查询必须与外层查询相关,注意NOT IN子查询不要返回空值。

索引

B+树索引:传统关系型数据库主要的索引结构使用的都是B+树。更有甚者,InnoDB引擎的表数据,整个都是以B+树的组织形式存放的。数据库中B+树索引又分为聚集索引和非聚集索引。

聚集索引:键值的逻辑顺序决定了表中相应行的物理顺序,即表中数据按主键顺序存放。聚集索引就是按每张表的主键构造一颗B+树,并且叶节点存放整张表的行记录数据,每张表只能有一个聚集索引(一个主键)。好处是它对于主键的排序查找和范围查找的速度非常快,叶节点的数据就是我们要找的数据。对于主键索引,MySQL在添加和删除操作时先创建一张临时表,然后把数据导入临时表,再删除原表,把临时表重命名为原表。

非聚集索引(辅助索引):叶级别不包含行的全部数据,该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同。叶级别除了包含行的键值以外,每个索引行还包含了一个书签,该书签告诉InnoDB引擎哪里可以找到与索引对应的数据。非聚集索引的存在并不影响数据在聚集索引中的组织,因此一个表可以有多个非聚集索引。当通过非聚集索引查找数据时,会遍历非聚集索引并通过叶级别的指针获得指向主键索引的主键,然后再通过主键索引找到一行完整的数据。

哈希索引:将索引键通过哈希运算之后,将运算结果的哈希值和所对应的行指针信息存放于一个哈希表中。它只能是等值过滤,无法避免排序,无法直接完成查询还是得访问表中的实际数据,哈希重复度高时效率低。

R树索引:适用于高维空间搜索问题,它把B树的思想很好的扩展到了多维空间。R树是B树在高维空间的扩展,是一棵平衡树。每个R树的叶子结点包含了多个指向不同数据的指针,当我们需要进行一个高维空间查询时,我们只需要遍历少数几个叶子结点所包含的指针,查看这些指针指向的数据是否满足要求即可。

索引的原则:最左匹配原则(遇到范围查询(>、<、between、like)就停止匹配)、=和in可以乱序(优化器自己优化)、尽量选择区分度高的列作为索引、索引列尽量不参与计算、尽量扩展索引而不是新建。

SQL优化

首先,确保设计SQL时尽量最优。然后对于固定下来的SQL,会有很多种可能的执行路径,查找SQL最优的执行路径,使得用户能够更快的得到SQL执行的结果是我们的目标。SQL的每一种执行路径,均可计算一个对应的执行代价(CPU和IO都要考虑)。代价越小,执行效率越高;反之则反之。除了代价优化模型还有规则优化模型。

show status可以大致上看看各类操作的执行次数,操作影响的行数等,但意义不大,适合看大致情况。

慢查询:给MySQL配置参数--log-slow-queries[=filename]启动,会写慢查询日志。对于正在执行的情况可以用show processlist来看目前正在执行的线程,是否锁表等执行情况。

SQL分析:可以查看执行计划,看怎么联接表,怎么扫描,使用到的索引以及统计信息,根据表的记录数和索引情况,改写SQL,调整索引,使用HINT,优化SQL的执行路径。

一些注意事项:少用*;尽量避免多表;尽量避免DISTINCT(可用EXISTS替代)、INTERSECT等耗费时间的操作;避免索引列上使用函数、NOT、IS NULL;避免前置通配符;尽量避免类型合适转换;调整连接顺序;WHERE代替HAVING提前过滤;NOT EXTSTS(有效利用索引)替代NOT IN(执行内部的排序合并);>=或<=代替>、<或NOT;尽量避免子查询;外联接代替NOT IN;删除表数据用TRUNCATE;及时提交数据释放资源。

NoSQL

这不是课程范围之内的东西,加之个人用得不多,所以简单介绍。一开始非常火,捧得特别高,现在人们对于NoSQL心态普遍正常了很多。关系型数据库中的表都是存储一些格式化的数据结构,每个元组字段的组成都一样,即使不是每个元组都需要所有的字段,但数据库会为每个元组分配所有的字段,这样的结构可以便于表与表之间进行连接等操作,但从另一个角度来说它也是关系型数据库性能瓶颈的一个因素。而非关系型数据库以键值对存储,它的结构不固定,每一个元组可以有不一样的字段,每个元组可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少一些时间和空间的开销。这里仅举两个例子。

Redis:它通常被称为数据结构服务器,因为值可以是字符串、哈希Map、List、集合和有序集合等类型。微博在大规模地用。

MongoDB:支持的数据结构非常松散,是类似JSON的BJSON格式,因此可以存储比较复杂的数据类型。最大的特点是支持的查询语言非常强大,语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

结语:别名的奇技淫巧

本来还想涉及一点分布式的内容,可惜自己又没有太多实践经验,只照本宣科地写出来没意思,所以来讨论点好玩的。MySQL doesn’t yet support ‘LIMIT & IN/ALL/ANY/SOME subquery’,如子查询中不能使用LIMIT,但是这样select * from table where id in (select t.id from (select * from table limit 10) as t)就可以通过。

问与答

MySQL的配置文件叫什么名字,如果通过命令登录?答:my.ini或my.cnf,其中有端口号、字符集、连接数、缓存大小、线程控制、事务控制、默认存储引擎等配置项,此外还有bin、data、lib目录。使用mysql -u[username] -p[password]命令来登录。

Oracle中NULL怎么和实际值比较大小?答:视为最大值。

Oracle中NVARCHAR2、VARCHAR2类型的区别是什么?答:NVARCHAR2中存储中文字时,一个中文字当一个字符来处理;而VARCHAR2中一个中文字按照字符集单字所占字符数处理。

表TABLE(userid,logintime,dat),userid为用户名(KEY),logintime为登录时间,dat为某些数据,请写SQL语句返回每个有记录的用户在最后一次登录所产生的userid,dat结果集。答:略。

微博每天产生大量的数据,假设一台机器的数据库只能存a亿条微博,但每年要产生a*50亿条微博,因此不得不将数据存储到多台机器上,请设计实现一种可行的存储方式,并说明如何实现查询需求。答:略。

通过iptables的recent模块实现服务器的动态访问控制

2014-09-29 • 技术文章

模块介绍

recent模块可以看作iptables里面维护了一个地址列表,这个地址列表可以通过“–set”(将地址和时间戳添加进列表)、“–update”(刷新时间戳)、“–rcheck”(检查地址是否在列表)、“–remove”(删除)四种方法来修改列表,每次使用时只能选用一种。还可附带“–name”参数来指定列表的名字(默认为DEFAULT),“–rsource”、“–rdest”指示当前方法应用到数据包的源地址还是目的地址(默认是前者)。

recent语句都带有布尔型返回值,每次执行若结果为真,则会执行后续的语句,比如“-j ACCEPT”之类的。

利用ping命令实现SSH动态开放

1
2
3
4
5
6
7
8
9
10
11
12
# 当包走完INPUT链而没被拿走时就会丢弃掉
iptables -P INPUT DROP
# 接受本地
iptables -A INPUT -s 127.0.0.1/32 -j ACCEPT
# 表明已经建立成功的连接和与主机发送出去的包相关的数据包都接受,保证后续可以连接
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# icmp类型8是ping包;指定包大小为128字节;recent用的列表名称为SSHOPEN,列表记录源地址。符合上述条件的数据包都接收。如果ping包内容为100字节,则加上IP头、ICMP头的28字节,总共128字节。
iptables -A INPUT -p icmp --icmp-type 8 -m length --length 128 -m recent --set --name SSHOPEN --rsource -j ACCEPT
# 接受一般的ping包
iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
# 对连接ssh 22端口的连接进行处理,来源于SSHOPEN源地址列表并且在列表时间小于等于15秒的放行
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --rcheck --seconds 15 --name SSHOPEN --rsource -j ACCEPT

实现连接限制

1
2
3
# 1小时内只允许连接5次
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --rcheck --seconds 3600 --hitcount 5 -j DROP
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --set -j ACCEPT

参考资料

http://www.cszhi.com/20120510/iptables-modules-recent.html