CyannyLive

AI and Big Data

分布式系统总结Part3

复制和一致性

数据的复制是为了提高性能和可靠性,但是我们需要保持各个副本的一致性:

问题一: 数据更新的实际分发问题,它需要关心副本的位置,以及如何在副本之间传播更新。

问题二:如何保持多个副本的一致性[more…]

以数据为中心的一致性

1. 严格的一致性

(1)条件:所有访问按绝对时间排序,数据项x的任何读操作将返回最近一次对x的写操作的结果所对应的值。

(2)要求:所有写操作是瞬间可见的,系统维持一个绝对的全局时间顺序,如果发生写操作,后续的读操作都会得到最新的写入的值。

(3)缺点:依赖于绝对的全局时间,分布式系统中为每个操作分配准确的全局时间是不可能的,一般是将时间分割成一系列连续的、不重叠的时间间隔,保证没个时间间隔内最多只发生一个单一操作。
精确的定义最后一次写操作是困难的,如图可以看到严格一致性
Distributed System02

2.线性化和顺序的一致性

(1)顺序一致性

条件:所有进程以相同顺序看到所有的共享访问,访问不按时间排序。任何执行结果都是相同的,就好像所有进程对数据存储的读、写操作按照某种序列顺序执行的,并且每个进程的操作按照程序所定制的顺序出现在这个序列中。

缺点:严重的性能问题,对于任何的顺序一致性存储,改变协议以提高读操作的性能必将降低写操作的性能,反之亦然。
Distributed System03
(2)线性化一致性

条件:所有进程以相同顺序看到所有的共享访问,访问根据(并非唯一的)全局时间戳排序。

在实际应用中,线性化主要用于开发算法的形式验证。关于根据时间戳维护顺序的附加限制使得线性化的实现比顺序一致性的实现开销更大。

3.因果一致性

条件:是一种弱化的顺序一致性模型,所有进程必须以相同的顺序看到具有潜在因果关系的写操作。不同机器上的进程可以以不同的顺序被看到并发的写操作.

当一个读操作后面跟着一个写操作时,这两个事件就具有潜在的因果关系。

Distributed System04

4.FIFO一致性

条件:所有进程以某个单一进程(有两个以上的写操作)提出写操作的顺序看到这些写操作,但是不同进程可以以不同的顺序看到不同的进程提出的写操作。

优点:容易实现,不需要保证不同进程看到相同的写操作顺序,除非两个以上的写操作是同一个进程提出的。这种情况下,写操作必须按顺序达到。

缺点:仍然对许多应用存在不必要的限制,因为这些应用需要从任何位置都可以看到按顺序看到某个单一进程所产生的写操作。同时并不是所有的应用程序都要求看到所有的写操作。这就引入了弱一致性。

Distributed System05

5.弱一致性

条件:引入同步变量,只有执行一次同步,共享数据才能保持一致。

a)对数据存储所关联的同步变量的访问是顺序一致的;b)每个拷贝完成所有先前执行的写操作之前,不允许对同步变量进行任何操作;c)所有先前对同步变量执行的操作都执行完毕之前,不允许对数据项进行任何读或者写操作。

特点:弱一致性是在一组操作,而非单个操作上强迫执行顺序一致性。同步变量用于划分操作的组。

缺点:即当同步变量被访问时,数据存储不知道此次访问是因为进程已经结束对数据存储的写操作还是因为进程将开始读数据而进行的。我们需要区分进程进入临界区和离开临界区的区别,引入了释放一致性。

Distributed System06

6.释放一致性

条件:退出临界区时,让共享数据保持一致,提供两种类型的同步变量。获取(acquire) 操作是用于通知数据存储进程进入临界区的操作,而释放(release)操作是表明进程刚刚离开临界区的操作。

  • 对共享数据执行读操作或写操作之前,所有进程先前执行的获取操作都必须已经成功完成;
  • 在释放操作被允许执行前,所有进程先前执行的读操作和写操作都必须已经完成;
  • 对同步变量的访问是FIFO一致的(不需要顺序一致)

Distributed System07

7.入口一致性

条件:它需要程序员(或编译器)在每个临界区的开始和结束处分别使用获取和释放操作,入口一致性要求每个普通的共享数据项都要与某种同步变量(如锁或障碍)关联。即让进程在进入临界区时,让属于同一临界区的共享数据保持一致。

优点:第一,将一系列共享数据项与各自的同步变量关联起来可以减少获取和释放一个同步变量所带来的额外开销。因为只有少数的数据项需要同步。第二,增加了并行度:这也使得多个包含不同共享数据的临界区可以同时执行

缺点:第一,同步变量和共享数据的关联带来了额外的复杂性和负载,程序设计可能更加复杂,容易出错。第二,关于入口一致性的一个程序设计问题是如何正确地将数据与同步变量关联起来。解决这个问题的一种方法是使用分布式的共享对象,向用户屏蔽低层的同步细节。

以数据为中心的一致性的比较

Distributed System18
Distributed System19

以客户为中心的一致性模型

1. 最终一致性

条件: 没有更新操作时,所有副本逐渐成为相互完全相同的拷贝。最终一致性实际上只要求更新操作被保证传播到所有副本

优点:开销小

缺点:移动用户访问分布式数据库的不同副本时,如果副本没有更新,会出现不一致。

2. 单调读

条件:总是读最新值,如果一个进程读取数据x的值,那么该进程对执行任何后续读操作将总是得到第一次读取的那个值或更新的值。
如果一个进程已经在t时刻看到x的值,那么以后他不再会看到较老的版本的x的值。

Distributed System08

3. 单调写

条件:总是在最新的拷贝上写,一个进程对数据项x执行的写操作必须在该进程对x执行任何后续写操作之前完成,保证写操作以正确的顺序传播到数据存储的所有拷贝。
在单调写一致性的定义中,同一进程的写操作的执行顺序与这些操作的启动顺序相同。

比较:注意,单调写一致性与数据为中心的FIFO一致性相似。FIFO一致性的本质是,同一进程执行的写操作必须在任何地方以正确的顺序执行。

这一顺序限制也适用于单调写一致性,只是我们这里考虑的是仅为单一进程维持的一致性,而不是为许多并发进程维持的一致性。

Distributed System09

4.写后读

条件:一个进程对数据项x执行一次写操作的结果总是会被该进程对x执行的后续读操作看见。 一个写操作总是在同一进程执行的后续读操作之前完成,而不管这个后续的读操作发生在什么位置。

Distributed System10

5.读后写

条件:同一个进程对数据项x执行的读操作之后的写操作,保证发生在与x读取值相同或比之更新的值上。进程对数据项上x所执行的任何后续的写操作都会在x的拷贝上执行,而该拷贝是用该进程最近读取的值更新的。

在读取的最新值上进行写操作。
Distributed System11

容错

1. 两军问题

两军的通信信道不稳定,需要达成一致才能发动攻击,无论双方发了多少次确认,都不能确定通信兵是否把自己的消息带给对方,永远不会达成协议。
在不可靠传输的条件下,即使是无错误的进程,在两个进程之间达成协议也是不可能的。

2. 拜占庭将军问题

通信良好,进程确不好,正如拜占庭的将军有叛徒的情况。

在这个问题中,红军还是在山谷中扎营,但是在附近的山上有n个带领部队的蓝军将领。通信是通过电话双向进行的,及时而且质量很好。但是有n个将军是叛徒(故障),他们通过给忠诚的将军发送错误的和矛盾的信息(模拟故障进程)来阻止他们达成协议。现在问题在于忠诚的将军是否还能达成协议。

Lamport采用递归算法来让无故障的进程达成协议。

N个进程,其中M个故障进程:只有当N>=3m+1时,才能达成一致,即有三分之二的进程是正常的。

3. 两阶段提交

Distributed System12
状态机很能说明问题。

两个阶段:vote_commit and global_commit, 3(n-1)条消息

缺点:两阶段提交的一个问题在于当协调者崩溃时,参与者不能做出最后的决定。因此参与者可能在协调者恢复之前保持阻塞。

因此引入3PC,三阶段提交,但3PC实际中用的少,因为2PC阻塞情况很少出现。

4. 三阶段提交

Distributed System13
没有一个可以直接转换到Commit或者Abort状态的单独状态。

没有一个这样的状态:它不能做出最后决定,而且可以从它直接转换到Commit状态。 Commit之前需要经过PRCOMMIT状态。

三阶段:vote-commit, prepare-commit, global-commit

引入了PRECOMMIT状态。

  • 2PC:崩溃的参与者可能恢复到了Commit状态而所有参与者还处于Ready状态。在这种情况下,其余的可能操作进程不能做出最后的决定,不得不在崩溃的进程恢复之前阻塞。
  • 在3PC中,只要有可操作的进程处于Ready状态,就没有崩溃的进程可以恢复到Init、Abort或Precommit之外的状态。因此存活进程总是可以做出的最后决定。当协调者崩溃,达到了预备提交阶段,在2PC中其他进程就会阻塞,但在3PC中,在预备提交阶段,即使没有协调者,也可以做出决定。

资源

分布式系统总结part1 中间件,进程迁移,移动通信失效,名称解析,移动实体定位

分布式系统总结part2 Lamport同步与向量时间戳,两大选举算法,三大互斥算法

分布式系统总结part3 复制和一致性(以数据和以客户为中心的一致性),容错(拜占庭将军问题,两阶段与三阶段提交)

分布式系统总结part4 Petri网解决哲学家问题和生产者、消费者问题

分布式系统总结Part2

Lamport逻辑和向量时间戳

1.Lamport逻辑时钟

Lamport认为,重要的不是所有进程在时间上完全一致,而是它们在事件的发生顺序上要达成一致。

先发生的定义: a → b 表示a在b之前发生,此时 C(a) < C(b), a b可以是同一个进程中的两个事件或进程间的消息发送事件。并发事件没有先后关系。

Lamport算法:[more…]

  • 遵循事件的先发生关系,每个消息都应携带根据发送者时钟的发送时间,当消息到达并接收时,接收者时钟显示的时间比消息发送者时间早时,接收者就将时钟调到比发送者者的时间大1的值。
  • 为了满足全局时间的需要:在每两个事件之间,时钟必须至少滴答一次,如果一个进程以相当快的速度发送或者接收两个消息,那么他得时钟必须在这之间至少滴答一次。
  • 两个事件不会精确地同时发生

2.Lamport逻辑时钟的缺陷

不能捕捉因果关系,而向量时间戳可以。

  • Lamport时间戳导致分布式系统中所有事件都要经过排序以具有这样的关系:如果a发生在b之前, 那么C(a) < C(b)
  • Lamport时间戳只能捕捉事件发生的先后关系,而不能捕捉因果关系。C(a) < C(b)不能说明a事件发生在b事件之前。 因果关系需要通过向量时间戳来捕获。

3.向量时间戳

因果关系:如果VT(a) < VT(b) 则a在因果上处于事件b之前。向量时间戳是让每个进程P都维护一个向量V来完成,该向量的性质如下:

a)Vi[i]是到目前为止进程Pi发生的事件的数量。

b)如果Vi[j]=k,那么进程Pi知道进程Pj中已经发生了k个事件

接收者可以通过消息m的时间戳知道其他进程中有多少事件发生在它之前,消息m在因果上可能依赖于这些事件。

当Pj收到消息m,调整自己的向量,将每项Vj[k]设置为max{Vj[k], vt[k]}, 然后 Vj[i]增加1

需要会看图计算向量时间戳:
Distributed System01
向量时间戳中只有各个分量都是小于关系时存在因果关系,而平行关系是并发关系。

选举算法

1. 欺负算法(Bully Algorithm)

算法:当一个进程发现协调者不再响应请求时,它就发起一个选举:

P向所有编号比它大的进程发送一个election消息;

如果无人响应,P获胜成为协调者;

如果有编号比它大的进程响应,则响应者接管选举工作。P的工作完成。

当以前崩溃的进程恢复时,它将主持一次选举,如果该进程是当前正在运行的进程中进程号最大的,就成为协调者。

总之进程号最大的总是取胜。

2.环算法——不使用令牌环

假设进程按照物理和逻辑顺序进行了排序,那么每个进程就知道它的后继者是谁了。

当任何一个进程注意到协调者不工作时,它就构造一个带有它自己的进程号的election消息,并将该消息发送给它的后继者。

如果后继者崩溃了,发送者沿着此环跳过它的后继者发送给下一个进程,或者再下一个,直到找到一个正在运行进程。

在每一步中,发送者都将自己的进程号加到该消息列表中,以使自己成为协调者的候选人之一。

最终,消息返回到发起此次选举的进程。当发起者进程接收到一个包含自己进程号的消息时,它识别出这个事件。此时,消息类型变成coordinator消息,并再一次绕环运行,向所有进程通知谁是协调者(成员列表中进程号最大的那个)以及新环中的成员都有谁。这个消息再循环一周后被删除,随后每个进程都恢复原来的工作。

互斥算法

1. 集中式算法

(1).算法

选举一个进程作为协调者,如最大网络地址号的机器上的进程。

无论何时一个进程要进入临界区,它都要向协调者发送一个请求消息,说明它想要进入哪个临界区并请求允许。

如果没有进程在临界区就发送“允许”应答,该进程进入临界区,如果有进程在临界区,就把该消息放入请求队列,发送“拒绝请求”的应答。

当临界区中的进程退出临界区,向协调者发送“释放”消息,协调者会从请求队列中取出第一个进程,发送“允许”进入的消息。

(2)优点

实现了互斥,每个时刻,协调者只让一个进程进入临界区。

很公平,没有进程会永远阻塞,不会饥饿,不会死锁

容易实现,每使用一次临界区,只需要三条消息(请求,允许,释放)

