ubuntu 一键安装 OpenStf

<br />#install oracle java https://www.digitalocean.com/community/tutorials/how-to-install-java-on-ubuntu-with-apt-get
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer

#ANDROIDSTUDIO
#necessary for mksdcard
sudo apt-get install lib32stdc++6

#edit ~/.profile and add env variables
export ANDROID_SDK="$HOME/android-sdk-linux"
PATH=$PATH:$ANDROID_SDK/platform-tools;$ANDROID_SDK/tools


##PREREQ
#Node.js >= 0.12
sudo apt-get install node.js

#ADB properly set up

#RethinkDB >= 2.2
source /etc/lsb-release && echo "deb http://download.rethinkdb.com/apt $DISTRIB_CODENAME main" | sudo tee /etc/apt/sources.list.d/rethinkdb.list
wget -qO- https://download.rethinkdb.com/apt/pubkey.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get install rethinkdb

#GraphicsMagick (for resizing screenshots)
sudo apt-get install graphicsmagick

#ZeroMQ libraries installed
sudo apt-get install libzmq1
sudo apt-get install libzmq-dev

#Protocol Buffers libraries installed (seems part of rethinkDB)
sudo apt-get install libprotobuf*

#yasm installed (for compiling embedded libjpeg-turbo)
sudo apt-get install yasm
sudo apt-get install npm
sudo apt-get install nodejs-legacy
npm install --save jpeg-turbo

#pkg-config so that Node.js can find the libraries
sudo apt-get install pkg-config

#node >=6.9 so install 8.x
curl -sL https://deb.nodesource.com/setup_8.x | bash
apt-get install nodejs

#add mirrors
npm config set registry https://registry.npm.taobao.org
npm config get registry

##STF
sudo apt-get install git
mkdir ~/stf
cd ~/stf
sudo npm install zmq
sudo npm install -g stf

##Continue here
https://github.com/openstf/stf/tree/2.0.0#running


高性能网络 | 你所不知道的TIME_WAIT和CLOSE_WAIT

本文源于大家在公众号里面的留言,既然很多人都搞不清楚TIME_WAIT和CLOSE_WAIT,那么小胖哥今天还是抽个时间,统一帮大家理理概念吧。

你遇到过TIME_WAIT的问题吗?

我相信很多都遇到过这个问题。一旦有用户在喊:网络变慢了。第一件事情就是,netstat -a | grep TIME_WAIT | wc -l 一下。哎呀妈呀,几千个TIME_WAIT.

然后,做的第一件事情就是:打开Google或者Bing,输入关键词:too many time wait。一定能找到解决方案,而排在最前面或者被很多人到处转载的解决方案一定是:

打开 sysctl.conf 文件,修改以下几个参数:

  • net.ipv4.tcp_tw_recycle = 1
  • net.ipv4.tcp_tw_reuse = 1
  • net.ipv4.tcp_timestamps = 1

你也会被告知,开启tw_recylce和tw_reuse一定需要timestamps的支持,而且这些配置一般不建议开启,但是对解决TIME_WAIT很多的问题,有很好的用处。

接下来,你就直接修改了这几个参数,reload一下,发现,咦,没几分钟,TIME_WAIT的数量真的降低了,也没发现哪个用户说有问题,然后就没有然后了。

做到这一步,相信50%或者更高比例的开发就已经止步了。问题好像解决了,但是,要彻底理解并解决这个问题,可能就没这么简单,或者说,还有很长的路要走!

什么是TIME-WAIT和CLOSE-WAIT?

所谓,要解决问题,就要先理解问题。随便改两行代码,发现bug“没有了”,也不是bug真的没有了,只是隐藏在更深的地方,你没有发现,或者以你的知识水平,你无法发现而已。

大家知道,由于socket是全双工的工作模式,一个socket的关闭,是需要四次握手来完成的。

  • 主动关闭连接的一方,调用close();协议层发送FIN包
  • 被动关闭的一方收到FIN包后,协议层回复ACK;然后被动关闭的一方,进入CLOSE_WAIT状态,主动关闭的一方等待对方关闭,则进入FIN_WAIT_2状态;此时,主动关闭的一方 等待 被动关闭一方的应用程序,调用close操作
  • 被动关闭的一方在完成所有数据发送后,调用close()操作;此时,协议层发送FIN包给主动关闭的一方,等待对方的ACK,被动关闭的一方进入LAST_ACK状态
  • 主动关闭的一方收到FIN包,协议层回复ACK;此时,主动关闭连接的一方,进入TIME_WAIT状态;而被动关闭的一方,进入CLOSED状态
  • 等待2MSL时间,主动关闭的一方,结束TIME_WAIT,进入CLOSED状态

通过上面的一次socket关闭操作,你可以得出以下几点:

  1. 主动关闭连接的一方 - 也就是主动调用socket的close操作的一方,最终会进入TIME_WAIT状态
  2. 被动关闭连接的一方,有一个中间状态,即CLOSE_WAIT,因为协议层在等待上层的应用程序,主动调用close操作后才主动关闭这条连接
  3. TIME_WAIT会默认等待2MSL时间后,才最终进入CLOSED状态;
  4. 在一个连接没有进入CLOSED状态之前,这个连接是不能被重用的!

所以,这里凭你的直觉,TIME_WAIT并不可怕(not really,后面讲),CLOSE_WAIT才可怕,因为CLOSE_WAIT很多,表示说要么是你的应用程序写的有问题,没有合适的关闭socket;要么是说,你的服务器CPU处理不过来(CPU太忙)或者你的应用程序一直睡眠到其它地方(锁,或者文件I/O等等),你的应用程序获得不到合适的调度时间,造成你的程序没法真正的执行close操作。

这里又出现两个问题:

  1. 上文提到的连接重用,那连接到底是个什么概念?
  2. 协议层为什么要设计一个TIME_WAIT状态?这个状态为什么默认等待2MSL时间才会进入CLOSED

先解释清楚这两个问题,我们再来看,开头提到的几个网络配置究竟有什么用,以及TIME_WAIT的后遗症问题。

Socket连接到底是个什么概念?

大家经常提socket,那么,到底什么是一个socket?其实,socket就是一个 五元组,包括:

  1. 源IP
  2. 源端口
  3. 目的IP
  4. 目的端口
  5. 类型:TCP or UDP

这个五元组,即标识了一条可用的连接。注意,有很多人把一个socket定义成四元组,也就是 源IP:源端口 + 目的IP:目的端口,这个定义是不正确的。

例如,如果你的本地出口IP是180.172.35.150,那么你的浏览器在连接某一个Web服务器,例如百度的时候,这条socket连接的四元组可能就是:

[180.172.35.150:45678, tcp, 180.97.33.108:80]