可以管理临界区或更一般的资源
(3).缺点

协调者是单点故障,在规模较大的系统中,单个协调者会成为性能瓶颈.

如果进程在发出请求之后阻塞,那么请求者就不能区分“拒绝进入”和协调者已经崩溃的两种情况。

2.分布式算法

1)Lamport算法

  • 当进程Si想进入临界区,向其他n-1个进程广播请求REQUEST(tsi, i), 并把请求放入自己请求队列request_queuei。

  • 其他n-1个进程受到请求REQUEST(tsi, i)后,把该请求放入各自的请求队列request_queuej, 并向进程Si响应一个带时间戳的REPLY消息。

  • 进程Si进入临界区,当且仅当满足以下两个条件:

      *   Si从其他进程收到的消息的时间戳都大于自己的请求时间戳(tsi, i)
    • Si的请求是请求队列request_queuei的第一个请求
  • 当进程Si退出临界区:从请求队列request_queuei中删除该请求,并向其他n-1个进程广播一个带时间戳的释放临界区的消息。其他n-1个进程收到该消息后,从请求队列request_queuej中删除该请求

在Lamport算法中,进程Request, REPLY, RELEASE一共发送了3(n-1)条消息,其实在一个接收者收到消息后,如果不同意Si进入临界区,没有必要再发送确认。
可以改进算法在2(n-1)到3(n-1)之间

2)Ricart和Agrwala算法,改进Lamport算法

  • 当一个进程想进入一个临界区时,它构造一个消息,其中包含它要进入的临界区的名字、它的进程号和当前时间。然后它将消息发送给所有其他的进程,理论上讲也包括它自己。
  • 当一个进程接收到来自另一个进程的请求消息时,它根据自己与消息中的临界区相关的状态来决定它要采取的动作。可以分为三种情况:第一,若接收者不在临界区也不想进入临界区,它就向发送者发送一个OK消息。第二,若接收者已经在临界区,它不进行应答,而是将该请求放入队列中。第三,如果接收者想进入临界区但尚未进入时,它将对收到的消息的时间戳和包含在它发送给其余进程的消息中的时间戳进行比较。时间戳最早的那个进程获胜。如果收到的消息的时间戳比较早,那么接收者向发送者发回一个OK消息。如果它自己的消息的时间戳比较早,那么接收者将接收到的请求放入队列中,并且不发送任何消息。
  • 在发送了请求进入临界区的请求消息后,进程进行等待,直到其他所有进程都发回OK消息为止。一旦得到所有进程的允许,它就可以进入临界区了。当它退出临界区时,它向其他队列中的所有进程发送OK消息,并将请求从队列中删除。(也就是说一个进程进入临界区的条件是收到了n-1个OK消息)

算法优点:不会饥饿,死锁;每次进入临界区仅需要2(n-1)条消息;没有单点故障

算法缺点:第一,单点故障变成了n点故障,如果任何一个进程崩溃,不能应答OK,这种不应答被错误的解释为拒绝请求,阻塞了所有进程进入任何一个临界区。第二,网络通信开销多于集中式算法;第三,要么必须使用组通信原语,要么每个进程必须维护组成员清单;第四,要求所有进程参与做出与进入临界区有关的所有决定,强迫每个进程都承担这样的负载是不可能的,可以在得到大多数进程OK的情况下进入临界区,但实现复杂。

3.令牌环算法

(1)算法

  • 假设:总线式的网络中,进程没有固定的顺序,环中为每个进程分配了一个位置,每个进程都直到谁在它的下一个位置。
  • 当环初始化时,进程0得到一个令牌token。该令牌绕着环运行,用点对点发送消息的方式把它从进程k传递到进程k+1(以环大小为模)。进程从它邻近的进程得到令牌后,检查自己是否要进入临界区。如果自己要进入临界区,那么它就进入临界区,做它要做的工作,然后离开临界区。在该进程退出临界区后,它沿着环继续传递令牌。不允许使用同一个令牌进入另一个临界区。
  • 如果一个进程得到了邻近进程传来的令牌,但是它并不想进入临界区,那么它只是将令牌沿环往下传递。因而,当没有进程想进入临界区时,令牌就绕环高速传递。

(2)优点

没有饥饿现象:任何时候都只有一个进程有令牌,并且令牌以固定的顺序循环传递。

(3)缺点

如果令牌丢失,必须重新生成令牌.

检测令牌丢失很困难,网络中令牌出现两次的时间间隔不确定,没有发现令牌可能是丢失,也可能是某个进程在占用。

如果有进程崩溃,该算法会有问题。(恢复方法: 要求每个进程维护进程环的配置信息, 每个进程收到令牌后发出确认信息,当它尝试把令牌传递给它的邻近进程时,如果没有收到确认,该进程就崩溃了,从组中删除该进程,继续传递令牌。)

三种互斥算法的比较

(1)程进入临界区,需要发送的消息数目不同

集中式算法: 3条消息,请求,允许,释放,简单而有效.

分布式算法:2(n-1)条

令牌环算法: 1~(n-1)条

(2)进入临界区之前的消息延迟不同
集中式算法: 2条消息,请求,允许。

分布式算法:2(n-1)条

令牌环算法: 0~(n-1)条

(3)三种算法在这三种算法在进程崩溃的情况下都损失惨重。为了避免进程崩溃造成的系统瘫痪,必须引入专门的措施和额外的复杂性。

资源

分布式系统总结part1 中间件,进程迁移,移动通信失效,名称解析,移动实体定位

分布式系统总结part2 Lamport同步与向量时间戳,两大选举算法,三大互斥算法

分布式系统总结part3 复制和一致性(以数据和以客户为中心的一致性),容错(拜占庭将军问题,两阶段与三阶段提交)

分布式系统总结part4 Petri网解决哲学家问题和生产者、消费者问题

分布式系统总结Part1

激动哥给了一些点,总结如下吧,算是对分布式的一些理解,希望对朋友们有帮助。

分布式系统系统基本概念

分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统。透明性, 故障透明性。

本质: 硬件上——机器是物理上独立的。软件上——对用户来说它们就像载和单个系统打交道。分布式系统位于用户的应用层和底层操作系统之间,有时也叫做中间件.

分布式系统的目标:资源链接和共享,透明性,开放性,可伸缩性。[more…]

分布式系统作为中间件技术

  1. 中间件在分布式系统中的位置

    中间件:在应用系统和网络系统之间的附加的软件层,隐藏网络操作系统中低层平台集合的异构性,提供一组完整程度不同的服务集,提高分布的透明性。

    中间件的最高目标是透明性。同时也具有开放性、可扩展性和易用性

  2. 中间件模型

  • 基于分布式文件系统:任何东西都是作为文件来处理,只对传统文件支持分布的透明性,比网络操作系统前进了一小步,仍然要求进程显式启动分布式机器,有一定的扩展。
  • 基于RPC:允许进程调用位于远程机器上的过程实现来隐藏网络通信。调用参数透明的传递到远程机器上,看起来就像在调用本地的进程一样,不知道网络通信的发生。
  • 基于分布式对象: 调用分布在远程机器上的对象的接口,通过消息传递调用

3.中间件通信技术

(1) RPC

使用客户端存根和服务器端存根,实现访问的透明性,按值传递,对引用传递的支持比较弱, 基于响应的暂时同步通信。

(2) RMI——远程对象调用

不使用用客户端存根和服务器端存根,使用针对对象的存根。本质上是RPC,但针对远程对象。

(3) MPI:面向消息的通信

RPC和RMI的不足:要求远程机器正在执行; 并且对同步要求高,客户在发出请求后阻塞

通信类型:持久通信,暂时通信;异步通信,同步通信; 两两正交共四种。

•持久异步通信:如邮件系统,消息队列

•持久同步通信

•暂时异步通信:如异步RPC,UDP

•暂时同步通信:基于接收的暂时同步通信:最弱的基于消息接收机制; 基于交付的暂时同步通信;基于响应的暂时同步通信: RMI, RPC。

MPI比套接字提供更多的抽象的消息传递原语,提供持久异步通信,用在RPC和RMI不适用的场合,它们主要用来协助将高度分散的数据库集成进大规模信息系统中。其他的应用还包括电子邮件和工作流。

(4)面向流的通信:

流是一种完全不同的通信方式,它的主要问题是两个连续的消息是否有时间上的联系。如音频流和视频流,同步很关键。

在连续数据流中,每个消息都规定了端到端的最大延迟时间。另外,发送的消息还要受端到端最小延迟时间的约束。

三种传输模式

异步传输模式:数据项是逐个传输的,但是对某一项在何时进行传输并没有进一步的限制。

同步传输模式:数据流中每一个单元都定义了一个端到端最大延迟时间。

等待传输模式:模式中数据单元必须按时传输,也就是数据传输的端到端延迟时间必须同时受到上限和下限的约束,实时系统。

进程迁移

  1. 弱迁移 vs 弱迁移

    弱迁移:即代码的可移植性,只传输代码段以及某些初始化数据,传输过来的程序总是以初始状态重新开始执行,弱可迁移性只要求在目标机器上能执行该代码段,例如Java Applet小程序,这种方法的好处在于简单性。

    强迁移:迁移执行中的进程,先停止运行中的进程,捕捉运行现场,迁移到另一台机器上,从中断处继续运行,强迁移比弱迁移实现难度大,例如D’Agent是支持强可移动性的一个例子(Dartmouth College)

  2. 发送者启动迁移 vs 接收者启动迁移

    发送者启动迁移,代码或正在执行的进程在哪台机器上,就由该机器来启动迁移,例如向Web服务器发送搜索程序运行查询。这种迁移容易实现.

    接收者启动迁移,代码迁移的主动权在目标机器手中,例如Java Applet

    区别:接收者下载代码到客户端,性能好,安全性好,客户端只有少数的资源需要保护,如内存和网络连接等;

    发送者启动迁移,上传代码到服务器端,需要认证用户,需要对服务器资源提供强保护。

  3. 在目标进程内执行迁移代码 vs 在派生进程内执行迁移代码

三种方法相互正交,形成了8中进程迁移方法,如图:

Distributed System20

移动Agent的基本概念

  1. 定义:是一种分布式的应用,移动Agent是一个运行于开放、动态网络环境中的,封装良好的计算实体,可自主地在异构的网络上寻找合适的计算资源,然后移动到资源所在机器上使用这些资源,它代表用户自主地在网络上移动,完成指定的任务。移动Agent由数据、操作、行为规则 封装而成。

  2. 基本特点:

  • 自主移动性:不拘泥于初始执行结点,可再网络各主机间自主移动。移动Agent可以将自身的状态和代码从一个环境迁移到另一个环境,并恢复执行。
  • 协作性:移动Agent可以和其他Agent进行自主通信,协作完成任务。
  • 安全性
  • 移动功能而不移动数据,减少网络负担和延迟

Mogent解决移动通信失效

1.移动通信失效定义

移动Agent最大的特性是移动性,其通信机制要求位置透明性,可靠性,高效性,异步性,自适应性。但在Agent自主移动过程中,常会导致消息发送到某一网络节点但接收者已经离开无法收到消息的情况,这种因为目标Agent的物理位置变化造成通信不正常的现象称为移动Agent通信失效。通信失效与网络和节点故障无关,完全是由Agent的移动性造成的,这是移动Agent协作的致命缺陷。

2. Mogent系统架构

一个完整的移动Agent通信协议至少包括Agent寻址和消息传送两大部分。Mogent系统采用结构化旅行计划模型。

Mogent的架构中有两个重要实体:

  • Mogent: 即移动Agent,可以协同工作。
  • Host:一个物理节点的抽象,由IP地址或域名来标识,每一个Host安装MogentServer,维护管理本地的Mogent,主要由迁移子系统、通信子系统、安全子系统和开发监控子系统构成。

3.Mogent系统的寻址

Mogent-Server中有两个部件Home和Communicator完成Agent的透明寻址。

Home:记录Host上“出生的”Agent的动态信息,Agent每次迁移到另一台Host必须向出生地登记当前的地址和物理名,基于起始位置的定位。

Communicator:记录当前Host上所有agent的信息,Agent迁移时要向Communicator register 和 unregister, 负责agent之间通信的目标寻址、信件转发和通信失效排除等通信细节。

4.通信失效的解决:消息传送

通信失效问题本质上是通信和移动所共享的“位置”信息未同步造成的。
Mogent系统中引入了“状态”的概念,每个Agent的状态分为迁移态和静止态。

同时引入两个信号量进行集中式同步控制策略,通过Home-Communicator集中管理对目标Mogent的地址信息的互斥访问,从根本上避免通信失效的发生,保证通信的可靠性。

  • 迁移状态:由Home构件记录Agent的状态,当Mogent在一个Host上时状态为静止态,当按旅行计划准备迁移时Mogent要通知Home更新状态为迁移态。
  • 在途信件数:保存在Host上,记录当前时刻以该Mogent为通信对象的在途信件数,发出信件,在途信件数增加,信件到达,在途信件数减一

消息发送机制:Mogent通过控制“在途信件数”和“迁移状态”这两个信号量,确保消息发送者仅向处于静止状态的Agent发送消息

Mogent迁移机制:Agent只有在没有消息发送给他的情况下才能移动。

5.Mogent局限性

  • 频繁迁移,Home的地址注册开销大,会拥挤
  • Agent迁移受到信号量的限制,影响Agent的自主性和移动性

两种名称解析方法:递归和迭代

分布式系统中名称用来标识一个实体,有三种类型——名称、标识符、地址,名称解析就是查询名称的过程。

1.迭代名称解析

客户端把需要解析的名称路径发给根服务器root,根服务器解析出下一个服务器server1的地址返回给客户端,客户端再查询server1,server1再解析出server2的地址…

如此迭代直到能解析出所需实体的地址。例如:考虑绝对路径名:root:<nl, vu, cs, ftp, pub, globe, index.txt>的解析,第四章PPT上有详细的说明

总之迭代名称解析是客户端发起迭代查询。

2.递归名称解析

客户端把需要解析的名称路径发给根服务器root,根服务器解析出server1的地址后,不把结果返回给客户端,直接把名称传给server1,由server1解析后,再传给server2…不断递归,最后将解析出的实体地址返回给根服务器,根服务器再将实体地址返回给客户端。

3.两种解析的比较
递归名称解析的缺陷:要求每台服务器具有较高的性能,根服务器要完成完整的名称解析,开销较大,一般在名称空间的全局层中,采用迭代名称解析。

优点:与迭代名称解析相比,递归解析可以有效的使用缓存提高性能;减少了通信开销,通信开销取决于客户主机和服务器之间的信息交换。

而在DNS解析中:从客户机到本地DNS的查询是递归查询,从本地DNS到到其他DNS服务器之间的查询是迭代查询

移动实体的定位

移动实体的定位方法:使用与位置无关的标识符有效地实现定位。

1.广播和多播

原理:包含该实体所用标识符的消息会广播到每台机器上,并且请求每台机器查看它是否拥有该实体。只有能够为实体提供访问点的机器才会发送回复消息,回复消息中包含访问点的地址。类比ARP

缺点:扩展性不好,随着网络的膨胀,广播变得更加低效。

可以采用多播向特定的一组主机发送标识符,使用多播查找最近的复制实体,但实践证明,选择最近的复制实体没有那么容易。

2.转发指针

原理:每当一个实体转移到另一个位置时,他就会留下一个指针,说明它下一步所在的位置。 例如:当实体从A移动到B时,它将在A中留下一个指针,这个指针指向它在B中的新位置。

定位实体需要遍历转发指针形成的路线。为了避免形成太长的指针链,定期缩短指针链很重要。

优点:简便,一旦找到一个实体,就可以顺着转发指针链查找到实体当前的地址。

缺点:链可能特别长,定位实体的开销较大。链很脆弱,容易断开,只要一个转发指针丢失,就无法定位实体。一个解决办法是让指针链相对短一些,确保转发指针链的健壮性。
链中所有中间位置就必须维护它们的那一部分指针链。

3.基于起始位置的方法

原理:每当实体转移到一个地方时,他会通知起始位置,告诉起始位置自己当前的位置,在定位实体时,首先询问起始位置,以便了解实体的当前位置。起始位置就是创建实体的位置。

优点:大型网络中进行实体定位,如Mogent

缺点:为了与移动实体通信,需要先和起始位置通信,而起始位置和实体本身的位置处于完全不同的位置,增加了通信延迟。 使用起始位置,必须保证起始位置始终存在,否则将无法定位实体。起始位置如果转移到另一个网络,将会无法定位实体。一种解决的办法是:注册起始位置,客户先查找起始位置所在的位置,起始位置相对稳定,可以缓存它。

4.分层方法——创建一颗搜索树

原理: 网络划分成不重叠的分层域。只有一个顶级域,它覆盖了整个网络,每个域又可以划分为更多的子域。最低层的域叫做叶域,与网络中的局域网向对应。

每个层次的每个域都有关联的目录节点,目录节点会持续跟踪实体,形成目录节点树。

顶级域拥有每个实体的位置记录(指针),其中每条位置记录都存储一个指向更低层子域目录节点的指针

优点:查询操作是在局部进行,最差情况下,搜索会从叶域一直查到根域,再从根域到达包括该实体地址的子域。更新,插入和删除操作是局部进行:从叶节点到根节点。

缺点:第一, 定位实体的开销较大,从叶节点到根节点,再到叶节点。一种解决方法是采用指针缓存。第二,扩展性问题: 根节点需要存储所有实体的位置记录, 并为每个实体处理请求, 太多的查询和更新请求会成为瓶颈。解决办法是把根节点和其他高层目录节点划分成多个子节点,每个子节点处理实体的定位请求。
这些子节点最好均匀的扩散到网络中

资源

分布式系统总结part1 中间件,进程迁移,移动通信失效,名称解析,移动实体定位

分布式系统总结part2 Lamport同步与向量时间戳,两大选举算法,三大互斥算法

分布式系统总结part3 复制和一致性(以数据和以客户为中心的一致性),容错(拜占庭将军问题,两阶段与三阶段提交)

分布式系统总结part4 Petri网解决哲学家问题和生产者、消费者问题

Netkit Filesystem 定制和裁剪

Netkit, “The poor man’s system for experimenting computer networking”,是基于Linux的开源网络实验环境,该环境通过启动多台Linux虚拟机,模拟路由器,交换机和PC的网络通信功能,Netkit中预装了路由协议软件包Quagga,可以提供多种路由协议功能,如RIP, OSPF, BGP,IS-IS等,Netkit主要用于网络功能的模拟,而不做网络性能的模拟。

最近花了一周的时间实验Netkit,是网络的大作业,如果不是作业的机会,也不会有空去看这么古老的Netkit,他是北欧开发的一个开源网络实验环境,相比Packet Tracer美观的图形界面,对于没有图形界面的Netkit来说,Netkit的优势在于提供了用户模式的Linux内核,每一个虚拟机就是一个Linux系统,可以更真实地模拟路由等网络功能,用户通过命令行操作虚拟机,能更好地学习和实验网络,而不是学习一个Cisco设备。如果有朋友以后用到Netkit,希望这个Blog会helpful。

Netkit主要由三部分构成:

  • netkit-core: 包含启动虚拟机和网络实验的脚本文件,如vstart,lstart等。
  • netkit-uml-filesystem: 这是一个基于Debian的文件系统,Netkit在该文件系统中安装了软件包,并配置了quagga,ebtables, iptables等服务。Netkit的文件系统是“copy-on-write”的模式,每个虚拟机启动时会生成一个*.disk文件,该文件就是该文件系统的拷贝,在虚拟机中作的任何更改都不会影响Netkit的Filesystem,修改写入*.disk文件.
  • netkit-uml-kernel: 这是一个linux kernel, Netkit通过patch文件对kernel进行了相关配置,Netkit的kernel是用户模式的linux进程,也叫做虚拟机,我们可以在Linux系统如Ubuntu中启动netkit,kernel进程的运行依赖于文件系统。
    我们发现Netkit的文件系统解压后超过10GB,每次启动一个虚拟机就会产生一个10GB的*.disk文件,占用空间较大,我们主要使用Netkit的Quagga进行路由协议的模拟,而Netkit很强大,提供了apache, FTP, openssl,openvpn, DNS, email等功能,我们不需要这些冗余功能,因此我们着手重新制作一个文件系统,并尽量让文件系统容量小,提高Netkit网络实验的性能。

Netkit官方提供了Makefile文件让开发者自己Build文件系统,然而实验后发现官方Makefile无法运行通过,并且Netkit官方指南中并不建议自己Build一个文件系统,在Google后也没有发现更多有用的文档,因此希望通过本Blog详细地描述如何制作一个小巧可用的Netkit文件系统以及遇到的问题。 [more…]

实验成果

最终定制和裁剪的文件系统只有335M,该文件系统基于Debian Squeeze版本定制,没有采用当前的最新版本Wheezy版,因为并不修改Netkit-Kernel,最新版的Wheezy文件系统和现有的Netkit Kernel不兼容。

该文件系统的制作简单来说,分为三个阶段:制作基础的linux filesystem, 配置为可用的Netkit文件系统,安装quagga和必要的软件包。这些步骤都是通过shell命令来完成的。

你可能会问,为什么是335M?我们最早制作的文件系统是2GB,在运行稳定后,我们发现2GB是稀疏文件,在虚拟机中通过df命令我们看到磁盘空间只占用了310M,在基础的Linux文件系统安装好后,磁盘占用空间在250M左右,而我们安装了less,vim,chkconfig,quagga,telnet, telnetd, tcptraceroute这7个必要的包后,磁盘占用空间为310M+,因此我们取文件系统320M来制作,在制作完成后,大小为335M。

最终制作和裁剪的文件系统通过了静态路由,RIP, OSPF Single Area, OSPF Multi Area, BGP的测试。

定制文件系统的源代码在:NetkitNewFS

测试的实验拓扑文件在:NetkitLabs

准备工作

1. Ubuntu 32位环境或虚拟机

Netkit是基于32bit的Linux系统编译的,建议在32bit环境下运行,64Bit的机器安装会缺一些lib包,让工作更加麻烦.

2. 安装Netkit

其次,安装Netkit,参见官方网站,安装很简单,解压+配置环境变量。

也可以看NetkitNewFS源码下的README,有安装方法。

定制流程

整个定制过程大体可以分为三歩:制作基础的Linux内核文件系统,修改文件系统为可用的Netkit文件系统,为文件系统安装Quagga。下面让我们按照这个顺序来看看整个定制流程。

step1.制作基础的Linux内核文件系统:

我们直接写一个bash脚本来完成第一步制作基础的Linux内核的文件系统的工作,完整的脚本内容如下:

脚本不长(netkit-fs-build.sh)
[bash]
#!/bin/bash
echo "====================Installing Base Linux System======================"
FS_NAME=netkit-fs-light
MOUNT_DIR=/mnt/nkfs2
FILESYSTEM_SIZE=320

each cylinder has 63 sectors, each of which is 512 bytes

let CYL_COUNT=$FILESYSTEM_SIZE*1048576/32256

Create empty netkit-fs file

dd if=/dev/zero of=$FS_NAME bs=1M count=0 seek=$FILESYSTEM_SIZE

Create image partition

echo ",,L,*" | sfdisk -q -H 1 -S 63 -C $CYL_COUNT $FS_NAME

Binding lookback device to netkit-fs

device_name=$(losetup -f)

The offset is the size of one track

losetup –offset 512 $device_name $FS_NAME

Create ext2 filesystem

mkfs.ext2 $device_name
losetup -d $device_name

Mount netkit-fs

rm -rf $MOUNT_DIR
mkdir $MOUNT_DIR
mount -o loop,offset=512 -t ext2 $FS_NAME $MOUNT_DIR

Install the base filesystem from Internet

debootstrap –arch i386 squeeze $MOUNT_DIR http://ftp.cn.debian.org/debian
echo "=================Base Linux System Installed Success=================="

umount $MOUNT_DIR
echo "done!"
[/bash]
脚本的功能是创建一个320M的文件,采用sfdisk创建Linux分区表,绑定到环回设备上创建ext2文件系统,在mount到主机的/mnt/nkfs2下,通过debootstrap命令联网联网下载并安装Linux Squeeze 文件系统。具体每一歩,在脚本注释中。
值得注意的是,脚本的最后部分,即命令:
[bash]
debootstrap –arch i386 squeeze $MOUNT_DIR http://ftp.cn.debian.org/debian
[/bash]
需要通过联网安装debian squeeze内核,该文件系统下载解压后只有200多兆,选择squeeze主要是为了和netkit-kernel兼容。
保存脚本文件,比如存为netkit-fs-build.sh,打开终端,cd到脚本文件所在目录下,使用命令:
[bash]
sudo sh netkit-fs-build.sh
[/bash]
运行脚本(注意使用root权限),即可得到基础的Linux文件系统了。

step2.修改文件系统为可用的Netkit文件系统:

1. 从Netkit原始文件系统中拷贝必要的文件,并修改netkit-phase1和netkit-phase2

上一步得到的文件系统,并不可以直接用于Netkit,启动虚拟机会失败,需要用到Netkit原始的文件系统中的部分文件进行补充,将其配置成可用的Netkit FileSystem。
所有需要添加到自制文件系统中的Netkit原始文件系统中的文件我们把他们放在了netkit-tweaks文件夹下,其目录结构如下,各自作用见注释:
[text]
netkit-tweaks
—- etc
———init.d #contains netkit-phase1 and netkit-phase2, the two important file for netkit bootstrap
———network #interfaces configure
———inittab # inittab file for bootstrap runlevel
———resolv.conf # DNS parse
———sysctl.conf # net.ipv4.ip_forward=1 for ip forwarding, important configure, enable ip packet forwarding
—–sbin
———mingetty # mingetty is a minimal getty program for watching virtual termianl
[/text]

该文件夹下所有的文件都可以在Netkit原始文件系统下找到,可以通过挂载原始文件系统把他们从挂载地址拷贝出来,其中/mnt/nkfs1为自定义的挂载地址:
[bash]
mount -o loop,offset=32768 netkit-fs-i386-F5.2 /mnt/nkfs1
[/bash]
文件netkit-phase1和netkit-phase2需要稍作修改, 修改netkit-phase1中开头部分为:
[bash]

BEGIN INIT INFO

Provides:

Required-Start:

Required-Stop: $all

Default-Start: 2 3 4 5

Default-Stop: 0 1 6

Short-Description:

Description:

END INIT INFO

[/bash]

修改netkit-phase2中开头部分为:
[bash]

BEGIN INIT INFO

Provides:

Required-Start: $all

Required-Stop:

Default-Start: 2 3 4 5

Default-Stop: 0 1 6

Short-Description:

Description:

END INIT INFO

[/bash]
$all的意思是最后,在netkit-phase1中表示最后停止,在netkit-phase2中表示最后开始,这是启动优先级的配置。
同时在netkit-phase2中,并将文件中/bin/sh -c ‘source /hostlab/$HOSTNAME.startup’这种类似的语句修改为”source /hostlab/$HOSTNAME.startup”。
因为用/bin/sh启动 startup脚本会会报”/bin/sh: source not found”的错误,默认用bash启动startup脚本就不会报错。
至此,所有需要添加进自制文件系统的文件已经全部在netkit-tweaks文件夹中了。