源IP为你的出口IP地址 180.172.35.150,源端口为随机端口 45678,目的IP为百度的某一个负载均衡服务器IP 180.97.33.108,端口为HTTP标准的80端口。

如果这个时候,你再开一个浏览器,访问百度,将会产生一条新的连接:

[180.172.35.150:43678, tcp, 180.97.33.108:80]

这条新的连接的源端口为一个新的随机端口 43678。

如此来看,如果你的本机需要压测百度,那么,你最多可以创建多少个连接呢?我在文章《云思路 | 轻松构建千万级投票系统》里也稍微提过这个问题,没有阅读过本文的,可以发送“投票系统”阅读。

第二个问题,TIME_WAIT有什么用?

如果我们来做个类比的话,TIME_WAIT的出现,对应的是你的程序里的异常处理,它的出现,就是为了解决网络的丢包和网络不稳定所带来的其他问题:

第一,防止前一个连接【五元组,我们继续以 180.172.35.150:45678, tcp, 180.97.33.108:80 为例】上延迟的数据包或者丢失重传的数据包,被后面复用的连接【前一个连接关闭后,此时你再次访问百度,新的连接可能还是由180.172.35.150:45678, tcp, 180.97.33.108:80 这个五元组来表示,也就是源端口凑巧还是45678】错误的接收(异常:数据丢了,或者传输太慢了),参见下图:

  • SEQ=3的数据包丢失,重传第一次,没有得到ACK确认
  • 如果没有TIME_WAIT,或者TIME_WAIT时间非常端,那么关闭的连接【180.172.35.150:45678, tcp, 180.97.33.108:80 的状态变为了CLOSED,源端口可被再次利用】,马上被重用【对180.97.33.108:80新建的连接,复用了之前的随机端口45678】,并连续发送SEQ=1,2 的数据包
  • 此时,前面的连接上的SEQ=3的数据包再次重传,同时,seq的序号刚好也是3(这个很重要,不然,SEQ的序号对不上,就会RST掉),此时,前面一个连接上的数据被后面的一个连接错误的接收

第二,确保连接方能在时间范围内,关闭自己的连接。其实,也是因为丢包造成的,参见下图:

  • 主动关闭方关闭了连接,发送了FIN;
  • 被动关闭方回复ACK同时也执行关闭动作,发送FIN包;此时,被动关闭的一方进入LAST_ACK状态
  • 主动关闭的一方回去了ACK,主动关闭一方进入TIME_WAIT状态;
  • 但是最后的ACK丢失,被动关闭的一方还继续停留在LAST_ACK状态
  • 此时,如果没有TIME_WAIT的存在,或者说,停留在TIME_WAIT上的时间很短,则主动关闭的一方很快就进入了CLOSED状态,也即是说,如果此时新建一个连接,源随机端口如果被复用,在connect发送SYN包后,由于被动方仍认为这条连接【五元组】还在等待ACK,但是却收到了SYN,则被动方会回复RST
  • 造成主动创建连接的一方,由于收到了RST,则连接无法成功

所以,你看到了,TIME_WAIT的存在是很重要的,如果强制忽略TIME_WAIT,还是有很高的机率,造成数据粗乱,或者短暂性的连接失败。

那么,为什么说,TIME_WAIT状态会是持续2MSL(2倍的max segment lifetime)呢?这个时间可以通过修改内核参数调整吗?第一,这个2MSL,是RFC 793里定义的,参见RFC的截图标红的部分:


这个定义,更多的是一种保障(IP数据包里的TTL,即数据最多存活的跳数,真正反应的才是数据在网络上的存活时间),确保最后丢失了ACK,被动关闭的一方再次重发FIN并等待回复的ACK,一来一去两个来回。内核里,写死了这个MSL的时间为:30秒(有读者提醒,RFC里建议的MSL其实是2分钟,但是很多实现都是30秒),所以TIME_WAIT的即为1分钟:

所以,再次回想一下前面的问题,如果一条连接,即使在四次握手关闭了,由于TIME_WAIT的存在,这个连接,在1分钟之内,也无法再次被复用,那么,如果你用一台机器做压测的客户端,你一分钟能发送多少并发连接请求?如果这台是一个负载均衡服务器,一台负载均衡服务器,一分钟可以有多少个连接同时访问后端的服务器呢?

TIME_WAIT很多,可怕吗?

如果你通过 ss -tan state time-wait | wc -l 发现,系统中有很多TIME_WAIT,很多人都会紧张。多少算多呢?几百几千?如果是这个量级,其实真的没必要紧张。第一,这个量级,因为TIME_WAIT所占用的内存很少很少;因为记录和寻找可用的local port所消耗的CPU也基本可以忽略。

会占用内存吗?当然任何你可以看到的数据,内核里都需要有相关的数据结构来保存这个数据啊。一条Socket处于TIME_WAIT状态,它也是一条“存在”的socket,内核里也需要有保持它的数据:

  1. 内核里有保存所有连接的一个hash table,这个hash table里面既包含TIME_WAIT状态的连接,也包含其他状态的连接。主要用于有新的数据到来的时候,从这个hash table里快速找到这条连接。不同的内核对这个hash table的大小设置不同,你可以通过dmesg命令去找到你的内核设置的大小:
  2. 还有一个hash table用来保存所有的bound ports,主要用于可以快速的找到一个可用的端口或者随机端口:

由于内核需要保存这些数据,必然,会占用一定的内存。

会消耗CPU吗?当然!每次找到一个随机端口,还是需要遍历一遍bound ports的吧,这必然需要一些CPU时间。

TIME_WAIT很多,既占内存又消耗CPU,这也是为什么很多人,看到TIME_WAIT很多,就蠢蠢欲动的想去干掉他们。其实,如果你再进一步去研究,1万条TIME_WAIT的连接,也就多消耗1M左右的内存,对现代的很多服务器,已经不算什么了。至于CPU,能减少它当然更好,但是不至于因为1万多个hash item就担忧。

如果,你真的想去调优,还是需要搞清楚别人的调优建议,以及调优参数背后的意义!

TIME_WAIT调优,你必须理解的几个调优参数

在具体的图例之前,我们还是先解析一下相关的几个参数存在的意义。

net.ipv4.tcp_timestamps

RFC 1323 在 TCP Reliability一节里,引入了timestamp的TCP option,两个4字节的时间戳字段,其中第一个4字节字段用来保存发送该数据包的时间,第二个4字节字段用来保存最近一次接收对方发送到数据的时间。有了这两个时间字段,也就有了后续优化的余地。

tcp_tw_reuse 和 tcp_tw_recycle就依赖这些时间字段。

net.ipv4.tcp_tw_reuse