2. 拷贝必要的文件到文件系统中

首先挂载刚刚创建的文件系统netkit-fs-light:
[bash]
FS_NAME=netkit-fs-light
NETKIT_TWEAKS_DIR=netkit-tweaks
MOUNT_DIR=/mnt/nkfs2
mount -o loop,offset=512 -t ext2 $FS_NAME $MOUNT_DIR
[/bash]
下面需要把一些必要的文件拷贝到自制的文件系统中,其中**/etc/sysctl.conf**文件很重要,作用是将ipv4.ip_forward设为1,否则虚拟机无法ping通:
[bash]
cp -Rvf $NETKIT_TWEAKS_DIR/etc $MOUNT_DIR/
cp -Rvf $NETKIT_TWEAKS_DIR/sbin $MOUNT_DIR/
[/bash]

3. 改变root根目录位置,准备安装必要的工具和软件

改变root的执行程序参考的根目录位置至挂载文件系统的位置,方便我们直接配置文件系统和使用文件系统中的命令:
[bash]
chroot $MOUNT_DIR
[/bash]
挂载proc文件系统,proc文件系统是提供Linux内核数据结构接口的伪文件系统,文件系统并没有挂载proc文件系统,proc文件系统一般挂载在/proc目录下,如果没有挂载,虚拟机启动时会出现mtab无法初始化错误,也就是mtab文件会被损坏,因此我们为了让文件系统更完善,增加挂载proc文件系统的命令。
[bash]
mount -t proc none /proc
[/bash]

4. 安装必要的软件包

紧接着为文件系统更新和安装一些必要的工具和软件:
[bash]
apt-get update
apt-get install less
apt-get install vim
apt-get install chkconfig #为设置netkit-phase文件的启动优先级
[/bash]

5. 设置netkit-phase1和netkit-phase2脚本的启动优先级

在Debian 6.0之后,不能采用update-rc.d命令设置init.d目录下启动文件的优先级,采用insserv命令可以简单设置。我们尝试过将rcX.d文件从原始netkit文件系统中拷贝到新的文件系统中,发现不能使用,rcX.d这些链接文件是需要通过命令来生成的。在原始的netkit Makefile中采用update-rc.d设置是不成功的,采用insserv是我们做出的改进。
将netkit-phase1和netkit-phase2链接到rcX.d并设置优先级:
[bash]
insserv netkit-phase1
chkconfig netkit-phase1 on
insserv netkit-phase2
chkconfig netkit-phase2 on
[/bash]

6. 禁止不必要的启动项,取消挂载

取消cron job的启动项,加快启动
[bash]
update-rc.d cron remove
[/bash]
最后退出并取消挂载:
[bash]
exit # 退出新文件系统的根目录环境,回到ubunu根目录环境下
umount $MOUNT_DIR/proc
umount $MOUNT_DIR
[/bash]
如果因为设备正忙而无法取消挂载,可以察看相应进程,先杀死进程再取消挂载:
[bash]
fuser -m $MOUNT_DIR

if out put is /dev/sdc1: 538

ps -aux | grep 538

then kill the process by proccess id

[/bash]

step3.为文件系统安装quagga:

以上两步都是在Ubuntu主机下运行的,现在我们自制的Netkit FileSystem应该可以正常启动虚拟机了,最后一步需要启动虚拟机并在虚拟机内安装quagga。
首先启动Netkit虚拟机:
[bash]
FS_NAME=netkit-fs-light
vstart pc1 -m $FS_NAME -M 512 –eth0=tap,10.0.0.1,10.0.0.2 –append=rout:98:1 –W
[/bash]
该命令中参数解释如下:
–m $FS_NAME 表示以指定的文件系统作为虚拟机的文件系统
-M 512 指定内存512M,以为要联网安装,所以不能用默认的32M内存,太小
–eth0=tap,10.0.0.1,10.0.0.2 绑定eth0网卡到tap碰撞域,tap碰撞域是netkit保留的碰撞域,通过tap可以连接主机上外部因特网,10.0.0.1是TAP-ADDRESS是在Tap碰撞域中分配给主机Ubuntu的地址,10.0.0.2是GUEST-ADDRESS是分配给虚拟机的地址,此时可以ping任意的因特网,如baidu.com是可以成功的。
–append=rout:98:1 为netkit-kernel提供的参数
-W 表示对虚拟机的修改就是对Netkit文件系统的修改,不产生*.disk文件
启动后的虚拟机如图:
netkit
接下来在虚拟机中安装必要软件和工具:
[bash]
apt-get install telnet
apt-get install telnetd
apt-get install tcptraceroute
[/bash]
接着安装quagga,注意安装的quagga 版本为0.99.20.1,太高的版本可能会因为与内核版本不兼容:
[bash]
apt-cache policy quagga # 查看quagga可安装的版本,默认就有 0.99.20.1版本
apt-get install quagga -v 0.99.20.1
[/bash]
察看占用空间,最后退出虚拟机:
[bash]
dh -lf # 320M is the smallest solution, since up to now, 310M has been used
halt
[/bash]
至此,我们的文件系统就制作成功了,以上step2和step3的脚本,请参考configure-netkit.sh,我采用的是手工配置,一方面命令不多,另一方面手工配置可以保证每一步的正确性。通过查看文件系统的信息我们看到文件系统为335M左右。
使用这一自制文件系统,我们通过了rip, ospf single area, ospf multi area和simple bgp的网络实验测试。Netkit lab实验在官方网站中有详细的教程,在此就不详细描述实验了,能做出这个文件系统,我表示很欣慰,同时也学习到文件系统的制作是通过shell命令完成,开始以为需要C方面的知识。

遇到的问题

在实验中,遇到了很多问题,这些问题对定制该文件系统有很大价值,在此做一个记录和说明,如果遇到相似的问题,可以参考。

1. 虚拟机启动闪退

我们在做netkit文件系统时,有三个组员出现了启动虚拟机闪退的问题,我们为此花费了很多时间,的解决方法如下:
1.检查基础Linux文件系统是否安装成功,之前是因为文件系统的分区就没有创建成功,造成debootstrap也没有成功,文件没有安装好,启动闪退。
2.基础文件系统安装好了,拷贝了netkit-phaseX等文件后,启动虚拟机闪退,这是因为netkit-phaseX文件没有设置好优先级,需要在Ubuntu主机中通过insserv和chkconfig设置优先级。方可启动不闪退。

2. Quagga安装失败

我尝试过在Ubuntu中,通过chroot后,在文件系统中安装quagga,此时安装的quagga的版本不是0.99.20.1版,安装失败,之后又在虚拟机种通过手工编译安装quagga,依然失败。
最后的解决方法是,在虚拟机中,采用apt-get install quagga –v 0.99.20.1安装,-v指定版本,quagga的安装需要依赖netkit提供的内核,在ubuntu安装是没有netkit内核的,造成不能使用。

3. IP Forwarding问题

Quagga安装成功后,lab可以启动了,路由可以学习到路由,但是不能ping通,纠结一阵之后,我们发现是ip forward在Linux中默认关闭了,打开就可以。因此从原netkit文件系统中拷贝sysctl.conf文件,该文件可以永久设定net.ipv4.ip_forward=1,这样ip forward在启动时就已经打开,虚拟机之间就可以ping通了。

4. Fedora- x64下配置虚拟机和配更改文件系统的问题(from Aqua)

在Ubuntu系统中配置完成实验之后,我们尝试了在64位Fedora系统中配置Netkit虚拟机。由于Netkit是基于32位系统编译,所以要首先解决64位系统中的不同函数库的依赖问题。在Debian系统中,解决32位函数库依赖只需要apt-get ia32-libs即可。但是在Fedora的yum系统中,并不存在这个名称的包。经验证,如下命令解决问题。
[bash]
su -c ‘yum -y install –skip-broken glibc.i686 arts.i686 audiofile.i686 bzip2-libs.i686 cairo.i686 cyrus-sasl-lib.i686 dbus-libs.i686 directfb.i686 esound-libs.i686 fltk.i686 freeglut.i686 gtk2.i686 hal-libs.i686 imlib.i686 lcms-libs.i686 lesstif.i686 libacl.i686 libao.i686 libattr.i686 libcap.i686 libdrm.i686 libexif.i686 libgnomecanvas.i686 libICE.i686 libieee1284.i686 libsigc++20.i686 libSM.i686 libtool-ltdl.i686 libusb.i686 libwmf.i686 libwmf-lite.i686 libX11.i686 libXau.i686 libXaw.i686 libXcomposite.i686 libXdamage.i686 libXdmcp.i686 libXext.i686 libXfixes.i686 libxkbfile.i686 libxml2.i686 libXmu.i686 libXp.i686 libXpm.i686 libXScrnSaver.i686 libxslt.i686 libXt.i686 libXtst.i686 libXv.i686 libXxf86vm.i686 lzo.i686 mesa-libGL.i686 mesa-libGLU.i686 nas-libs.i686 nss_ldap.i686 cdk.i686 openldap.i686 pam.i686 popt.i686 pulseaudio-libs.i686 sane-backends-libs-gphoto2.i686 sane-backends-libs.i686 SDL.i686 svgalib.i686 unixODBC.i686 zlib.i686 compat-expat1.i686 compat-libstdc++-33.i686 openal-soft.i686 alsa-oss-libs.i686 redhat-lsb.i686 alsa-plugins-pulseaudio.i686 alsa-plugins-oss.i686 alsa-lib.i686 nspluginwrapper.i686 libXv.i686 libXScrnSaver.i686 qt.i686 qt-x11.i686 pulseaudio-libs.i686 pulseaudio-libs-glib2.i686 alsa-plugins-pulseaudio.i686’
[/bash]
这个长命令涵盖了ia32-libs中包含的所有依赖文件。
但是在生成文件系统过程中,由于Debian的Debootstrap并不能很好的兼容Fedora系统,导致生成文件系统失败。尚未找到更好的解决方案。
在Fedora下的尝试不成功,这也就是我们选取Ubuntu的原因,Netkit是32bitDebian系统,在32bitDebian系统下编译会更好。

参考资源

[1] Netkit官方网站
[2] Netkit官方FAQ
[3] Netkit 官方实验和介绍
[4] Netkit用户问答
[5] Debian内核release介绍
[6] An introduction to services, runlevels, and rc.d scripts
[7] Install quagga as linux router
[8] Quagga Tutorial for ip forwarding
[9] How to umount when device is busy

IPsec之IP层安全架构

什么是IPSec

IP层的安全架构由IPsec定义,IPsec(Internet Protocol Security), 是一个开放标准的框架,它是为IP层提供端到端的数据加密,数据完整性和数据认证的协议簇。

IPsec最早于1995年在RFC1825和RFC1829中定义,之后在1998年IETF又重新修改为RFC2401和RFC2412, 在RFC2401中引入秘钥交换协议(IKE)管理安全联盟(Security Association, SA), 而后在2005年,IETF又发布了新的文档定义RFC4301和RFC4309,引入IKEv2管理SA。本文即基于RFC4301来阐述IPsec的主要功能和工作机制。

IPsec的设计意图是为IPv4和IPv6提供安全保护,在RFC6434之前IPsec是必选内容,而对IPv4是可选的。IPv6的地址空间广阔,更有可能成为DDos, IP欺诈等网络攻击的目标,因此IETF旨在随着IPv6的发展,推广IPsec,提高IP层的安全性。

IPsec是OSI第三层协议,它可以为上层的基于TCP和UDP协议的数据流提供数据安全保护,如SSL不能保护UDP的通信流,就可以借助IPsec保护数据流。

IPsec可以在一个主机、网关或独立的设备中进行实现,从IP层提供高质量的安全服务,包括访问控制,无连接的完整性,数据源认证,重放攻击检测和拒绝和数据加密等.

IPsec定义了IPsec作为一个IP层防火墙所需的最小功能集。IPsec进行访问控制的规则主要定义在安全规则数据库中(Security Policy Database, SPD),IPsec根据这些规则对数据包进行保护、丢弃或通过的处理。[more…]

IPsec安全功能组成

总体来说IPsec的安全功能由两个安全协议(AH和ESP)和建立安全联盟的协议(IKE)组成。

1. 两种安全协议

包括认证头协议(Authentication Header,AH)和封装安全载荷协议(Encapsulating Security Payload, ESP)。

AH,提供数据完整性,反重放攻击和可选的数据源认证的安全特性。通常使用单向Hash函数的摘要算法——MD5和SHA1实现其安全特性。

ESP,可以同时提供数据完整性,数据加密,反重放攻击等安全特性。通常使用DES,3DES和AES等加密算法来进行数据加密。使用MD5和SHA1实现数据认证。

AH和ESP都采用SPD来提供访问控制。IPsec要求一定要实现ESP,AH可选,一般ESP就可以满足大部分的安全需求.

AH在实践中用的少,其原因有二:第一,没有数据加密,数据是以明文传输,而ESP提供数据加密。第二,AH提供数据源认证,一旦数据源地址发生改变,校验失败,所以AH不能穿越NAT。但是在PC到PC的通信中,采用AH更好,因为ESP的开销较大。

2. 建立安全联盟的协议

Internet Key Exchange, IKE是用于建立和维护SA的协议,在端到端之间进行协商,确认通信端的身份,建立安全的通信关联。

在1998年RFC2401中第一次在IPsec中引入IKE,8年后RFC4301中更新为IKEv2,RFC4301中采用的是IKEv2。IKEv1和IKEv2的主要区别是:

  • IKEv2比IKEv1消耗的带宽更少。
  • IKEv2支持扩展认证头协议(Extensible Authentication Protocol, EAP), 而IKEv1不支持,IKEv2对无线的支持更好。
  • IKEv2支持MOBIKE,而IKEv1不支持,IKEv2可以提供移动通信支持。
  • IKEv2内内嵌支持NAT,而IKEv1不支持。
  • IKEv2可以检测隧道是否alive,但IKEv2不支持。
  • IKEv2的引入可以在建立安全关联时,提供更好的安全特性。

IPsec数据处理模型

1.1Top Level IPsec Processing Model

Psec在数据处理时,在保护接口(Protected Interface)和非保护接口(Unprotected Interface)之间创建了一个分界(Boundary)。数据从非保护接口进入,IPsec会基于AH或ESP进行访问控制,对数据的处理结果有三种:保护(Protected), 丢弃(Discard), 通过(Bypass)。

IPsec对IP数据包处理有两种情况:

Inbound,即IP输入,数据从非保护接口端进入穿过IPsec,从保护接口端输出。

Outbound, 即IP输出, 数据从保护接口端进入,从非保护接口端输出。

IPsec两种封装模式和应用场景

IPsec的一个重要应用场景就是VPN。
1.2IPsec VPN应用场景

如图上图所示,企业的各个内网间通过隧道连接,而隧道模式是IPsec重要的应用模式。

IPsec提供两种封装模式,传输模式和隧道模式,主要分为四种场景:

1.3IPsec四种应用场景

1. Gateway-to-Gateway网关到网关,如上图的A场景,Alice的PC要访问公司HR的服务器,需要通过隧道模式进行安全连接,该隧道就是建立在两个网关之间。这是通常的VPN的场景。

2. End-to-Gateway端到网关,如图中的B场景,从Alice的PC端连接到另一个IPsec网关,这也是在隧道模式下。

3. End-to-End端到端,如图中的C场景,采用隧道模式一个Cisco路由器和PIX防火墙通过隧道模式连接。

4. 传输模式,如图中的D场景传输模式,IPsec传输模式一般用于端到端的情况,或者端到网关,此时网关被当作一个主机。D场景中Alice PC用传输模式连接PIX防火墙,对防火墙进行管理。

可以发现,IPsec的传输模式和隧道模式的区别:

传输模式一般只用于端到端的情况,如PC-to-PC。传输模式下,AH,ESP不对IP头进行修改和加密。

隧道模式可以用于任何一种场景,多用于网关到网关的场景,但是隧道模式下,AH,ESP会在源IP报文前面添加外网IP头,隧道模式会多一层IP头的开销,在端到端的模式中,建议使用传输模式。

IPsec重要加密和认证算法

IPsec为了保证数据的完整性,实现数据的认证和加密,相关算法有:
数据加密算法:

  • DES,基于共享秘钥进行数据加密和解密,采用56bit的秘钥保证加密的性能。
  • 3DES,与DES相似,提供数据加密和解密,采用变长的秘钥。
  • Diffie-Hellman(D-H): 这是一个公钥加密协议。它可以在通信的两端基于MD5或DES算法建立共享秘钥,实现安全通信。D-H主要用于IKE,建立安全session会话。秘钥一般为768bit或1024bit。
  • RSA,基于公钥的加密,来实现数据认证,例如在Cisco的路由上的IPsec采用D-H交换来决定两端的私钥,并生成共享秘钥,采用RSA签名进行公钥认证。

数据认证算法:

  • Message Digest 5(MD5): 是一个Hash算法,用于数据包验证。这是一个单向的加密算法,IKE,AH和ESP中采用MD5进行数据认证,防止重放攻击。
  • Secure Hash Algorithm(SHA-1): 是一个Hash算法,用于数据包验证。IKE,AH和ESP中采用MD5进行数据认证,防止重放攻击。

IPsec安全协议之AH认证头协议

AH协议主要用于保护传输分组的数据完整性,并可以进行数据源认证。它采用滑动窗口和丢弃旧数据包的技术来防止重放攻击。但是AH不提供数据加密。

在IPv4和IPv6中,AH试图保护所有的IP头字段,除了TTL,ECN, Flags等可变字段。

2.1AH的两种数据封装模式

如图,AH提供两种封装模式,传输模式和隧道模式。

传输模式下,AH采用单向Hash算法,对IP头和数据载荷进行摘要,形成AH头部,AH头部放在IP头部和数据之间。在AH处理前后IP头部不发生变化。

隧道模式下,AH对原IP头进行Hash摘要,生成新的IP头。摘要生成的头被放于新的IP头之后,原IP头之前。

AH不能通过NAT,因为NAT会改变源IP地址,破坏AH头部,造成包被IPsec另一端拒绝。

2.2AH头部字段

如所示是AH的头部字段,包括:

下一个头(Next Header):8bit,标识被传输的IP报文采用的是什么协议,如TCP或UDP。

载荷长度(Payload Len):8bit认证包头的大小。

保留字段:16bit为将来应用做保留,目前都置0。

安全参数索引(SPI): 32bit与目的IP地址一起来标识与接收方的安全关联。

序列号(Sequence Number):32bit,单调增值的序列号,防止重放攻击。

完整性检查值(Integrity Check Value, ICV): 变长字段,一般32bit的倍数,包含认证当前包所必须的数据。

IPsec安全协议之ESP封装安全载荷协议

ESP协议为IPsec提供数据源认证,数据完整性和数据加密功能。与AH不同的是在传输模式下,ESP不提供对整个IP数据包的数据完整性和认证功能,只对IP数据载荷进行加密和认证。然而在传输模式下,提供对整个IP包的加密和认证,生成新的包头。

2.3ESP的两种封装模式

如图是ESP的两种封装模式。

传输模式下,ESP只对上层协议数据加密,不加密IP头,只对ESP头和加密的上层协议数据进行认证,不认证IP头,生成的新IP报文,IP头不变,ESP头和加密的数据放在IP头之后。

隧道模式下,ESP对整个IP头和上层协议数据加密,对ESP头和加密数据进行认证,生成新的IP头,包括外部IP源、目的地址。但新的IP头不参与认证。

在ESP加密和认证中,总是先对数据加密再HASH认证,这样可以让接收端在解密之前,对数据包进行快速检测,防止重放攻击。

2.4ESP的头部字段

如图2.4,是ESP定义的头部字段:

安全参数索引(SPI): 32bit与目的IP地址一起来标识与接收方的安全关联。

序列号(Sequence Number):32bit,单调增值的序列号,防止重放攻击。

载荷数据(Payload Data): 变长,受保护的IP数据,其数据内容由下一个头字段标识。

填充(Padding):一些加密算法用此字段将数据填充至块的长度,和下一字段对齐。

填充长度:8bit,标识填充字段的长度。

下一个头(Next Header): 标识被传输数据所用的上层协议。

完整性检查值(Integrity Check Value, ICV): 变长字段,一般32bit的倍数,包含认证当前包所必须的数据。

SA安全联盟

安全联盟(Security Association, SA也有翻译为安全关联、安全连接),是IPsec中的重要概念。在IPsec发送端和接收端进行安全通信之前,IPsec需要通过SA建立安全关联来确定如何建立安全通信。

IPsec为安全通信提供数据加密,数据完整性和认证这三种服务,当服务的类型确立后,通信的两端需要确立采用什么加密(DES或3DES)和认证(MD5或SHA-1)算法, 再决定算法后又需要交换session秘钥。可以对于一个安全通信会话,需要交换很多信息,所以引进SA的概念来管理安全通信参数和算法等信息。

总之,SA就是IPsec进行安全通信的一簇算法和安全参数,如封装模式,发送方和接收方的IP地址,兴趣流等,这些参数被用于加密和认证。

SA是单向的,通信的两端如果要双向通信,则需要建立一对SA,这样当任何一方的SA被破解,另一方的SA不会受影响。

3.1SA的结构示例

如图是一个SA的结构示例,包括:

目的地址

安全参数索引(SPI): 每一个通信端都有唯一的SPI,IPsec将基于SPI,源地址和目的地址在SAD数据库中搜索安全参数记录。

IPsec安全协议

秘钥

其他的SA属性,如IPsec Lifetime

3.2SA的工作机制

如图所示,是一个在具体通信中路由器R1和R2的IPsec SA参数,可以看到SA是单向的,从任何一方到另一方都要建立SA。当一个数据包需要IPsec保护,首先它会查询SAD数据库(安全关联数据库),将SA中的SPI插入到IPsec的头部,当接收端收到数据包后,接收端会根据目的地址和SPI在自己的SAD中找到相应的SA, 如果SA匹配,则进一步采用AH或ESP对数据包进行处理。

3.3不同通信端的不同SA

如图所示,是在一个网络中,不同的主机间的通信采用了不同IPsec安全参数,从Client到Router A采用传输模式ESP,Router A到Router B采用隧道模式AH,这些安全参数都需要SA来管理。

SA如何判断网关的安全性—-IKE

SA是安全连接,而如何建立安全连接呢?如何确定网关的安全信呢?需要因特网秘钥交换(Internet Key Exchange)协议,IKE旨在对IPsec通信的两端进行安全会话秘钥交换,建立和维护SA。

IKE的具体工作机制在RFC2409中定义,而在RFC2401中使用的IKEv2在RFC4306中有定义。

IPsec重要数据库

  1. Security Policy Database (SPD)

    SA是管理安全通信的参数,但不管理具体的数据包的处理,对每一个IP数据包采取什么样的安全服务,如何进行访问控制,需要这些访问控制的信息就存储在安全规则数据库SPD中。

    每一个IPsec至少要实现一个SPD,SPD是一个有序数据库,它存储访问控制列表(Access Control List, ACL),防火墙或路由的包过滤规则等。

    SPD中的记录,对数据的处理有三种选择:丢弃(Discard),通过(Bypass)和保护(Protect)。

    SPD在逻辑上被分为三部分:

    SPD-I:包括对于inbound的数据包,需要采取丢弃和通过的规则。

    SPI-S:包括需要对数据进行保护的规则。

    SPI-O:包括对于outbound的数据包,需要采取丢弃和通过的规则。

  2. Security Association Database (SAD)

    SA安全管理的相关信息,需要存储在SAD中,SAD是一个概念上的数据库,只是以某种列表的数据结构来存储SA。
    每一个实体定义了SA的安全参数。对于Outbound的数据包,SAD的实体指向SPD缓存中的SPD-S部分。对于Inbound的数据包,只通过SPI或IPsec协议来查找SA。

    具体的结构SA实体结构参见前面给出的示例.

  3. Peer Authorization Database (PAD)

    PAD,端认证数据库,提供SA管理协议,如IKE与SPD的之间的管理。有时候SA发生变化,SPD就地不到及时更新,此时就需要借助PAD对SA和SPD做出调整。

    PAD是一个有序数据库,它建立了IKE ID和SPD实体的关联。PAD支持6种ID类型:

    DNS Name

    Distinguished Name

    Email Address

    IPv4 Address

    IPv6 Address

    Key ID

    PAD的相关工作机制是:

    在IKE SA建立时,发送方和接受方都会通过IKE ID进行身份确认,确认之后向对方发送认证信息。当一个IKE信息收到后,便会通过IKE ID在PAD数据库中找到匹配的实体,每一个PAD实体都记录了进行身份认证的方法,它可以保证对不同的通信端采用正确的身份认证。

IPsec的工作机制

5.1IPsec工作机制

如图5.1所示,IPsec的工作流程可以分为5个阶段:

1. 决定兴趣流

IPsec对IP包的保护是需要消耗资源的,并非所有的流量都需要IPsec保护,那些需要IPsec保护的数据流就叫做兴趣流,IPsec会对兴趣流进行访问控制。
如发起方的兴趣流式192.168.1.0/24 -> 10.0.0.0/8,接收方的兴趣流是10.0.0.0/8->192.168.1.0/30,那么取交集,兴趣流IPsec保护的兴趣流就是192.168.1.0/30 <-> 10.0.0.0/8

IPsec通信开始时,发送方如图5.1的Router A要将兴趣流发送给接收方Router B。

2.IKE 第一步

对IPsec的通信端进行身份认证,协商并建立IKE SA。这一步建立的是IKE安全连接,通过Diffie-Hellman算法交换共享秘钥,为IKE第二步通信建立安全隧道。

3.IKE第二步

IKE第二步,主要是建立IPsec SA,在IKE第一步建立的IKE SA的基础上协商并建立IPSec SA。周期性的协商,保证SA的安全性,可选采用Diffie-Hellman交换算法。

4.IPsec数据传输

在IPsec安全隧道建立后,采用IPsec SA确立安全参数,秘钥,进行数据通信。

5.IPsec会话停止

IPsec SA通过检测和超时来停止会话,在SA停止IPsec后,如果还需要数据传输,则需要重新进入IKE第一步或IKE第二步重新协商建立新的SA。

References

RFC4301

Cisco IPsec Overview

技术点详解—IPSec VPN基本原理

如何配置VPS并发布WordPress Blog?(第一篇)

最近将VPS放到digitalocean上, 因为之前的VPS被关停了,所以再找一个, 相信这次会稳定了,之前的服务器是CentOS5.9,而现在的版本是CentOS7,以下的一些配置可能不正确了,可以参考这个链接LAMP with Centos 7.0

目标

发布个人的WordPress博客网站,配置LAMP环境,并用GitHub来发布Blog,不用FTP,会很慢。
[more…]

连接VPS

我在Mac下,所以很方便的连上VPS, 为了方便管理直接用root登陆, 第一次配置安全性先不考虑,用root方便些
[bash]
ssh -l root ip.address
[/bash]
如果在Windows下,下载一个putty就可以很方便的连上VPS,SSH端口是22,VPS默认可以用SSH连接。

有用的命令