字面意思,reuse TIME_WAIT状态的连接。

时刻记住一条socket连接,就是那个五元组,出现TIME_WAIT状态的连接,一定出现在主动关闭连接的一方。所以,当主动关闭连接的一方,再次向对方发起连接请求的时候(例如,客户端关闭连接,客户端再次连接服务端,此时可以复用了;负载均衡服务器,主动关闭后端的连接,当有新的HTTP请求,负载均衡服务器再次连接后端服务器,此时也可以复用),可以复用TIME_WAIT状态的连接。

通过字面解释,以及例子说明,你看到了,tcp_tw_reuse应用的场景:某一方,需要不断的通过“短连接”连接其他服务器,总是自己先关闭连接(TIME_WAIT在自己这方),关闭后又不断的重新连接对方。

那么,当连接被复用了之后,延迟或者重发的数据包到达,新的连接怎么判断,到达的数据是属于复用后的连接,还是复用前的连接呢?那就需要依赖前面提到的两个时间字段了。复用连接后,这条连接的时间被更新为当前的时间,当延迟的数据达到,延迟数据的时间是小于新连接的时间,所以,内核可以通过时间判断出,延迟的数据可以安全的丢弃掉了。

这个配置,依赖于连接双方,同时对timestamps的支持。同时,这个配置,仅仅影响outbound连接,即做为客户端的角色,连接服务端[connect(dest_ip, dest_port)]时复用TIME_WAIT的socket。

net.ipv4.tcp_tw_recycle

字面意思,销毁掉 TIME_WAIT。

当开启了这个配置后,内核会快速的回收处于TIME_WAIT状态的socket连接。多快?不再是2MSL,而是一个RTO(retransmission timeout,数据包重传的timeout时间)的时间,这个时间根据RTT动态计算出来,但是远小于2MSL。

有了这个配置,还是需要保障 丢失重传或者延迟的数据包,不会被新的连接(注意,这里不再是复用了,而是之前处于TIME_WAIT状态的连接已经被destroy掉了,新的连接,刚好是和某一个被destroy掉的连接使用了相同的五元组而已)所错误的接收。在启用该配置,当一个socket连接进入TIME_WAIT状态后,内核里会记录包括该socket连接对应的五元组中的对方IP等在内的一些统计数据,当然也包括从该对方IP所接收到的最近的一次数据包时间。当有新的数据包到达,只要时间晚于内核记录的这个时间,数据包都会被统统的丢掉。

这个配置,依赖于连接双方对timestamps的支持。同时,这个配置,主要影响到了inbound的连接(对outbound的连接也有影响,但是不是复用),即做为服务端角色,客户端连进来,服务端主动关闭了连接,TIME_WAIT状态的socket处于服务端,服务端快速的回收该状态的连接。

由此,如果客户端处于NAT的网络(多个客户端,同一个IP出口的网络环境),如果配置了tw_recycle,就可能在一个RTO的时间内,只能有一个客户端和自己连接成功(不同的客户端发包的时间不一致,造成服务端直接把数据包丢弃掉)。

我尽量尝试用文字解释清楚,但是,来点案例和图示,应该有助于我们彻底理解。

我们来看这样一个网络情况:

  1. 客户端IP地址为:180.172.35.150,我们可以认为是浏览器
  2. 负载均衡有两个IP,外网IP地址为 115.29.253.156,内网地址为10.162.74.10;外网地址监听80端口
  3. 负载均衡背后有两台Web服务器,一台IP地址为 10.162.74.43,监听80端口;另一台为 10.162.74.44,监听 80 端口
  4. Web服务器会连接数据服务器,IP地址为 10.162.74.45,监听 3306 端口

这种简单的架构下,我们来看看,在不同的情况下,我们今天谈论的tw_reuse/tw_recycle对网络连接的影响。

先做个假定:

  1. 客户端通过HTTP/1.1连接负载均衡,也就是说,HTTP协议投Connection为keep-alive,所以我们假定,客户端 对 负载均衡服务器 的socket连接,客户端会断开连接,所以,TIME_WAIT出现在客户端
  2. Web服务器和MySQL服务器的连接,我们假定,Web服务器上的程序在连接结束的时候,调用close操作关闭socket资源连接,所以,TIME_WAIT出现在 Web 服务器端。

那么,在这种假定下:

  1. Web服务器上,肯定可以配置开启的配置:tcp_tw_reuse;如果Web服务器有很多连向DB服务器的连接,可以保证socket连接的复用。
  2. 那么,负载均衡服务器和Web服务器,谁先关闭连接,则决定了我们怎么配置tcp_tw_reuse/tcp_tw_recycle了

方案一:负载均衡服务器 首先关闭连接 

在这种情况下,因为负载均衡服务器对Web服务器的连接,TIME_WAIT大都出现在负载均衡服务器上,所以,在负载均衡服务器上的配置:

  • net.ipv4.tcp_tw_reuse = 1 //尽量复用连接
  • net.ipv4.tcp_tw_recycle = 0 //不能保证客户端不在NAT的网络啊

在Web服务器上的配置为:

  • net.ipv4.tcp_tw_reuse = 1 //这个配置主要影响的是Web服务器到DB服务器的连接复用
  • net.ipv4.tcp_tw_recycle: 设置成1和0都没有任何意义。想一想,在负载均衡和它的连接中,它是服务端,但是TIME_WAIT出现在负载均衡服务器上;它和DB的连接,它是客户端,recycle对它并没有什么影响,关键是reuse

方案二:Web服务器首先关闭来自负载均衡服务器的连接

在这种情况下,Web服务器变成TIME_WAIT的重灾区。负载均衡对Web服务器的连接,由Web服务器首先关闭连接,TIME_WAIT出现在Web服务器上;Web服务器对DB服务器的连接,由Web服务器关闭连接,TIME_WAIT也出现在它身上,此时,负载均衡服务器上的配置:

  • net.ipv4.tcp_tw_reuse:0 或者 1 都行,都没有实际意义
  • net.ipv4.tcp_tw_recycle=0 //一定是关闭recycle

在Web服务器上的配置:

  • net.ipv4.tcp_tw_reuse = 1 //这个配置主要影响的是Web服务器到DB服务器的连接复用
  • net.ipv4.tcp_tw_recycle=1 //由于在负载均衡和Web服务器之间并没有NAT的网络,可以考虑开启recycle,加速由于负载均衡和Web服务器之间的连接造成的大量TIME_WAIT

回答几个大家提到的几个问题

  1. 请问我们所说连接池可以复用连接,是不是意味着,需要等到上个连接time wait结束后才能再次使用?