[bash]
cat /etc/release #查看Linux的版本
uname -a # 查看内核的版本
ifconfig -a # 查看网卡情况
nman localhost # 查看端口的情况
iptables -vL # 查看防火墙的情况
netstat -aln | grep 80 # 查看网络连接情况
init 6 # 重启
passwd # 修改当前用户的密码,可以该root密码
[/bash]

Linux running level

Linux下的运行级别,一个常识

0 – halt

1 – Single user mode

2 – Multiuser, without NFS

3 – Full multiuser mode

4 – unused

5 – X11

6 – reboot

[bash]
init running-level # 触发运行级别,关机,重启各种方便
[/bash]

关闭selinux

selinux经常捣乱,先把它关了,还要永久关
[bash]
getenforce # 查看selinux的状态
sestatus # 一样,查看selinux状态
vim /etc/sysconfig/selinux # 将SELINUX 改为disabled状态,然后重启
setenforce 0 # 只能暂时改变selinux状态,不能永久更改,只有上面的方法可以
init 6 # 重启
[/bash]

这个在DigitalOcean的镜像中不需要配置.

安装Apache

[bash]
yum -y install httpd
chkconfig –levels 235 httpd on # 将httpd进程设置为开机启动
service httpd start # 此时可以用ip访问VPS,如http://129.29.10.10,如果可以访问便安装成功
[/bash]
Apache在CentOS的DocumentRoot是“/var/www/html”, 配置文件在”/etc/httpd/config/httpd.conf”

无奈,第一个问题遇到了,我的Apache访问不了,纠结半天,原来是防火墙iptables的问题。

打开防火墙

CentOS的iptables默认只让注册过的端口通过,而80端口没有注册过,不能通过防火墙。
[bash]
vim /etc/sysconfig/iptables

将 “-A RH-Firewall-1-INPUT -j REJECT –reject-with icmp-host-prohibited” 这行注释了,保存退出

service iptables restart
[/bash]
BTW,如果采用以下的方法enable 80 端口,我今天成功了, 以前没有成功不知为何,不过上面的方法是肯定好的,下面的方法是一个安全点的办法。
[bash]
iptables -A INPUT -p tcp –dport 80 -j ACCEPT
iptables -A INPUT -p tcp –dport 443 -j ACCEPT // 添加443 SSL端口未来会用
service iptables save // /etc/sysconfig/iptables 文件会被重写
service iptables restart
[/bash]
此时再访问http://youripaddress就会有apache界面了。

在DigitalOcean中,不需要配置本项.

安装MySQL

[bash]
yum install -y mysql mysql-server
chkconfig –levels 235 mysqld on
service mysqld start
mysql_secure_installation // 设置root密码,我这次谨慎了一下,没有全部选yes,大家看情况,记住自己的root密码
mysql -uroot -p // 进入MySQL,看看玩玩
[/bash]

在DigitalOcean中安装的是MariaDB, 兼容MySQL, 具体看参考链接.LAMP with Centos 7.0

安装PHP

我被坑过,CentOS 5.9的yum的默认包库中PHP是5.1.6,后来WordPress跑不了(至少5.2.4),所以需要更新一下yum。

如果想了解更详细的信息,可以看看这个链接
Install Apache, MySQL 5.5.32 & PHP 5.5.0 on RHEL/CentOS 6.4/5.9 & Fedora 19-12
[bash]
yum info name of module # 查看某个包的信息
rpm -Uvh http://dl.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-5.rpm
yum –enablerepo=remi,remi-test install -y php php-common
yum –enablerepo=remi,remi-test install php-mysql php-pgsql php-pecl-mongo php-sqlite php-pecl-memcache php-pecl-memcached php-gd php-mbstring php-mcrypt php-xml php-pecl-apc php-cli php-pear php-pdo # 安装PHP会用到的module
service httpd restart
vim /var/www/html/phpinfo.php
[/bash]
输入:
[php]
<?php
phpinfo();
?>
[/php]
再访问http://ipaddress/phpinfo.php, 查看php的状态

VPS DNS解析

有了VPS,再买一个域名吧,我在godaddy上买了一个域名,用DNSPod来解析,国内的DNS解析,会快一些。

需要在godaddy上将NameServer更改为:

[text]
F1G1NS1.DNSPOD.NET
F1G1NS2.DNSPOD.NET
[/text]
再到DNSpod上注册,填写IP,等信息,就能简单完成DNS解析,从此以后就可以用域名访问VPS了。

本章结束

OKay, that’s it! LAMP环境安装好了,一切就绪,坐等发布WordPress了,请看如何配置VPS并发布WordPress Blog?(第二篇)

如何配置VPS并发布WordPress Blog?(第二篇)

完成了VPS的LAMP环境的配置,接下来的工作就是要将WordPress Blog部署到VPS上。方法多种多样,例如可以在VPS上配置FTP,用FTP将文件传输到VPS上,以后就可以直接在VPS上写博客了,一次性的买卖,方便,听起来很不错,但是不安全,如果哪天VPS Down了数据就没了。

我采取的办法是在本地写博客,然后发布到GitHub,然后VPS端Clone到本地,这样做的原因如下:

[more…]

  • WordPress Blog作为轻量的博客,主要发布文字,图片是用第三方的图床,博客本身的数据量不大。
  • FTP传输速度不理想。
  • GitHub在VPS端运行很快,VPS毕竟是服务器,网速快,因此部署Blog很快。
  • 版本控制,本地有数据备份,以后要迁移VPS也可以轻松搞定。
  • WordPress的Blog数据是写入MySQL的,因此发布WordPress时的一个大问题就是要处理MySQL的数据,其实基本的mysqldump就可以了。

VPS 配置GIT

[bash]
rpm -Uvh http://dl.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm // 这个在前面的php安装时输入过了,可以忽略
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-5.rpm // 这个在前面的php安装时输入过了,可以忽略
yum install git-core -y
git –version
[/bash]
一定配置一下SSH,这样不会在git clone时报错,当然建立github repository和使用github都是默认掌握了。
Set up git

Enable SSH Git

VPS MySQL权限配置

刚装MySQL时运行过mysql_secure_installation,如果所有选项都yes了,那么VPS的mysql只能是本地的root可以访问,blog访问不了,这一步很关键,也让我头疼了很久。

进入MySQL
[bash]
mysql -u root -p
[/bash]
[sql]
CREATE USER ‘monty’@’localhost’ IDENTIFIED BY ‘some_password’;
GRANT ALL PRIVILEGES ON . TO ‘monty’@’localhost’;
CREATE USER ‘monty’@’%’ IDENTIFIED BY ‘some_password’;
GRANT ALL PRIVILEGES ON . TO ‘monty’@’%;
[/sql]
watch out

我在这一步遇到了问题:当运行
[sql]
GRANTALL PRIVILEGES ON . TO ‘monty’@’localhost’;
[/sql]
报错:Access denied for user ‘root’@’localhost’。后来在stackoverflow上找到了答案:access-denied-for-user-rootlocalhost-while-attempting-to-grant-privileges

我采用了二楼的方法如下就可以了:
[bash]
$ su - mysql
$ rm -rf /var/lib/mysql/*
$ mysql_install_db
$ /etc/init.d/mysql restart
[/bash]
然后再重置root密码:
[bash]
mysqladmin -u root password
[/bash]

VPS MySQL CharSet配置

为了防止中文乱码,将VPS的MySQL的CharSet设置为utf8,当然WordPress的mysqldump的SQL文件中的每一个表都强制指定了CharSet为utf8,如果略去这一步也是可以的。
[bash]
vim /etc/my.cnf
[/bash]
在文本中的相应位置添加
[text]
[mysqld]
init_connect=’SET collation_connection = utf8_unicode_ci’
character-set-server = utf8
collation-server = utf8_unicode_ci
[client]
default-character-set = utf8
[mysql]
default-character-set = utf8
[/text]
验证,进入MySQL输入:
[sql]
SHOW VARIABLES LIKE ‘character%’;
SHOW VARIABLES LIKE ‘collation%’;
[/sql]

创建博客数据库

进入mysql,创建数据库
[bash]
mysql -u root -p
[/bash]
[sql]
mysql> create database yourblogdatabase;
[/sql]

本地Blog GitHub Set Up

首先在GitHub网站上创建一个Repository,GitHub of Cyanny Live Blog
在本地的Blog中:
[bash]
cd ~/Sites/Blog //打开文件夹
git init
git remote add origin git@github.com:lgrcyanny/CyannyLive.git // github的ssh地址
git pull origin master
[/bash]

本地Blog MySQL数据导出备份

我直接写了一个脚本,备份MySQL的数据,脚本backup.sh如下:
[shell]

!/bin/bash

export DATABASE_DIR=~/Sites/myblog/wp-content/backup-db
cd $DATABASE_DIR
mysqldump -u root -pyourpassword dbname > temp-db.sql

sed 命令替换在sql文件中Blog的http地址,这一步非常重要,否则在VPS上打不开,

原因很简单,本地是Localhost访问,VPS是域名访问,WordPress为每一个Post生成的访问地址是写死的

sed ‘s%http://cyanny/myblog%http://www.cyanny.com%g' temp-db.sql &gt; db.sql

数据压缩一下,会从上百KB变成几十个KB

tar -czvf db.tar.gz db.sql

删除中间文件

rm db.sql
rm temp-db.sql
[/shell]
运行backup.sh
[bash]
sh backup.sh
[/bash]

本地Blog htaccess配置

博客的访问地址,如果设置过Permalinks,这一步就很重要,否则在VPS端地址找不到
[bash]
cp .htaccess htaccess.prod
[/bash]
编辑htaccess.prod
[text]
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index&#46;php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
[/text]

本地Blog的其他配置

编辑.gitignore
[text]
wp-config.php
uploads/&#42;
wp-cache/&#42;
wp-content/cache
.htaccess
[/text]

wp-config.php配置
[bash]
cp wp-config.php wp-config-prod.php //本地的数据库配置和VPS上的不一样,因此要在wp-config-prod.php中设置VPS的DB信息
[/bash]

本地Blog 发布到 GitHub

[bash]
git add .
git commit -a -m ‘message’
git push origin master
[/bash]

VPS端 Enable htaccess overwirte

因为Blog的Post地址会被overwrite,所以需要VPS端具有htaccess overwrite的功能,这个Bug让我抓狂很久。

进入VPS
[bash]
vim /etc/httpd/conf/httpd.conf
[/bash]
编辑httpd.conf
[text]
// 找到下面这一段
<Directory /var/www/html>
Options Indexes FollowSymLinks MultiViews
// 更改为 AllowOverride All
AllowOverride None
Order allow,deny
allow from all
</Directory>
[/text]

VPS端的发布脚本

为了方便VPS端将WordPress从GitHub Clone到本地, 设置文件权限,DB数据导入,我创建了一个简单地发布脚本

deploy.sh, 这个脚本放在VPS上
[bash]

!/bin/bash

export BLOG_ROOT_DIR=/var/www/html/cyannyblog
export BLOG_DATABASES_DIR=$BLOG_ROOT_DIR/wp-content/backup-db

Git update

rm -Rf cyannyblog
git clone git@github.com:lgrcyanny/CyannyLive.git cyannyblog # 更换为自己的GitHub的地址

Change mod, grant access right

chmod -R 755 $BLOG_ROOT_DIR
chmod -R 777 $BLOG_ROOT_DIR/wp-content

Add config

rm -f $BLOG_ROOT_DIR/wp-config.php
cp $BLOG_ROOT_DIR/wp-config-prod.php $BLOG_ROOT_DIR/wp-config.php

Add .htaccess

cd $BLOG_ROOT_DIR
rm -f .htaccess
cp htaccess.prod .htaccess

Import data to mysql 不用担心数据冲突,因为mysqldump出来的表都会先drop再导入

cd $BLOG_DATABASES_DIR
tar -xvf db.tar.gz
mysql -u yourdbuser -pyourpassword -h localhost dbname < db.sql
[/bash]

在VPS上运行deploy.sh
[bash]
sh deploy.sh
[/bash]

VPS端将DocumentRoot指向Blog文件夹

[bash]
vim /etc/httpd/conf/httpd.conf
[/bash]
编辑httpd.conf:
[text]
DocumentRoot "/var/www/html/blog"
[/text]
我想这不是一个好办法,不过先将就一下。如果要在VPS上放置多个网站,DocumentRoot当然不能只是Blog,应该可以有一些Virtual的方法的,之后我会改进。目前这样是因为DNS不能解析到某一个路径

结束

Okay, 发布流程部署结束,接下来就可以访问啦。
以后每写一遍Post,或者本地有什么更新只需三个步骤就可以完成发布:

1. 本地 run backup.sh

2. GitHub Commit

3. VPS run deploy.sh, 当然未来还可以用cronjob,这样VPS端的发布问题就不用手工了,鉴于不是频繁发布Post,手工操作也无妨。

后记

1. 2014-08-17
VPS版本换了Centos7, MySQL替换为MariaDB, 但是DB不稳定,今天终于挂了
[bash]
systemctl restart mariadb
[/bash]
启动失败,最后修复如下:
[bash]
systemctl stop mariadb
rm -rf /var/lib/mysql
rm -rf /var/log/mariadb/
yum list mariadb
yum remove maridadb mariadb-server

yum remove all list about mariadb

yum install mariadb mariadb-server
reboot
systemctl enable mariadb
mkdir -p /var/lib/mysql
chown -R mysql:mysql /var/lib/mysql
systemctl start mariadb
yum install php-mysql
systemctl restart httpd.service
[/bash]

How to Start Learning Node.js

I have always wanted to do some meaningful projects, not the homework project at college, not the debug working at company. I just wanted to start a meaningful project for interest, or for fun. Maybe it will become a big success. and I believe in that. And recently I am busy with a spark prject based on Node.js.

Node.js is a platform built on Chrome’s JavaScript V8 engine. The event-driven, non-blocking I/O model makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

In short, I think the advantages is:[more…]

  • Same language on both server side and front side
  • Event-driven and callback feature gains perfect performance
  • With WebSocket, you can built great real-time app, like online chat room
  • Worth to learn, it’s new, and will give you a new perspective of web development

Beginner Guides

1. Felix’s Node.js Beginners Guide

This a short blog that can help you overview Node.js, learn some basics of Node.js, you can finish it within 30 min.
The Module system of node is worth to dig, read the api, especially the concept of exports and the module.exports

2. Node style guide

Before programming, learn the programming style of node.

NPM coding style
This is the npm coding style. At the beginning, indentation with 2 spaces make me uneasy. But now I am used to it.

3. The Node Beginning Book

The beginning book is really great, Even though it has more than 70 pages, I finished it and learned a lot. I followed the example in the book, build a simple blog demo. And the code in the book had some tiny issue. I have uploaded the demo to my github, node-simle-blog-demo.
BTW, the book will teach you how to run linux command by node Child Processes, sounds interesting.

Learning more details

4. Express guide

After learning how to build an application stack from the beginner book, you can start express now, finish the guide, understand the basics of the great web framework express. BTW, in node community, there are large amount of web framework. Like Tower.js, meteor.js, derby and so on. But express is the most popular and is supported by many people. I recommend it.

5. Node.js in Action

The book recommended by express guide has more than 400 pages. Don’t withdraw, insist on it, you can follow the book example, and learn more details about node. I haven’t finish it, because I want to start my project more quickly, I just walked to Chapter4.
The callback model and event driven explained in the book is great. Especially the muti-chat room by socket.io gave me a deep impression.

6. Build a express mongo blog

Follow the blog and build a simple blog with mongodb+express+jade, the code of jade for the blog has a tiny issue here, my demo is here express blog

7. Now I am fed up with tutorials, I decided to build something by myself. I build a file uploader/downloader with express. FileManager

Build the Web project

8. Node Express mongoose demo

I build PartyTime based on the demo. The demo is a blog with passport and authentication function. Worth to learn

9. Mongoose

Although mongodb provide nodejs api, I think the middleware is more better than the origin mongodb API

10. Mongodb Manual

Lean basics about mongodb, especially the Data Modeling method.

Others

11. Node github

12. A guide for api usage

13. Node Cloud
This is a resource directory gathering sites related to Node.js.

14. NPM  Finding and uploading npm package.

15. Some api worth to read: Modules, Child Processes, Crypto, File System, HTTP, Events, Path, QueryString, URL.

Good Luck!

Many tutorials, no matter how to lean, enjoy the learning process and the final sucess! Don’t waiting for finishing every details before starting your project.

“吐槽”敏捷软件开发

敏捷软件开发是在迭代和增量软件开发方法的基础上发展而来的一套软件开发方法,敏捷开发主张软件开发团队自组织,跨功能,它在1990年代开始逐渐引起广泛关注,并在2001年初由17名开发者在美国犹他州雪鸟滑雪胜地发起并组成了敏捷联盟,发表了著名的敏捷宣言。

敏捷宣言的价值观倡导:个体和互动高于流程和工具;工作的软件高于详尽的文档;客户合作高于合同谈判;响应变化高于遵循计划。在这四个价值观的倡导下,该联盟又发布了敏捷开发的12条原则。12条原则中强调了敏捷开发的最重要目标是通过持续不断地及早交付有价值的软件使客户满意,即不再以on-time, on-budget作为成功的标准,而是以给客户带来的商业价值作为成功的标准。

敏捷开发是轻量的开发方法,尽量的减少文档并面向源码,但文档并不是敏捷开发的根本特点,在《新方法学》中提到敏捷方法的两个根本特点:“适应性”而“非预见性”,“面向人”而非“面向过程”。

敏捷方法矫正了传统软件开发方法中的官僚繁琐的过程,拥抱变化,强调适应性和以人为本的理念。敏捷开发方法包括XP,Scrum,水晶系列,相关环境驱动测试,Lean Developments (精悍开发)和RUP (Rational Unified Process)。而Scrum作为一种重要的敏捷开发方法,现被广泛应用在企业软件的开发中。[more…]

敏捷开发的优势

敏捷软件开发作为一种新型的软件开发方法,具有很多优势:

1. 适应性

敏捷开发,敏捷的迭代周期短,可以快速交付可用的原型,通过迭代开发的方式对变更的需求做出适应性的调整,持续不断地及早的交付有价值的软件使客户满意。

2. 团队自组织,以人为本

敏捷团队里没有蓝领的编码工人,每一个人都是设计者,因为编码也是一种设计,编码是专业性更高的设计,给开发者更多的自主性,让他们自主决定一个user story该分成几个task,可以提高他们的积极性和创造力。让开发者自愿地投入产品开发比用强制力的手段更能带来产品的成功。

3. 关注软件,减少繁琐的文档

敏捷价值观众强调工作的软件高于详尽的文档,软件的需求不确定,软件的设计也很难给出,而敏捷开发可以更快的开始编码,生产出迭代可交付的产品,根据用户的反馈再做修改,不需要详尽的体系结构设计文件,详细设计文档等,减少了开发者的工作量,更多的关注编码。

4. 面对面的交流

敏捷开发的原则强调传递信息效果最好效率也最高的方式是面对面的交谈,Scrum每天的daily meeting,可以让团队成员面对面交流,保持项目进展的透明性。

敏捷开发还有很多优势,在此就不一一列举,而我们更需要关注的是,是不是所有的软件开发都要敏捷呢?事实上,工业界也有很多公司不用敏捷开发,敏捷开发还存在它不能适应的地方。

敏捷开发不是银弹

没有什么软件开发方法可以作为银弹的,敏捷开发也有它的不足。在Brooks的《人月神话》中,说道软件开发的根本任务是打造抽象软件实体的概念结构,次要任务是使用编程语言表达这些抽象实体,在空间、时间限制内将它们映射成机器语言。

同时也提出了软件开发最根本的困难是复杂性,可变性,一致性和不可见性,而这部分就将从软件开发的根本困难方面探讨敏捷方法还存在的缺陷。

(一)从复杂性方面和不可见性考虑——敏捷方法缺乏足够的设计和文档

复杂性是软件开发中的本质特性,复杂性主要来自于如何打造抽象和复杂的概念结构。McConnel曾经指出一个大型项目中,编码和单元测试只占15%,对于一个大型项目,编码的比重较少,还需要大部分的时间进行计划和设计,如果只是依靠代码很难把这些抽象的概念结构表达清楚的。敏捷方法中,采用面向源码而不是面向文档的方式进行软件开发,缺乏对整个产品和系统设计的考量和设计文档。

在不可见性方面,软件是复杂的,难以可视化,敏捷可以通过迭代来交付可视化可运行的原型,但是通常的界面原型是不能够表现软件的质量属性的,软件需要必要设计,提高质量。

敏捷方法在设计方面的不足,主要表现如下:

1. 在开发之前,缺乏足够的针对易用性方面地设计,主要是用户体验和UI的设计

在2009年,一份针对敏捷开发现状的调查报告—— Current State of Agile User-Centered Design: A Survey中指出:“ 敏捷软件开发方法在今天越来越流行,每年在工业界都有一定的增长。但是采用敏捷方法的团队缺乏软件易用性的意识,不能把易用性和以用户为中心的设计(User-Centered Design, UCD)和敏捷开发方法结合起来”。

敏捷开发的最终目的是要及早的交付有价值的让客户满意的软件。然而太快的交付会造成软件的用户体验不佳。在这份报告中采用XP的方式开发一款游戏软件,软件确实可以不断地交付高质量的增量,但是用户对游戏并不满意。

芬兰兰普拉达理工大学的教师Lea Hannola在他的论文Assessing and improving the front end activities of software development中指出:“软件开发能获得的最重要的益处可以通过提升前端的行为来实现。” [23]而如果要提升前端的行为就需要在软件编码开发之前对用户界面,前端交互方式,用户的输入,软件的输出,图形的色彩,相关的商业规则等方面,进行设计,并对设计的前端交互进行review。

在这里并不是说需要一个完美的易用性设计,毕竟想挖掘所有的用户需求是困难,我们强调的是”just enough design”. 敏捷开发之前的几个迭代周期,不应该直接编码来做出一个交互原型UI,太多的关注代码的细节,浪费时间和精力,应该进行必要地易用性设计,这样以后的迭代中会更有信心,前期工作做好了后期的变更代价也会降低。

2. 直接开始低层设计即编码,会带来更多的缺陷

敏捷开发面向源码,不面向文档,提倡可运行的软件高于详尽的文档。而在实践中,很多敏捷团队把文档降到最低,只写user story, 拆分task,用JIRA跟踪管理项目Task,Bug等。

Jack Reeves提出源码也应该是设计文档,而源码的设计文档是在数据结构和算法方面的低层的设计文档,过分的关注细节,会造成丢失大局。试问:如果对商业过程的规则都没有进行很好地建模和设计,何来一个良好的数据结构呢?试问:如果没有很好地中层设计,如何开发出符合模块化、信息隐藏,符合六条面向对象设计原则的代码呢?试问:如果不进行良好的设计,如何让写出的代码符合设计模式,而不是乱序的堆砌代码呢?

在软件开发之前,虽然不恩能够进行完备的设计,但是可以进行能够指导开发工作的”enough up-front design”。

软件开发的复杂度是复杂抽象概念结构的表达,例如开发一个股票交易软件,对股票交易的规则,对经济市场的信息需要进行建模,不管是用本体论,还是用BPL,UML,如果进行过设计,则可以降低一定的复杂度,在这些软件中编程实现是次要任务,根本任务是要把业务流程表达清楚,没有清晰地业务流程编码也使很难进行的。

《软件工程的事实与谬误》中指出软件质量由七个属性组成:可移植性,可靠性,效率,可用性,可测试性,易理解性和可修改性。要做到这些质量,需要从体系结构方面进行设计,通过软件的User Story场景,建模逻辑视图、开发视图、进程视图和部署视图,从总体的角度定义软件的体系结构风格,是以数据为中心的风格、主程序子程序风格、隐式调用风格、Pipe Line风格、Client-Server风格或者MVC风格,这些都需要在体系结构上进行设计,并生成必要地文档。

光从源码中的复杂的文件夹结构,复杂的包结构,是很难快速看出软件的体系结构风格的,不利于维护。

而在体系结构的基础上,最好进行一定的中层设计,如果采用结构化的变成方法,则需要对函数的调用关系方面进行一定的设计,如是面向对象的方面,则需要绘制必要地类图、包图,如是对数据库的设计,则需要实体关系图,数据存储的设计。

在足够的设计的基础上,复杂度降低了,再开始迭代编码,会让开发的增量更有质量。同时在设计和分析阶段,可以减少一定的缺陷,根据贝姆定律,在软件开发后期的变更的代价会更大,虽然敏捷拥抱变化,但我想没有哪一个程序员希望在迭代的后期在架构上做出变更,越早地给出一个设计方案,可以一定程度上降低后期变更的可能性。

一个良好的设计,通过设计建模,让软件的质量属性一定程度上可视化,提高可见性,同时编写必要地设计文档,可以让团队保持接口的一致性。

3. 对于需求相对确定的复杂项目,更需要设计

如开发一个操作系统,服务器,数据库,编程语言如Nodejs,Python这类需求可以相对确定和复杂度较高的项目,也可以采用敏捷开发,但是在迭代开始之前,需要根据需求进行体系结构设计,中层设计,再针对具体的进行低层设计,编码,持续集成,测试,并根据每一个迭代的增量交付修改设计,再进行下一个迭代。

(二)从可变性方面考虑——敏捷方法缺乏足够的需求工程过程和文档

Scrum中通过User Story, 用文本的方式描述需求,“作为。。。,我想。。。,以便。。。”,再加上优先级和相关的功能测试集。

但是简单地User Story并不能更清晰地表达复杂的需求,如一些专业领域的需求的建模,如金融、医学、生物等领域的,对于业务流程,需要适当数据流图和决策树表达复杂的业务流程,对于相关的数据,需要创建数据字典。

在开始敏捷的快速迭代之前,一个足够的需求工程过程,可以让项目的域更加清晰和明确。敏捷开发的一个很大的问题是项目的域失控(Scope Creep), 敏捷虽然强调“欣然面对需求的变化,及时在开发的后期也一样”, 而敏捷的方法是快速迭代,用两周和三周的时间做出对需求变更的调整。但是没人会喜欢软件开发后期需求的变更,那为什么不在项目开始之前和用户做好足够的沟通呢?

敏捷开发随着增量的迭代,用户会持续的提出需求,添加新功能,每一个sprint太过分的强调sprint的goal,而最终忘记了软件的goal,造成软件功能冗余,或偏离最初的需求,最终Scope Creep。

需求工程过程也是一个可以降低复杂度的过程,通过需求的描述用例,活动图,复杂的状态图,通过多个维度分析软件需求,明确Scope,降低软件后期变更的风险和压力。

(三)从一致性方面考虑——敏捷方法不适合工作地点分离的团队

Scrum只适合小团队运作, 并且工作地点要尽量在一起,这样面对面的交流可以保证工作的透明度和一致性

对于大型地上百人,而又不能拆分的团队,用敏捷开发是不适合的。敏捷,如Scrum最高效地是在5-6人,当超过7人时daily meeting,Planning Meeting的时间就会变长,影响团队的士气和气氛,同时会降低交流的效率。

同时当团队成员不在一个办公室或者交流的网速不好,处于异地如跨国团队,团队的交流效率是不高的,此时敏捷开发是不适合的。不利于团队的知识的一致性

(四)从管理方面考虑——敏捷方法的其他问题

最后再从软件开发的管理方面讨论一下敏捷方法还存在的问题:
1. 每一个Sprint的估算没有那么准确

虽然团队的估算能力好于个人,scrum sprint planning meeting的估算最终并没有那么准确,尤其是当sprint的User Story和task划分不明确时,估算的过程无疑是一个浪费时间的事情。

2. Scrum Master变成决策者

每天的Daily Meeting只是大家同步和汇报一下进度,而在中国很多的公司,也难免Scrum Master官僚起来,不相信团队成员,站立会议变成了向领导报告,听取领导建议,再开始今天的工作,而失去了站立会议的本意。团队打着自主的旗号,其实还是官僚的组织。

敏捷需要Scrum Master相信自己的团队。

3. Scrum团队只适合有很好开发经验的团队

敏捷开发不适合专业技能不强的团队,敏捷开发需要跨功能的经验充足的团队,专业技能不足,sprint的任务难以交付,也就失去了敏捷的意义。

4. 不适合有deadline和固定预算的项目

Scrum敏捷开发,可以很好的运作在需求不明确,deadline不明确的软件开发中,如移动互联网的很多项目,创新项目,而当软件项目是合同制的,需求明确,需要on-time, under-budget,那么采用传统的软件开发更好。

5. 团队成员的离开可能会带来很大的负面效应

Scrum团队本身是小型的团队,当某一个团队成员,特别是核心技术成员离开团队,会对团队的工作效率,士气等造成负面影响。

6. 每个sprint的测试压力较大
敏捷团队是跨功能的团队,同时也包含测试人员,我曾经实习的团队有8人,其中有两名测试人员,她们在每个sprint中承担了所有的测试任务,工作压力大,尤其在sprint交付时的回归测试中,不得不占用其他开发者的时间帮助测试,而且测试保证的只是功能正常,对代码质量方面,无法提供保障。

7. 当一个sprint backlog确定后,在一个sprint中的需求不允许变更

在Scrum的一个sprint中,当前sprint的backlog不会再变更,变更是发生在下一次planning,但当在当前的sprint中如果User Story没有定义好,对需求理解不够清晰,或者在sprint的迭代周期内发生需求变更,那么当前sprint的交付注定会让用户不满意,无疑是浪费时间,那么只有在下一次planning才会做出变更。

总结

敏捷开发纵然不是银弹,但他做为一种轻量级的软件开发方法,确实会给软件开发带来效率的提升,尤其是它强调的面对面交流,如daily meeting保持了团队进度的透明性,让每一个人都知道项目的进度,帮助项目管理。同时敏捷开发给了团队很大的自主性,如果是正确的采取的敏捷方法,团队的士气和积极性都会得到很大的提升。我们应该根据自己的需求来决定是否采取敏捷软件开发方法,不能盲目跟风。

有价值的参考资料

敏捷宣言

敏捷12原则

新方法论

benefits-pitfalls-of-using-scrum-software-development-methodology

providing-just-enough-design-can-make-agile-software-delivery-more-successful

the-advantages-and-disadvantages-of-agile-software-development

agile-scrum-sucks-but-so-do-the-alternatives

谈谈开源软件,谈谈质量

开源软件的基本概念最早可追溯到1955年IBM为了交换编程资料、深入研究IBM操作系统而开发的“IBM用户组分享”。在几十年后,1997年Eric Raymond发表了《大教堂与市集》——开源软件运动的圣经,以大教堂和市集这生动的比喻,阐述了商业封闭软件和自由软件的开发模式,并以Linux和Fetchmail为案例讨论了开源软件的优势。至今,20多年过去了,开源软件取得了不朽的成就,像Linux,Java,Eclipse,Android,Apache,Hadoop,Git,Nginx,Python,Node.js等,都是优秀的开源软件。

开源软件vs自由软件

开源软件

开源软件的定义,是由Bruce Perens(Debian创始人之一)于1997年基于Debian Free Software Guidelines提出,开源软件即公开源代码的软件,允许用户使用,修改,拷贝,合并,出版发行,再散布,贩售软件及软件副本,同时开源软件允许版权持有人在软件协议的规定之下保留一部分权利。

open source describes a broad general type of software license that makes source code available to the general public with relaxed or non-existent copyright restrictions.[more…]

1998年Eric.S.Raymond和Perens成立了OSI(Open Source Initiative), OSI规定开源软件需要遵守OSI支持的许可证,例如Apache License, BSD license, GNU General Public License, GNU Lesser General Public License, MIT License, Eclipse Public License和Mozilla Public License,如果软件源代码本身开源,但是限制用户的修改和再发行等权利,或者程序源码不可读、质量低造成用户难以自由使用,也只能是“Source Available Software”,不是开源软件。

自由软件

相对于开源软件,我们常提到自由软件,大多数开源软件也是自由软件,但二者不能混谈。自由软件, 是1983年由美国麻神理工人工智能实验室研究Richard Stallman提出,并于1984年发起了自由软件运动,建立了自由软件基金会(FSS),启动了GNU工程。他提出了Copyleft的思想,并为Copyleft提出了GPL许可证,GPL是该运动的精髓。自由软件的定义有FSS在1986年正式提出:
software is free software if people who receive a copy of the software have the following four freedoms.

Freedom 0: The freedom to run the program for any purpose.

Freedom 1: The freedom to study how the program works, and change it to make it do what you wish.

Freedom 2: The freedom to redistribute copies so you can help your neighbor.

Freedom 3: The freedom to improve the program, and release your improvements (and modified versions in general) to the public, so that the whole community benefits.

Freedoms 1 and 3 require source code to be available because studying and modifying software without its source code can range from highly impractical to nearly impossible.

开源软件和自由软件区别

如果硬要区别开源软件和自由软件,可以说二者的出发点不同,用Richard Stallman的话说”Open source is a development methodology; free software is a social movement”.

开源软件出发点是程序本身,旨在通过开源,让更多的人合作开发,Linus定律指出”Given enough eyeballs all bugs are shallow.”,开源致力于提高程序的质量,是一种集市的开发模式.

自由软件可以看做一种哲学和道德观念,强调用户的自由,如果一个软件卖给一个用户的只是二进制代码,而没有源代码,妨碍了用户自由使用、学习的权利,这就是不道德的。Richard Stallman认为软件不应该用来剥削和压榨利润,应该给用户自由的权利。自由软件一定是开源的,自由软件可以看做是开源软件的子集,开源软件中存在一些软件是限制用户再发售软件的权利,这就不是自由的。但大多数软件是自由开源软件FOSS。

The term “open source” software is used by some people to mean more or less the same category as free software. It is not exactly the same class of software: they accept some licenses that we consider too restrictive, and there are free software licenses they have not accepted. However, the differences in extension of the category are small: nearly all free software is open source, and nearly all open source software is free.

—–Free Software Foundation

自由软件常用的许可证是GPL和BSD,现在的更多的FOSS接受MIT或者BSD的许可证,而不太接受自由软件协议GPL,因为在GPL下,再次开发的软件必须是GPL的,不能作为商业用途,代码的传染性太高,也算是一种对自由的限制。

开源软件的优势

1.较低的维护成本,快速的Bug修复

正如Linus定律所述: “如果有足够多的眼睛,所有的错误都是浅显的。”更多的开发者,则可以更快的修复Bug。程序员如果找到Bug,不比像商业软件中那样,先上报、再审批、再决定Bug修复方法,再修复,效率较低,而开源社区的程序员们则可以快速响应修复问题。并且,开源软件的开发者们都是自主自愿的做贡献,软件的维护成本基本为零。

2. 自由和透明性

开源软件让开发者可以自由地使用和学习源代码,可以按自己的需求修改源代码,可以学习别人的代码,提高自己的技能。同时也可以了解软件的运作机制,修复bug,为开源软件做出贡献,提高自己在科技界的知名度。 这是开发者的快乐所在。

3. 为公司打开市场

IBM公司在开源软件Eclipse上投入上亿美元,开发了这个高质量的Java IDE,打败了竞争对手,推广了自己的产品,赢得了市场;Joyent公司发布开源的Node.js, 一个基于Chrome V8引擎的开发web应用的开发平台,曾一度成为GitHub上的Top Star,并受MicroSoft, Linkedln,eBay等大公司的亲睐,相信Joyent这家云服务提供商也拓宽了自己的市场。在软件有了市场后,便可以通过对软件的互补物品,如技术支持,存储空间,广告等方面获得利润。

4. 吸引更多优秀的工程师

一个公司进行一个开源项目,可以吸引到更多的人才。很多工程师,喜欢为开源社区工作,提高自己在科技界的声望,帮助他们找到更好的工作。而如果有公司支持开源项目,他们也乐意去那里工作。

开源软件的质量不太理想

开源软件承诺并鼓励开发更高质量,更高可靠性,更加灵活,更低成本的软件,让用户得到更多的自由,而我们也看到像Linux,GNU Project, Apache Project, Python, Chromium, Mozilla, Android都是高质量的开源软件,然而开源软件并不保证一定高质量,在ohloh(开源和自由软件的在线字典)上的60多万的开源软件的质量没有那么理想,高质量的开源软件是榜样,但不能把开源和高质量等同。
Robert在《软件工程的事实与谬误中》给出了质量的定义,即7个属性的集合:可靠性,可移植性,效率,可用性(人类工程学),可测试性,易理解性和可修改性。
开源软件在质量方面的劣势如下:

1. 可用性不理想

商业软件,如Windows,Adobe Photoshop,Office,Dropbox,Skype,iTune等,都有对应的开源软件,如Ubuntu,GIMP,Open Office,Cabos,CuteCom,Songbird,同时也是免费的。开源软件的开发者们缺乏在可用性,HCI方面的设计经验,常常会去模仿工业界的商用软件的设计,缺乏自主创新,这也就解释了几乎每一个商业软件的都有一个开源软件与之对应。模仿的结果是可用性和用户满意度不高,对于不懂技术的普通用户,如果经济允许,购买商用软件会比用开源带来更多的方便。

2. “早发布,常发布”造成缺乏成熟的设计

开源社区,有优秀的程序员,但少有优秀的设计师。开源软件让开发者合作开发,其本质是大量的开发者为软件免费修复bug。开源软件还没有设计好,就草率的发布,势必会降低软件的质量,软件最终会失控。而很多时候,软件设计的重要性等同甚至大于代码的重要性,如HCI设计,需要专业的设计师。而开发者们都喜欢去实现算法,编写代码,在可用性上只按自己的喜好进行设计,造成在细节方面做得不如商业软件。

3. 文档质量不高

很多时候拿到一份源代码,看文档比看源码更有效率,文档是交流的利器。然而,开源软件的文档质量并没有商业软件那么理想。商业软件有好的技术文档和用户手册,但开源软件的开发者宁可写代码,也不太喜欢写文档。我曾经参与过Joomla项目,Joomla的文档就让人很头疼。

4. 软件变得越来越复杂而难以控制

太多的人参与,太多的意见,开发者们按自己的需求,自己对”好软件”的定义开发,让软件越来越复杂,集成和版本控制的成本增加,这些都源于对用户需求没有一个清晰的定义,不满足用户的需求,或者过多冗余的功能,会造成软件的质量下降。

5. 开发人员管理困难

好的软件往往需要一个或多个优秀的开发者全职在一起工作,一起开发、维护和改善软件。当开发者遍布世界各地,便很难保证开发者会全职为软件做贡献。而很多优秀的开源软件是大公司支持的,软件的贡献者同时也是公司的全职员工,这也是这些开源软件可以高质量的一个原因。

开源软件和商业软件之间的平衡

软件开发没有能带来数量级增长的银弹,开源和商业软件各有优势,如何选择是需要仔细考虑的。

1. 根据用户的需求来决定用开源软件或者商业软件

开源软件,开放源代码,开发者对此更感兴趣,如果应用是面向开发者的软件,对可用性和HCI要求不高,如编程语言(Python),服务器,IDE,平台软件,可以考虑用开源软件,让大量的开发者合作开发,可以提高软件的质量。

如果用户是不关心技术的普通用户,且如果有对软件保密性、安全性、高可靠性等方面的需求,采用商业软件的开发方法更好,例如金融理财软件,邮件系统,铁路系统等。
如果用户对软件的交付日期有要求,不要用开源软件,开源很难控制开发进度。

2. 如果采用开源软件,当心GPL

很多开源软件受GPL的保护,而如果你需要二次开发的开源软件,在GPL下,则你开发的软件也必须在GPL下,这会损害你的专利权利,并且软件不能出售。

3. 考虑个人的需求和公司的需求

如果对于开发者个人,需要提高自己在软件界的声望,想锻炼自己的能力,让CV更加好看,多参与和贡献开源软件是一个好方法。

如果一个公司,想扩大自己的市场影响力,想以开源软件的方法获得商业利益,则可以采用开源软件。

但如果个人或者公司想创新,实现创新的idea,并保有自己的专利权利,打算以出售软件来赚钱,那么就要采用商业软件的开发方法。

总之,有了开源软件,我们就多了一种软件的开发方法,开源软件为软件的世界带来了很多生机,像GitHub现在全球最大的开源社区,每天都有世界各地的开发者合作交流。商业软件还是开源软件,我们都要从自己的需求出发来决定。

一些参考资源

When Free Software Isn’t (Practically) Better

Why free software has poor usability, and how to improve it

The Problems of Open Source

Corporate Open Source Considerations

Open Source Sucks

Open Source Rocks

The Top 50 Proprietary Programs that Drive You Crazy — and Their Open Source Alternatives

Open Source Software: The Hidden Cost of Free

Copyright
© 2022 Cyanny Liang