所谓连接池复用,复用的一定是活跃的连接,所谓活跃,第一表明连接池里的连接都是ESTABLISHED的,第二,连接池做为上层应用,会有定时的心跳去保持连接的活跃性。既然连接都是活跃的,那就不存在有TIME_WAIT的概念了,在上篇里也有提到,TIME_WAIT是在主动关闭连接的一方,在关闭连接后才进入的状态。既然已经关闭了,那么这条连接肯定已经不在连接池里面了,即被连接池释放了。

2. 想请问下,作为负载均衡的机器随机端口使用完的情况下大量time_wait,不调整你文字里说的那三个参数,有其他的更好的方案吗?

第一,随机端口使用完,你可以通过调整/etc/sysctl.conf下的net.ipv4.ip_local_port_range配置,至少修改成 net.ipv4.ip_local_port_range=1024 65535,保证你的负载均衡服务器至少可以使用6万个随机端口,也即可以有6万的反向代理到后端的连接,可以支持每秒1000的并发(想一想,因为TIME_WAIT状态会持续1分钟后消失,所以一分钟最多有6万,每秒1000);如果这么多端口都使用完了,也证明你应该加服务器了,或者,你的负载均衡服务器需要配置多个IP地址,或者,你的后端服务器需要监听更多的端口和配置更多的IP(想一下socket的五元组)

第二,大量的TIME_WAIT,多大量?如果是几千个,其实不用担心,因为这个内存和CPU的消耗有一些,但是是可以忽略的。

第三,如果真的量很大,上万上万的那种,可以考虑,让后端的服务器主动关闭连接,如果后端服务器没有外网的连接只有负载均衡服务器的连接(主要是没有NAT网络的连接),可以在后端服务器上配置tw_recycle,然后同时,在负载均衡服务器上,配置tw_reuse。

  1. 如果想深入的学习一下网络方面的知识,有什么推荐的?

学习网络比学一门编程语言“难”很多。所谓难,其实,是因为需要花很多的时间投入。我自己不算精通,只能说入门和理解。基本书可以推荐:《TCP/IP 协议详解》,必读;《TCP/IP高效编程:改善网络程序的44个技巧》,必读;《Unix环境高级编程》,必读;《Unix网络编程:卷一》,我只读过卷一;另外,还需要熟悉一下网络工具,tcpdump以及wireshark,我的notes里有一个一站式学习Wireshark:https://github.com/dafang/notebook/issues/114,也值得一读。有了这些积累,可能就是一些实践以及碎片化的学习和积累了。

写在最后

这篇文章我断断续续写了两天,内容找了多个地方去验证,包括看到Vincent Bernat的一篇文章以及Vincent在多个地方和别人的讨论。期间,我也花了一些时间和Vincent探讨了几个我没在tcp源码里翻找到的有疑问的地方。

我力求比散布在网上的文章做到准确并尽量整理的清晰一些。但是,也难免会

有疏漏或者有错误的地方,高手看到可以随时指正,并和我讨论,大家一起研究!

感谢您阅读。

go caddy server install on Centos 6 and init.d config

# step 1, install caddyserver
curl -s https://getcaddy.com | bash
groupadd -g 33 www-data
useradd \
  -g www-data --no-user-group \
  --home-dir /var/www --no-create-home \
  --shell /usr/sbin/nologin \
  --system --uid 33 www-data

mkdir /etc/caddy
chown -R root:www-data /etc/caddy
mkdir /etc/ssl/caddy
chown -R www-data:root /etc/ssl/caddy
chmod 0770 /etc/ssl/caddy

# step 2, download sysvinit file
wget https://raw.githubusercontent.com/mholt/caddy/master/dist/init/linux-sysvinit/caddy -O /etc/init.d/caddy

# step 3, install daemon
cd /usr/local/src
wget http://developer.axis.com/download/distribution/apps-sys-utils-start-stop-daemon-IR1_9_18-2.tar.gz
tar zxvf apps-sys-utils-start-stop-daemon-IR1_9_18-2.tar.gz
cd apps/sys-utils/start-stop-daemon-IR1_9_18-2
gcc start-stop-daemon.c -o start-stop-daemon
cp start-stop-daemon /usr/sbin/

# step 4, start service
service caddy start

webp与png、jpg相互转换,Convert WEBP to JPG,Convert PNG to webp

主要使用webp-tools

#ubuntu
apt-get install webp

#centos
yum -y install libwebp-devel libwebp-tools

会生成几个工具。

cwebp → WebP encoder tool
dwebp → WebP decoder tool
vwebp → WebP file viewer
webpmux → WebP muxing tool
gif2webp → Tool for converting GIF images to WebP

# convert from webp to png
dwebp mycat.jpg -o mycat.png

# Convert from JPG to WebP
cwebp some.jpg -o target.webp

dwebp可以将webp图片转换成无损的png图片格式,有了png,则可以使用imagemagic之类的工具再转换成jpg.
cwebp可以将jpg转换成webp,将png转换成webp

青云、阿里云、腾讯云磁盘速度测试

阿里云,香港,SSD云盘

[root@ali03 ~]# time dd if=/dev/zero of=/test.dbf bs=8k count=300000
300000+0 records in
300000+0 records out
2457600000 bytes (2.5 GB) copied, 29.2894 s, 83.9 MB/s

腾讯云,新加坡,默认

[root@VM_0_2_centos ~]# time dd if=/dev/zero of=/test.dbf bs=8k count=300000
300000+0 records in
300000+0 records out
2457600000 bytes (2.5 GB) copied, 3.70669 s, 663 MB/s

real    0m3.744s
user    0m0.040s
sys 0m2.450s

青云,北京3区,默认

[root@JY11 ~]# time dd if=/dev/zero of=/test.dbf bs=8k count=300000
300000+0 records in
300000+0 records out
2457600000 bytes (2.5 GB) copied, 17.3187 s, 142 MB/s

real    0m17.365s
user    0m0.033s
sys 0m1.644s

Linux / UNIX Crontab File Location Crontab配置文件路径

一般是用crontab -e来增删计划任务,如果要导入任务,则可以通过复制文件的方式来操作

Mac OS X – /usr/lib/cron/tabs/ (user cron location /usr/lib/cron/tabs/vivek)
FreeBSD/OpenBSD/NetBSD – /var/cron/tabs/ (user cron location /var/cron/tabs/vivek)
CentOS/Red Hat/RHEL/Fedora/Scientific Linux – /var/spool/cron/ (user cron location /var/spool/cron/vivek)
Debian / Ubuntu Linux – /var/spool/cron/crontabs/ (user cron location /var/spool/cron/crontabs/vivek)
HP-UX Unix – /var/spool/cron/crontabs/ (user cron location /var/spool/cron/crontabs/vivek)
IBM AIX Unix – /var/spool/cron/ (user cron location /var/spool/cron/vivek)

OneApm 的使用总结

我司的部分业务从去年起,开始接入OneApm,到目前已经有50台机器的规模。
业务层的Nginx、PHP、Mysql,到Redis、ElasticSearch监控,到业务模拟测试可用度,到自定义SDK实现的特殊业务监控,目前都有涉及到(http://www.4wei.cn/archives/1002578)。

总的来说,好评满满,DevOps时代不可或缺的必备工具服务。

QQ20160414-0

20+监控服务器,Nginx、Mysql、ES、REDIS、PHP_FPM等数个平台服务的监控

QQ20160414-1

配置自定义仪表盘

QQ20160414-2

设置告警策略

CentOS远程重装系统

公司内网的一台Linux弱口令机器让扫出来了,数据洗劫一空,悲剧啊
还好不是什么重要的东西,赶紧重装系统。

人不在公司,只能使用远程重装,方案如下:

Fedora 14需要下载的文件在http://nas1.itc.virginia.edu/fedora/releases/14/Fedora/x86_64/os/images/…
64位Centos需要下载的文件在 http://mirror.centos.org/centos-5/5/os/x86_64/images/pxeboot/

修改服务器的/boot/grub/grub.conf文件,在这个配置文件中,添加如下启动项:

title CentOS Reinstall
root (hd0,0)
kernel /vmlinuz vnc vncpassword=12345678 headless ip=10.36.64.238 netmask=255.255.255.0 gateway=10.36.64.254 dns=10.36.10.8 hostname=0map238 ksdevice=eth0 method=http://mirrors.163.com/centos/6/os/x86_64/ lang=
en_US keymap=us
initrd /initrd.img

在"hiddenmenu" 和 "title CentOS..." 增加一项:
method中的url为安装centos的源

重启后使用vnc软件连接服务器 IP:1 ,并输入刚刚设置的vnc密码即可进行centos的重装。这个过程中机器需要下载一些镜像,大约要等待15分钟,VNC才可以访问。

使用OneApm CI SDK实现业务响应速度监控

目前负责的业务处于急速扩张期,每周会增加几台服务器,业务日访问量在5000万左右。

目前的监控需求在可用性和响应速度。运营的需求要求每次接口响应控制在0.1-0.5s内。

在现在的基础监控中,可以分析出http业务的可用性,但没法监控具体的响应时间。
最开始使用的方法为在后端添加serverId和处理时间并放到http header中,通过curl去获得后端信息和处理时间,采样后生成报表。
听起来就比较复杂。
再后来,改成通过nginx记录upstream的response time,采样生成可视化。
由于nginx日志分布于不同的机器中,收集数据相对来讲还是比较麻烦的。

后来将一部分监控迁到OneAPM上,折腾一段时间以后,无意中发现了CI有一个SDK,学习了一下,发现可以实现一些业务层的监控。
经过一段时间的试验,发现CI SDK使用起来非常方便,能方便的接入丰富的业务数据。

其实现的原理为隔一段时间采样一个数据,上报给CI,CI会根据输入的数值,生成线性报表。
下面是一些使用的经验,分享给大家。

以下是抄了OneApm的官方介绍,供参考。

==============================

OneApm CI是什么
http://docs-ci.oneapm.com/

Cloud Insight SDK For Python
http://docs-ci.oneapm.com/api/python.html

Cloud Insight 集成了数十种互联网流行基础组件的监控,开箱即用,您只需要进行最小化的配置就可以实现复杂的基础组件监控, 免除了传统基础组件监控中的复杂流程。Cloud Insight 采集这些基础组件的权威指标,所有指标都是标准化的格式,您再也不需要 自己定义各种指标,以及思考如何进行各种指标的组合展示,一切就只有两步,安装探针,查看仪表盘,如果您使用的是阿里云、UCloud 等云厂商,甚至不需要安装探针,Cloud Insight 会直接通过这些云厂商提供的 API 收集服务器以及基础组件的性能和健康情况的 指标,并友好的展示在定义好的仪表盘中。

OneApm CI还提供了SDK,可以实现自定义的业务数据监控,比如业务的订单趋势,响应速度曲线等。配合CI的丰富报表功能,非常轻松的实现自定义业务监控。

==============================

按照文档,安装CI, 及CI SDK,这里不再赘述。
step 1, OneAPM CI Agent 安装
step 2, OneApm CI SDK For Python安装
step 3, 编写一段简单的python 代码

#!/usr/bin/env python
# -*- coding:utf8 -*-

import commands
import socket
from oneapm_ci_sdk import statsd

hostname = socket.gethostname()
error, result = commands.getstatusoutput(""" tail /opt/dataroot/nginx/access.log |grep "download" | awk -F '" "' '{print $7}' """)
if ( error == 0 ):
        code = result.split("\n")
        statsd.gauge('php_response_time.download.%s' % hostname, float( max(code) ) )
        print 'php_response_time.%s : %04f' % ( hostname, float(max(code)) )

上述代码实现的逻辑为调用系统命令,获取nginx中,php的responsetime,从几个响应时间中取最大值。

step 4, 部署收集数据

#获取Nginx Upstream response time
* * * * * for i in $(seq 3); do sleep 15; python /opt/ci_check_php_response_time.py; done

添加上述计划任务,每秒统计三次响应最慢的请求。由于默认的系统计划任务无法实现按秒制定任务,通过sleep间接实现。

step 5, 查看报表

进入 https://cloud.oneapm.com/dashboard#/,在最右下角找到自定义仪表盘,
效果如下:

QQ20160318-0

根据官方文档的说明,未来还会开放不需要SDK的API,非常适合做一些私有业务的监控和告警,非常期待。

Cloud Insight API

API 提供了更加强大的功能,您可以不受任何约束的发送符合Cloud Insight数据格式标准的任意数据,无论本机是否安装了Cloud Insight Agent。目前API正在开发之中。

在几个月的使用中,OneApm CI和AI,给我们提供了非常多的帮助,慢慢的使用才发现OneApm的强大,感谢 OneApm 志利在使用过程中给我们的帮助,不管是晚上还是周末,响应速度非常快,非常感动。
下次分享一下在使用AI的过程中,通过AI定位ThinkPHP中Redis连接异常的一个故障处理。

Update:

CI在这个月发布了新版,也提供了新的PHPSDK,可以愉快的从之前的python sdk切过来了。同时,也增加了仪表盘分享功能。

aws ami 执行yum出现"Protected multilib versions: openssl-1.0.1e-42.el6_7.2.x86_64 != openssl-1.0.1e-42.el6.i686"

[txtplain]
--> Finished Dependency Resolution
Error: Multilib version problems found. This often means that the root
cause is something else and multilib version checking is just
pointing out that there is a problem. Eg.:

1. You have an upgrade for openssl which is missing some
dependency that another package requires. Yum is trying to
solve this by installing an older version of openssl of the
different architecture. If you exclude the bad architecture
yum will tell you what the root cause is (which package
requires what). You can try redoing the upgrade with
--exclude openssl.otherarch ... this should give you an error
message showing the root cause of the problem.

2. You have multiple architectures of openssl installed, but
yum can only see an upgrade for one of those arcitectures.
If you don't want/need both architectures anymore then you
can remove the one with the missing update and everything
will work.

3. You have duplicate versions of openssl installed already.
You can use "yum check" to get yum show these errors.

...you can also use --setopt=protected_multilib=false to remove
this checking, however this is almost never the correct thing to
do as something else is very likely to go wrong (often causing
much more problems).

Protected multilib versions: openssl-1.0.1e-42.el6_7.2.x86_64 != openssl-1.0.1e-42.el6.i686
[/txtplain]

原因未知,卸载掉openssl-1.0.1e-42.el6.i686即可

Tail for php,php实现tail命令

监控文件变化,可以通过tail,inotify来实现,也可以通过awk转发变化的内容到外部命令中。

下面是通过popen来调用系统命令,性能内存开销相对比较小。

```php
$handle = popen("tail -f /var/log/your_file.log 2>&1", 'r');
while(!feof($handle)) {
$buffer = fgets($handle);
echo "$buffer\n";
flush();
}
pclose($handle);
```

Linux Shell 文本处理工具集锦

本文将介绍Linux下使用Shell处理文本时最常用的工具:
find、grep、xargs、sort、uniq、tr、cut、paste、wc、sed、awk;
提供的例子和参数都是最常用和最为实用的;
我对shell脚本使用的原则是命令单行书写,尽量不要超过2行;
如果有更为复杂的任务需求,还是考虑python吧;

继续阅读Linux Shell 文本处理工具集锦

Android ADB命令大全

(通过ADB命令查看wifi密码、MAC地址、设备信息、操作文件、查看文件、日志信息、卸载、启动和安装APK等)

ADB很强大,记住一些ADB命令有助于提高工作效率。

  1. 获取序列号:
     adb get-serialno
  2. 查看连接计算机的设备:
     adb devices
  3. 重启机器:
     adb reboot
  4. 重启到bootloader,即刷机模式:
     adb reboot bootloader
  5. 重启到recovery,即恢复模式:
     adb reboot recovery
  6. 查看log:
     adb logcat
  7. 终止adb服务进程:
     adb kill-server
  8. 重启adb服务进程:
     adb start-server
  9. 获取机器MAC地址:
     adb shell  cat /sys/class/net/wlan0/address
  10. 获取CPU序列号:
    adb shell cat /proc/cpuinfo
  11. 安装APK:
    adb install <apkfile> //比如:adb install baidu.apk
  12. 保留数据和缓存文件,重新安装apk:
    adb install -r <apkfile> //比如:adb install -r baidu.apk
  13. 安装apk到sd卡:
    adb install -s <apkfile> // 比如:adb install -s baidu.apk
  14. 卸载APK:
    adb uninstall <package> //比如:adb uninstall com.baidu.search
  15. 卸载app但保留数据和缓存文件:
    adb uninstall -k <package> //比如:adb uninstall -k com.baidu.search
  16. 启动应用:
    adb shell am start -n <package_name>/.<activity_class_name>
  17. 查看设备cpu和内存占用情况:
    adb shell top
  18. 查看占用内存前6的app:
    adb shell top -m 6
  19. 刷新一次内存信息,然后返回:
    adb shell top -n 1
  20. 查询各进程内存使用情况:
    adb shell procrank
  21. 杀死一个进程:
    adb shell kill [pid]
  22. 查看进程列表:
    adb shell ps
  23. 查看指定进程状态:
    adb shell ps -x [PID]
  24. 查看后台services信息:
    adb shell service list
  25. 查看当前内存占用:
    adb shell cat /proc/meminfo
  26. 查看IO内存分区:
    adb shell cat /proc/iomem
  27. 将system分区重新挂载为可读写分区:
    adb remount
  28. 从本地复制文件到设备:
    adb push <local> <remote>
  29. 从设备复制文件到本地:
    adb pull <remote>  <local>
  30. 列出目录下的文件和文件夹,等同于dos中的dir命令:
    adb shell ls
  31. 进入文件夹,等同于dos中的cd 命令:
    adb shell cd <folder>
  32. 重命名文件:
    adb shell rename path/oldfilename path/newfilename
  33. 删除system/avi.apk:
    adb shell rm /system/avi.apk
  34. 删除文件夹及其下面所有文件:
    adb shell rm -r <folder>
  35. 移动文件:
    adb shell mv path/file newpath/file
  36. 设置文件权限:
    adb shell chmod 777 /system/fonts/DroidSansFallback.ttf
  37. 新建文件夹:
    adb shell mkdir path/foldelname
  38. 查看文件内容:
    adb shell cat <file>
  39. 查看wifi密码:
    adb shell cat /data/misc/wifi/*.conf
  40. 清除log缓存:
    adb logcat -c
  41. 查看bug报告:
    adb bugreport
  42. 获取设备名称:
    adb shell cat /system/build.prop
  43. 查看ADB帮助:
    adb help
  44. 跑monkey:
    adb shell monkey -v -p your.package.name 500

More:

Linux清除日志

cat /dev/null > /var/log/wtmp
cat /dev/null > /var/log/messages
cat /dev/null > /var/log/secure
cat /dev/null > /var/log/lastlog
rm -f /var/log/wtmp*
rm -f /root/.bash_history
touch .hushlogin
history -c

cat /dev/null > /var/log/syslog
cat /dev/null > /var/adm/sylog
cat /dev/null > /var/log/wtmp
cat /dev/null > /var/log/maillog
cat /dev/null > /var/log/messages
cat /dev/null > /var/log/openwebmail.log
cat /dev/null > /var/log/maillog
cat /dev/null > /var/log/secure
cat /dev/null > /var/log/httpd/error_log
cat /dev/null > /var/log/httpd/ssl_error_log
cat /dev/null > /var/log/httpd/ssl_request_log
cat /dev/null > /var/log/httpd/ssl_access_log

兼容所有linux操作系统的shell

#!/bin/bash
#########################################
#Function:    update time
#Usage:       bash update_time.sh
#Author:      Customer service department
#Company:     Alibaba Cloud Computing
#Version:     3.0
#########################################

check_os_release()
{
  while true
  do
    os_release=$(grep "Red Hat Enterprise Linux Server release" /etc/issue 2>/dev/null)
    os_release_2=$(grep "Red Hat Enterprise Linux Server release" /etc/redhat-release 2>/dev/null)
    if [ "$os_release" ] && [ "$os_release_2" ]
    then
      if echo "$os_release"|grep "release 5" >/dev/null 2>&1
      then
        os_release=redhat5
	os_type=redhat
        echo "$os_release"
      elif echo "$os_release"|grep "release 6" >/dev/null 2>&1
      then
        os_release=redhat6
	os_type=redhat
        echo "$os_release"
      else
        os_release=""
        echo "$os_release"
      fi
      break
    fi
    os_release=$(grep "Aliyun Linux release" /etc/issue 2>/dev/null)
    os_release_2=$(grep "Aliyun Linux release" /etc/aliyun-release 2>/dev/null)
    if [ "$os_release" ] && [ "$os_release_2" ]
    then
      if echo "$os_release"|grep "release 5" >/dev/null 2>&1
      then
        os_release=aliyun5
	os_type=redhat
        echo "$os_release"
      elif echo "$os_release"|grep "release 6" >/dev/null 2>&1
      then
        os_release=aliyun6
	os_type=redhat
        echo "$os_release"
      else
        os_release=""
        echo "$os_release"
      fi
      break
    fi
    os_release=$(grep "CentOS release" /etc/issue 2>/dev/null)
    os_release_2=$(grep "CentOS release" /etc/*release 2>/dev/null)
    if [ "$os_release" ] && [ "$os_release_2" ]
    then
      if echo "$os_release"|grep "release 5" >/dev/null 2>&1
      then
        os_release=centos5
	os_type=redhat
        echo "$os_release"
      elif echo "$os_release"|grep "release 6" >/dev/null 2>&1
      then
        os_release=centos6
	os_type=redhat
        echo "$os_release"
      else
        os_release=""
        echo "$os_release"
      fi
      break
    fi
    os_release=$(grep -i "ubuntu" /etc/issue 2>/dev/null)
    os_release_2=$(grep -i "ubuntu" /etc/lsb-release 2>/dev/null)
    if [ "$os_release" ] && [ "$os_release_2" ]
    then
      if echo "$os_release"|grep "Ubuntu 10" >/dev/null 2>&1
      then
        os_release=ubuntu10
	os_type=ubuntu
        echo "$os_release"
      elif echo "$os_release"|grep "Ubuntu 12.04" >/dev/null 2>&1
      then
        os_release=ubuntu1204
	os_type=ubuntu
        echo "$os_release"
      elif echo "$os_release"|grep "Ubuntu 12.10" >/dev/null 2>&1
      then
        os_release=ubuntu1210
	os_type=ubuntu
        echo "$os_release"
      else
        os_release=""
        echo "$os_release"
      fi
      break
    fi
    os_release=$(grep -i "debian" /etc/issue 2>/dev/null)
    os_release_2=$(grep -i "debian" /proc/version 2>/dev/null)
    if [ "$os_release" ] && [ "$os_release_2" ]
    then
      if echo "$os_release"|grep "Linux 6" >/dev/null 2>&1
      then
        os_release=debian6
	os_type=debian
        echo "$os_release"
      else
        os_release=""
        echo "$os_release"
      fi
      break
    fi
    break
    done
}

modify_rhel5_yum()
{
  wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyuncs.com/repo/Centos-5.repo
  sed -i 's/aliyun/aliyuncs/g' /etc/yum.repos.d/CentOS-Base.repo
  sed -i 's/\$releasever/5/' /etc/yum.repos.d/CentOS-Base.repo
  yum clean metadata
  yum makecache
  cd ~
}

modify_rhel6_yum()
{
  wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyuncs.com/repo/Centos-6.repo
  sed -i 's/aliyun/aliyuncs/g' /etc/yum.repos.d/CentOS-Base.repo
  sed -i 's/\$releasever/6/' /etc/yum.repos.d/CentOS-Base.repo
  yum clean metadata
  yum makecache
  cd ~
}

update_ubuntu10_apt_source()
{
echo -e "\033[40;32mBackup the original configuration file,new name and path is /etc/apt/sources.list.back.\n\033[40;37m"
cp -fp /etc/apt/sources.list /etc/apt/sources.list.back
cat > /etc/apt/sources.list <<EOF
#ubuntu
deb http://cn.archive.ubuntu.com/ubuntu/ maverick main restricted universe multiverse
deb-src http://cn.archive.ubuntu.com/ubuntu/ maverick main restricted universe multiverse
#163
deb http://mirrors.163.com/ubuntu/ maverick main universe restricted multiverse
deb-src http://mirrors.163.com/ubuntu/ maverick main universe restricted multiverse
deb http://mirrors.163.com/ubuntu/ maverick-updates universe main multiverse restricted
deb-src http://mirrors.163.com/ubuntu/ maverick-updates universe main multiverse restricted
#lupaworld
deb http://mirror.lupaworld.com/ubuntu/ maverick main universe restricted multiverse
deb-src http://mirror.lupaworld.com/ubuntu/ maverick main universe restricted multiverse
deb http://mirror.lupaworld.com/ubuntu/ maverick-security universe main multiverse restricted
deb-src http://mirror.lupaworld.com/ubuntu/ maverick-security universe main multiverse restricted
deb http://mirror.lupaworld.com/ubuntu/ maverick-updates universe main multiverse restricted
deb http://mirror.lupaworld.com/ubuntu/ maverick-proposed universe main multiverse restricted
deb-src http://mirror.lupaworld.com/ubuntu/ maverick-proposed universe main multiverse restricted
deb http://mirror.lupaworld.com/ubuntu/ maverick-backports universe main multiverse restricted
deb-src http://mirror.lupaworld.com/ubuntu/ maverick-backports universe main multiverse restricted
deb-src http://mirror.lupaworld.com/ubuntu/ maverick-updates universe main multiverse restricted
EOF
apt-get update
}

update_ubuntu1204_apt_source()
{
echo -e "\033[40;32mBackup the original configuration file,new name and path is /etc/apt/sources.list.back.\n\033[40;37m"
cp -fp /etc/apt/sources.list /etc/apt/sources.list.back
cat > /etc/apt/sources.list <<EOF
#12.04
deb http://mirrors.aliyuncs.com/ubuntu/ precise main restricted universe multiverse
deb http://mirrors.aliyuncs.com/ubuntu/ precise-security main restricted universe multiverse
deb http://mirrors.aliyuncs.com/ubuntu/ precise-updates main restricted universe multiverse
deb http://mirrors.aliyuncs.com/ubuntu/ precise-proposed main restricted universe multiverse
deb http://mirrors.aliyuncs.com/ubuntu/ precise-backports main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ precise main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ precise-security main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ precise-updates main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ precise-proposed main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ precise-backports main restricted universe multiverse
EOF
apt-get update
}

update_ubuntu1210_apt_source()
{
echo -e "\033[40;32mBackup the original configuration file,new name and path is /etc/apt/sources.list.back.\n\033[40;37m"
cp -fp /etc/apt/sources.list /etc/apt/sources.list.back
cat > /etc/apt/sources.list <<EOF
#12.10
deb http://mirrors.aliyuncs.com/ubuntu/ quantal main restricted universe multiverse
deb http://mirrors.aliyuncs.com/ubuntu/ quantal-security main restricted universe multiverse
deb http://mirrors.aliyuncs.com/ubuntu/ quantal-updates main restricted universe multiverse
deb http://mirrors.aliyuncs.com/ubuntu/ quantal-proposed main restricted universe multiverse
deb http://mirrors.aliyuncs.com/ubuntu/ quantal-backports main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ quantal main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ quantal-security main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ quantal-updates main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ quantal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyuncs.com/ubuntu/ quantal-backports main restricted universe multiverse
EOF
apt-get update
}

config_time_zone()
{
  if [ "$os_type" == "redhat" ]
  then
    if [ -e "/usr/share/zoneinfo/Asia/Shanghai" ]
    then
      echo -e "\033[40;32mStep1:Begin to config time zone.\n\033[40;37m"
      cp -fp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      echo -e "ZONE=\"Asia/Shanghai\"\nUTC=false\nARC=false">/etc/sysconfig/clock
    fi
  elif [ "$os_type" == "ubuntu" ] || [ "$os_type" == "debian" ]
  then
    echo -e "\033[40;32mStep1:Begin to config time zone.\n\033[40;37m"
    cp -fp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  fi
}

update_debian_apt_source()
{
cat >> /etc/apt/sources.list <<EOF
#debian6
deb http://mirrors.aliyuncs.com/debian/ squeeze main non-free contrib
deb http://mirrors.aliyuncs.com/debian/ squeeze-proposed-updates main non-free contrib
deb-src http://mirrors.aliyuncs.com/debian/ squeeze main non-free contrib
deb-src http://mirrors.aliyuncs.com/debian/ squeeze-proposed-updates main non-free contrib
EOF
apt-get update
}

install_ntp()
{
  case "$os_release" in
  redhat5|centos5|aliyun5)
    modify_rhel5_yum
    if ! yum install ntp -y
    then
      echo "Can not install ntp.Script will end."
      rm -rf $LOCKfile
      exit 1
    fi
    ;;
  redhat6|centos6|aliyun6)
    modify_rhel6_yum
    if ! yum install ntp -y
    then
      echo "Can not install ntp.Script will end."
      rm -rf $LOCKfile
      exit 1
    fi
    ;;
  ubuntu10)
    update_ubuntu10_apt_source
    if ! apt-get install ntp ntpdate -y
    then
      echo "Can not install ntp.Script will end."
      rm -rf $LOCKfile
      exit 1
    fi
    ;;
 ubuntu1204)
   update_ubuntu1204_apt_source
   if ! apt-get install ntp ntpdate -y
   then
     echo "Can not install ntp.Script will end."
     rm -rf $LOCKfile
     exit 1
   fi
   ;;
 ubuntu1210)
   update_ubuntu1210_apt_source
   if ! apt-get install ntp ntpdate -y
   then
     echo "Can not install ntp.Script will end."
     rm -rf $LOCKfile
     exit 1
   fi
   ;; 
 debian6)
   update_debian_apt_source
   if ! apt-get install ntp ntpdate -y
   then
     echo "Can not install ntp.Script will end."
     rm -rf $LOCKfile
     exit 1
   fi
   ;;
 esac
}

mod_config_file()
{
  if [ "$os_type" == "redhat" ]
  then
     if ! grep "aliyun.com" /etc/ntp/step-tickers >/dev/null 2>&1
     then
       echo -e "ntp1.aliyun.com\nntp1.aliyun.com\nntp1.aliyun.com\n0.asia.pool.ntp.org\n210.72.145.44">>/etc/ntp/step-tickers
     fi
  fi
  if ! grep "aliyun.com" /etc/ntp.conf >/dev/null 2>&1
  then
    echo -e "server ntp1.aliyun.com prefer\nserver ntp2.aliyun.com\nserver ntp3.aliyun.com\nserver 0.asia.pool.ntp.org\nserver 210.72.145.44">>/etc/ntp.conf
  fi
}

install_chkconfig()
{
  if [ "$os_type" == "redhat" ] || [ "$os_type" == "centos" ]
  then
     yum install chkconfig -y
  elif [ "$os_type" == "ubuntu" ] || [ "$os_type" == "debian" ]
  then
     apt-get install rcconf dialog whiptail -y --force-yes --fix-missing
  fi
}

####################Start###################
#check lock file ,one time only let the script run one time 
LOCKfile=/tmp/.$(basename $0)
if [ -f "$LOCKfile" ]
then
  echo -e "\033[1;40;31mThe script is already exist,please next time to run this script.\n\033[0m"
  exit
else
  echo -e "\033[40;32mStep 0.No lock file,begin to create lock file and continue.\n\033[40;37m"
  touch $LOCKfile
fi

#check user
if [ $(id -u) != "0" ]
then
  echo -e "\033[1;40;31mError: You must be root to run this script, please use root to install this script.\n\033[0m"
  rm -rf $LOCKfile
  exit 1
fi
check_os_release
config_time_zone

echo -e "\033[40;32mStep2:Check ntp package and if not to install it.\n\033[40;37m"
install_ntp

echo -e "\033[40;32mStep3:Modify the ntp config file.\n\033[40;37m"
mod_config_file

echo -e "\033[40;32mStep4:Begin to update time...\n\033[40;37m"
ntpdate -u ntp1.aliyun.com
ntpdate -u ntp2.aliyun.com

echo -e "\033[40;32mStep5:Restart ntp service...\n\033[40;37m"
if [ "$os_type" == "redhat" ] || [ "$os_type" == "centos" ]
then
   service ntpd restart
elif [ "$os_type" == "ubuntu" ] || [ "$os_type" == "debian" ]
then
   service ntp restart
fi

install_chkconfig
if [ "$os_type" == "redhat" ] || [ "$os_type" == "centos" ]
then
   chkconfig --level 2345 ntpd on
elif [ "$os_type" == "ubuntu" ] || [ "$os_type" == "debian" ]
then
   rcconf --on ntp
fi
echo -e "\033[40;32mStep6:The NTP service is configured to start automatically at runlevels 2345.\n\033[40;37m"
rm -rf $LOCKfile