ubuntu 使用apt-get install 升级安装php5.6

php5.6版本比之前任何一个PHP版本速度上都要快一些,所以,宝讯决定把服务器上的PHP升级到5.6版本,以此来提升服务器的性能。

$ sudo apt-get install python-software-properties
$ sudo add-apt-repository ppa:ondrej/php
$ sudo apt-get update
$ sudo apt-get -y install php5.6 php5.6-mcrypt php5.6-mbstring php5.6-curl php5.6-cli php5.6-mysql php5.6-gd php5.6-intl php5.6-xsl php5.6-zip

如果第一行命令报错,先执行下面的命令

$ sudo apt-get install software-properties-common python-software-properties 

安装成功后,需要将/etc/apache2/mods-available/php5.load中的php加载路径修改为:

LoadModule php5_module /usr/lib/apache2/modules/libphp5.6.so

编辑/etc/php/5.6/apache2/php.ini配置文件,看需要php什么扩展,就把前面的;后删除。

最后,重启apache使之生效!

UBUNTU 解决非正常关闭APT-GET的锁

在ubuntu的命令行窗口中使用apt-get命令安装程序, 命令未执行完的情况下关闭窗口或使用Ctrl+C来结束命令。 当我们再次使用apt-get命令安装程序的时候, 报错信息如下:

E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)
E: 无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它?

我们执行如下命令, 删除锁定的文件

$ sudo rm -rf /var/cache/apt/archives/lock
$ sudo rm -rf /var/lib/dpkg/lock

此时, 我们再次执行命令apt-get install, 获得如下报错信息:

E: dpkg 被中断,您必须手工运行 sudo dpkg --configure -a 解决此问题。

我们执行脚本 sudo dpkg –configure -a, 获得新的报错信息:

debconf: DbDriver "config": /var/cache/debconf/config.dat is locked by another process: 资源暂时不可用

我们执行rm命令将该文件也删除:

$ sudo rm -rf /var/cache/debconf/config.dat

再次运行apt-get install命令, 一切恢复正常。

Apache 获取真实ip的配置的实现方法

Apache 获取真实ip的配置的实现方法

最近因为用了web应用防火墙产品(阿里云的),所以获取不到用户的真实ip。

经过多方搜集尝试,方案如下:

apache2.4提供了自带的remoteip模块可以实现获取真实ip。

我的环境是:ubunt16.04 Apache2.4.18

cd /etc/apache2.mods-available

新建配置文件

vim remoteip.conf

输入:

RemoteIPHeader X-Forwarded-For

RemoteIPProxiesHeader X-Forwarded-By

保存

启用:

a2enmod remoteip

重启apache即可生效。

详细分析apache httpd反向代理的用法

代理方式有两种:正向代理和反向代理。

正向代理是为客户端转发请求,各客户端将请求交给正向代理服务器,正向代理服务器再负责转发给服务端,响应时服务端先响应给正向代理服务器,正向代理服务器再转发给对应的客户端。也就是说,正向代理是为局域网内客户端做代理,它扮演的角色类似于NAT。

反向代理是为服务端转发请求,客户端将请求发送至反向代理服务器,反向代理服务器再将请求转发给真正的服务器以处理请求,响应时后端真正的服务器将处理结果发送给反向代理,再由反向代理构建响应并响应给客户端。

一、正向代理

httpd通过ProxyRequests指令配置正向代理的功能。例如:

ProxyRequests On
ProxyVia On

<Proxy "*">
  Require host internal.example.com
</Proxy>

其中< Proxy >容器表示的是只有internal.example.com下的主机可以通过该正向代理去访问任意URL的请求内容。ProxyVia指令表示在响应首部中添加一个Via字段。

二、反向代理

为了成为一个”基本的”web server,提供静态和动态内容给最终用户,httpd(以及其他大多数web server)可以扮演反向代理服务器的角色,也就是众所周知的”网关”服务器。

在这种场景下,Httpd自身不生成产出数据,而是从后端服务器中获取数据,这些后端服务器器一般不会和外界网络通信。当httpd从客户端接收到请求,请求被代理到后端服务器组中的其中一个服务器上,该后端服务器处理请求,生成内容并返回内容给httpd server,最后由httpd server生成实际的HTTP响应给客户端。

有无数应该使用反向代理的理由,最常见的是安全、高可用、负载均衡、集中授权/认证。反向代理的布置和架构中,后端服务器(真正处理请求的服务器)和外界完全绝缘并由此受到保护,对于外界客户端来说,当他们需要关心服务器对象是谁时,它们得到的结果总是反向代理服务器,而非后端服务器。

一个典型的实现如下:

未分类

2.1 简单的反向代理配置

ProxyPass指令用于映射请求到后端服务器。最简单的代理示例是对所有请求”/”都映射到一个后端服务器上:

ProxyPass "/"  "http://www.example.com/"
ProxyPassMatch "^/((?i).*.php)$" "fcgi://127.0.0.1:9000/var/www/a.com/$1"

为了地址重定向时也能正确使用反向代理,应该使用ProxyPassReverse指令。

ProxyPass "/"  "http://www.example.com/"
ProxyPassReverse "/"  "http://www.example.com/"

或者只为特定的URI进行代理,例如下面的配置,只有/images开头的路径才会代理转发,其他的所有请求都在本地处理。

ProxyPass "/images"  "http://www.example.com/"
ProxyPassReverse "/images"  "http://www.example.com/"

假如本地服务器地址为http://www1.example.com,当请求http://www1.example.com/images/a.gif时,将代理为http://www.example.com/a.gif。

2.2 负载均衡:后端成员

上面的配置中没有添加后端服务器节点,无法享受反向代理的优点。因此,有必要添加后端节点。添加的方法是使用< proxy >容器将后端节点定义成一个负载均衡组,各节点是该组中成员,然后代理目标指向组名即可。

例如:

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080
    ProxySet lbmethod=bytraffic
</Proxy>

ProxyPass "/images/"  "balancer://myset/"
ProxyPassReverse "/images/"  "balancer://myset/"

balancer://myset告诉httpd,它创建了一个负载均衡节点集合,名称为myset,此集合中有两个后端成员。在上面的配置中,任意/images的请求都会代理至2个成员中的一个。ProxySet指令指定myset均衡组使用的均衡算法为bytraffic,即基于I/O流量字节数权重的算法。ProxySet指令设置的是Proxy容器的公共属性。

httpd有3种复杂均衡算法:

  • byrequests:默认。基于请求数量计算权重。
  • bytraffic:基于I/O流量大小计算权重。
  • bybusyness:基于挂起的请求(排队暂未处理)数量计算权重。

对于上面的示例,还可以稍加修改,使其支持更多功能。例如添加权重比例,使得某后端节点被转发到的权重是另一节点的3倍,等待后端节点返回数据的超时时间为1秒。

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
    ProxySet lbmethod=byrequests
</Proxy>

ProxyPass "/images"  "balancer://myset/"
ProxyPassReverse "/images"  "balancer://myset/"

2.3 故障转移

还可以再次调整实现故障转移,例如当所有负载节点都失败时,指定一个备份节点(standby node)。参考如下配置:

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
    BalancerMember http://hstandby.example.com:8080 status=+H
    BalancerMember http://bkup1.example.com:8080 lbset=1
    BalancerMember http://bkup2.example.com:8080 lbset=1
    ProxySet lbmethod=byrequests
</Proxy>

ProxyPass "/images/"  "balancer://myset/"
ProxyPassReverse "/images/"  "balancer://myset/"

其中成员1、2、4、5是负载节点,成员3是备份节点。当所有负载节点都不健康时,将转发请求给备份节点,并由备份节点处理请求,httpd设置备份节点的方式很简单,只需将状态设置为”H”,表示hot-standby。还需注意的是负载节点4、5,它们额外的参数为lbset=1,不写时默认为0,这是负载均衡时的优先级设置,负载均衡时总是先转发给低数值的节点,也就是说或数值越小,优先级越高。所以上面的配置中,当节点1、2正常工作时,只在它们之间进行负载,此时节点4、5处于闲置状态。只有当节点1、2都失败时,才会在节点4、5之间进行负载。

2.4 提供负载状态显示页面

<Location "/bm">
    SetHandler balancer-manager
    Require host localhost
    Require ip 192.168.100
</Location>

然后在浏览器中输入http://server/bm即可,返回结果如图。

未分类

2.5 proxy相关指令

2.5.1 ProxyPass指令

该指令将远程服务器映射到本地主机上,但本地主机不是真实的服务器,而是远程主机的一个镜像。这个镜像通常称为反向代理服务器或网关。该指令不能用于< Directory >、< Files >容器中,且使用该指令时通常会关闭正向代理,即ProxyRequests=off。

语法:

ProxyPass [path] !|url [key=value [key=value ...]]

path参数为本地主机的URL路径,url参数为远程服务器的url一部分,不能包含查询参数。如果第一个参数path尾随了斜线,则url部分也必须尾随斜线,反之亦然。如果该指令封装在< Location >容器中,则第一个参数path可以省略,因为Location中已经指定了URL路径。如果第二个参数为”!”,则表示此path不使用反向代理功能。

例如:

<Location "/mirror/foo/">
    ProxyPass "http://backend.example.com/foo/"
</Location>

当访问http://server/mirror/foo/bar时,将转发到http://backend.example.com主机上,并请求该主机的/foo/bar文件。下面的配置指令与此等价。

ProxyPass "/mirror/foo/" "http://backend.example.com/foo/"

如果想让某个子目录不进行反向代理,而是在本地处理。可以设置第二个参数为”!”。例如,下面的配置中,/mirror/foo会被代理,但/mirror/foo/i则不会被代理。

ProxyPass "/mirror/foo/i" "!"
ProxyPass "/mirror/foo" "http://backend.example.com"

再需要说明的是连接池,httpd会为后端节点创建连接池,httpd会连接连接池中的各个节点。后端节点属性相同的共享一个连接池。后端节点的属性由key=value参数指定。以下是常见的一些属性设置,完整的属性见官方手册 (http://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypass) 。

  • keepalive=Off|On:默认为Off。设置httpd和后端节点之间是否开启长连接,注意,这和web服务的长连接不一样,此处设置的是反向代理服务器和后端节点两者连接,当httpd将请求转发给连接池中的一个节点,并等待返回数据,当数据返回完成后,连接立即关闭,如果开启了长连接,连接暂时不关闭,只有等待均衡算法下次轮到该节点时才会再使用该连接。通常只有在httpd和后端节点间使用了防火墙时才设置为On。

  • lbset=N:默认为0。设置后端节点的优先级。数值N越低的,优先级越高。httpd总是会先尝试优先级高的,只有优先级高的节点不可用时,才一会尝试优先级低的。

  • ping=N:默认为0。设置健康状况检查时间间隔。该ping只能检查是否能ping同对方,也就是检测是否能与对方通信。更多的健康状况检查应该使用mod_proxy_hcheck模块。

  • retry=N:默认为60秒。当检测到后端某节点错误状态(error status)时,将在每N秒后才转发一次请求给该节点。设置为0表示正常转发请求,不用任何等待时间。该属性通常设置用来维护服务器下线然后再上线的情况。

  • status=VALUE:将节点手动置为何种状态。包括以下几种状态,各状态可使用”+”(默认)来赋予属性,使用”-“来取消属性。例如”+H”,”S-E”。

    • D: 该节点被禁用,不再接受任何请求。

    • S: 该节点处于管理维护的目的被停止。

    • I: 将该节点设置为无视错误(ignore-errors)模式,此模式下httpd将认为该节点可用,总会转发请求给该节点。

    • H: 该节点处于hot-standby模式,该节点只有在其他所有后端节点都失效时才启用。因此,该节点为备份节点。

    • E: 将该节点设置为错误状态(error-state)。

    • N: 将该节点设置为drain模式,该模式只接受已预定粘滞会话的请求sticky session,其他所有请求都会被忽略。

  • timeout=ProxyTimeout:设置httpd等待后端节点返回数据的超时时间。

如果使用了”balancer://”,例如前面的balancer://myset,将创建一个虚拟的连接池。虚拟连接池中的各节点可共享部分属性,也可以为每个节点设置上面所说的属性。共享属性使用ProxySet指令设置,常见的包括下面几种:

  • lbmethod=METHOD:设置负载均衡算法。有三种:byrequests(默认)按照请求数量计算均衡节点;bytraffic按照io流量计算均衡节点;bybusyness按照繁忙程度计算计算均衡节点。

  • nofailover=On|Off:默认为off。session不可用时是否转移到其他具有相同session的节点上。如果后端节点不支持session复制,应将此项设置为on。

  • stickysession:设置session粘滞的名称,如JSESSIONID、PHPSESSIONID。

例如:

<Proxy balancer://myset>
    BalancerMember http://www2.example.com:8080
    BalancerMember http://www3.example.com:8080 loadfactor=3 timeout=1
    BalancerMember http://hstandby.example.com:8080 status=+H
    BalancerMember http://bkup1.example.com:8080 lbset=1
    BalancerMember http://bkup2.example.com:8080 lbset=1
    ProxySet lbmethod=byrequests
</Proxy>

ProxyRequests off
ProxyPass "/images/"  "balancer://myset/"
ProxyPassReverse "/images/"  "balancer://myset/"

2.5.2 ProxyPassMatch指令

正则匹配模式的ProxyPass。例如:

ProxyPassMatch "^/(.*.gif)$" "http://backend.example.com/$1"
ProxyPassMatch "^/((?i).*.php)$" "fcgi://127.0.0.1:9000/var/www/a.com/$1"

唯一需要注意的是,在正则匹配之前,远程url参数必须是能够解析的URL地址。例如下面两条指令,第一条指令将失败,因为在正则解析前,url参数无法解析为正确的URL地址,这是一个bug,可以通过修改正则表达式的分组部分将”/”分离出去,正如下面的第二个指令。

ProxyPassMatch "^(/.*.gif)$" "http://backend.example.com:8000$1"
ProxyPassMatch "^/(.*.gif)$" "http://backend.example.com:8000/$1"

2.5.3 ProxySet指令

设置Proxy后端节点的属性。通常用来设置共享属性,但也可以设置某一个节点的属性。

例如:

<Proxy "balancer://hotcluster">
    BalancerMember "http://www2.example.com:8080" loadfactor=1
    BalancerMember "http://www3.example.com:8080" loadfactor=2
    ProxySet lbmethod=bytraffic
</Proxy>
<Proxy "http://backend">
    ProxySet keepalive=On
</Proxy>
ProxySet "balancer://foo" lbmethod=bytraffic timeout=15

2.5.4 < Proxy >容器

< Proxy >容器用于封装一组proxy相关指令,这些指令主要用于设置访问权限、负载均衡成员组以及它们的属性。

例如,下面的设置了只有yournetwork.example.com下的主机才能通过该(正向或反向代理)服务器访问任意请求的内容(使用了*进行通配)。

<Proxy "*">
  Require host yournetwork.example.com
</Proxy>
<Proxy "balancer://hotcluster">
    BalancerMember "http://www2.example.com:8080" loadfactor=1
    BalancerMember "http://www3.example.com:8080" loadfactor=2
    ProxySet lbmethod=bytraffic
</Proxy>

2.5.5 ProxyStatus指令

ProxyStatus {on|off|full}决定是否开启server-status中关于proxy的状态信息,默认为off,full是on的同义词。

例如:

ProxyStatus on
<Location "/server-status">
        SetHandler server-status
        Require all granted
</Location>

以下是关于proxy相关的状态示例:

     ----------------------------------------------------------------------

                 Proxy LoadBalancer Status for balancer://myset

   SSes Timeout Method     
   -    0       byrequests 

   Sch  Host           Stat         Route Redir F Set Acc Wr Rd 
   http 192.168.100.14 Init Ok                  1 0   0   0  0  
   http 192.168.100.15 Init Ok                  3 0   0   0  0  
   http 192.168.100.54 Init Stby Ok             1 0   0   0  0  
   http 192.168.100.16 Init Ok                  1 1   0   0  0  
   http 192.168.100.21 Init Ok                  3 1   0   0  0  

     ----------------------------------------------------------------------

   SSes    Sticky session name         
   Timeout Balancer Timeout            
   Sch     Connection scheme           
   Host    Backend Hostname            
   Stat    Worker status               
   Route   Session Route               
   Redir   Session Route Redirection   
   F       Load Balancer Factor        
   Acc     Number of uses              
   Wr      Number of bytes transferred 
   Rd      Number of bytes read

2.5.6 ProxyVia指令

是否在响应首部中添加”Via:”字段。可以设置为On/Off等。例如如设置为On时:

[root@xuexi ~]# curl -I http://192.168.100.17/index.html
HTTP/1.1 200 OK
Date: Sun, 01 Oct 2017 18:10:17 GMT
Server: Apache/2.4.27 (Unix)
Last-Modified: Sun, 01 Oct 2017 14:10:48 GMT
ETag: "29-55a7cd31f2329"
Accept-Ranges: bytes
Content-Length: 41
Content-Type: text/html; charset=UTF-8
Via: 1.1 customer.sharktech.net

2.6 ProxyPass指令的排序和共享问题

ProxyPass指令有个需要注意的问题,在匹配生效时,最先被匹配到的指令立即生效,后面的都将失效。但如果ProxyPass指令放在< Location >容器中时,由于容器中只能放置一个ProxyPass指令(因为path参数一样),此时匹配越精确的越优先。

例如下面的指令,如果将两个ProxyPass指令位置调换,则/mirror/foo/i也仍会被代理。

ProxyPass "/mirror/foo/i" "!"
ProxyPass "/mirror/foo" "http://backend.example.com"

可以将它们分别定义到< Location >容器中,这样就无需考虑位置顺序,而是考虑匹配的精确程度,因为Location容器自身有加载顺序优先级。例如,下面的配置是可行的。

<Location "/mirror/foo/">
    ProxyPass "http://backend.example.com/"
</Location>
<Location "/mirror/foo/i">
    ProxyPass "!"
</Location>

还需考虑一个共享的问题。下面两个指令中的url参数各有长短,且第一个url是第二个url的子串。这时第二个ProxyPass的属性部分总是会使用第一个指令的属性。因此/examples/bar的请求被转发到backend.example.com/examples/bar时,它的属性timeout=60而非10。这样的属性共享可以减少创建连接池,相对来说更有效一些。

ProxyPass "/apps" "http://backend.example.com/" timeout=60
ProxyPass "/examples" "http://backend.example.com/examples" timeout=10

三、健康状况检查模块

ProxyPass指令自带了ping属性,可用于简单判断后端节点是否健康,只要Ping能通信就认为是健康的。但显然,对于Http服务来说,健康的指标并不能简单地通过它来判断。例如,检测某个页面是否正常、是否允许某方法等。因此,httpd提供了一个专门的健康状况检查模块mod_proxy_hcheck用于个性化订制检查指标。

检查指标也即检查方法有以下几种,由hcmethod指定:

  • TCP:检查是否能与后端节点建立TCP套接字,这就是问对方”你还活着吗”。

  • OPTIONS:发送一个HTTP OPTIONS请求给后端节点。

  • HEAD:发送一个HTTP HEAD请求给后端节点。

  • GET:发送一个HTTP GET请求给后端节点。

该健康状况检查模块认为,只要HTTP方法的检查指标返回2xx或3xx状态码都认为是健康的。

指定了检查方法后,还需订制检查的细节,例如检查的时间间隔。包括以下几项:

  • hcinterval:默认为30秒。发送检查的时间间隔,单位为秒。

  • hcuri:健康检查时,追加在URL后的URI。通常用于GET检查方法。

  • hcpasses:默认为1。表示只有检查了N次后都是通过的,才认为该节点是健康的可再次启用。

  • hcfails:默认为1。表示只有检查了N次后都是失败的,才认为该节点已经不健康,于是禁止使用该节点。

例如,以下是几个健康检查的配置示例:

<Proxy balancer://foo>
  BalancerMember http://www.example.com/  hcmethod=GET hcuri=/status.php
  BalancerMember http://www1.example.com/ hcmethod=TCP hcinterval=5 hcpasses=2 hcfails=3
  BalancerMember http://www2.example.com/
</Proxy>

ProxyPass "/" "balancer://foo"
ProxyPassReverse "/" "balancer://foo"

使用Jenkins进行持续构建与发布应用到Kubernetes集群中

我们基于Jenkins的CI/CD流程如下所示。

未分类

流程说明

应用构建和发布流程说明。

  1. 用户向Gitlab提交代码,代码中必须包含Dockerfile;

  2. 将代码提交到远程仓库;

  3. 用户在发布应用时需要填写git仓库地址和分支、服务类型、服务名称、资源数量、实例个数等,确定后触发Jenkins自动构建;

  4. Jenkins的CI流水线自动编译代码并打包成docker镜像推送到Harbor镜像仓库;

  5. Jenkins的CI流水线中包括了自定义脚本,根据我们已准备好的kubernetes的YAML模板,将其中的变量替换成用户输入的选项;

  6. 生成应用的kubernetes YAML配置文件;

  7. 更新Ingress的配置,根据新部署的应用的名称,在ingress的配置文件中增加一条路由信息

  8. 更新PowerDNS,向其中插入一条DNS记录,IP地址是边缘节点的IP地址。关于边缘节点,请查看kubernetes-handbook中的【最佳实践——边缘节点配置】章节;

  9. Jenkins调用kubernetes的API,部署应用到kubernetes集群中。

阿里云CentOS安装Jenkins

Jenkins是一个用Java编写的开源自动化服务器。 Jenkins有助于自动化完成非人员部分的软件开发过程,不断整合和促进连续交付的技术方面。 它是一个基于服务器的系统,可在servlet容器(如Apache Tomcat)中运行。 它支持版本控制工具,包括CVS,Subversion,Git,Mercurial,RTC等,并且可以执行Apache Ant,Apache Maven和基于sbt的项目以及任意shell脚本和Windows批处理命令。

构建可以通过各种手段触发,例如通过在版本控制系统中提交,通过类似cron的机制进行调度,并通过请求特定的构建URL。 也可以在队列中的其他构建完成后触发。 Jenkins功能可以通过插件扩展。

安装Jenkins

使用以下命令安装jenkins:

sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo
sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
sudo yum install jenkins

安装Java:

判断Java是否已经安装

java --version

如果不存在,则用如下命令进行安装:

sudo yum install java

启动、关闭jenkins服务

sudo service jenkins start/stop/restart

阿里云安全组配置

  1. 登录 云服务器管理控制台。

  2. 单击左侧导航中的 安全组。

  3. 选择地域。

  4. 找到要授权规则的安全组,单击 配置规则。

  5. 单击 添加安全组规则。

  6. 在弹出的对话框中,设置下面参数:

未分类

etcd使用之ttl不准确问题

问题现象

部署有一个etcd集群,分别是10.8.65.106,10.8.65.107和10.8.65.108。

然后我使用etcdctl为一个值设置ttl,然后通过watch观察,发现失效时间不准确,而且时间随机。

比如我设置/mytest/test的ttl时间为10秒

[root@node-106 ~]# date &&etcdctl set --ttl 10 /mytest/test hello &&date
Fri Sep  2 05:31:10 EDT 2016
hello
Fri Sep  2 05:31:10 EDT 2016

这里采用的是东八区时间,所以UTC时间应该为2016-09-02T09:31:20

但是通过watch查看时候,发现etcd将其失效时间设置为了2016-09-02T09:31:18,而不是2016-09-02T09:31:20。

[root@node-106 ~]# curl -X GET "http://10.8.65.108:2379/v2/keys/mytest/test1?recursive=false&wait=true&stream=true"
{"action":"set","node":{"key":"/mytest/test","value":"hello","expiration":"2016-09-02T09:31:18.221701998Z","ttl":17,"modifiedIndex":306840,"createdIndex":306840}}
{"action":"expire","node":{"key":"/mytest/test","modifiedIndex":306844,"createdIndex":306840},"prevNode":{"key":"/mytest/test","value":"hello","expiration":"2016-09-02T09:31:18.221701998Z","ttl":9,"modifiedIndex":306840,"createdIndex":306840}}
{"action":"expire","node":{"key":"/mytest/test","modifiedIndex":306844,"createdIndex":306840},"prevNode":{"key":"/mytest/test","value":"hello","expiration":"2016-09-02T09:31:18.221701998Z","ttl":9,"modifiedIndex":306840,"createdIndex":306840}}

这个反复实验多次,发现理论失效时间10秒与实际失效时间的误差,最多可能到9秒,也有0秒。误差似乎是随机的。

问题分析

打开debug模式,进行详细分析。

[root@node-106 ~]# date && etcdctl --debug set --ttl 10 /mytest/test1 hello && date
Fri Sep  2 05:57:20 EDT 2016
start to sync cluster using endpoints(http://127.0.0.1:4001,http://127.0.0.1:2379)
cURL Command: curl -X GET http://127.0.0.1:4001/v2/members
cURL Command: curl -X GET http://127.0.0.1:2379/v2/members
got endpoints(http://10.8.65.107:2379,http://10.8.65.106:2379,http://10.8.65.108:2379) after sync
Cluster-Endpoints: http://10.8.65.107:2379, http://10.8.65.106:2379, http://10.8.65.108:2379
cURL Command: curl -X PUT http://10.8.65.107:2379/v2/keys/mytest/test1 -d "ttl=10&value=hello"
hello
Fri Sep  2 05:57:20 EDT 2016

可以看到etcdctl发起设置请求时,会首先获得集群的members,然后向其中发送一个set mytest/test1的请求。而这个请求会是随机的。如上是请求定位到了10.8.65.107之上。

之后我分别查看了三台机器的时间,发现三台时间不同步。初步判断是时间不同步导致的,因此这里使用ntp进行同步。

[root@node-106 ~]# ntpdate pool.ntp.org
 2 Sep 05:45:23 ntpdate[24846]: adjust time server 120.25.108.11 offset -0.000273 sec

之后再进行ttl设置,失效时间恢复准确。

回顾与解决

回顾整个问题,主要原因还是时间不同步。之后再出现该问题时,可以根据返回值进行判断。

[root@node-106 ~]# curl -X GET "http://10.8.65.108:2379/v2/keys/mytest/test1?recursive=false&wait=true&stream=true"
{"action":"set","node":{"key":"/mytest/test","value":"hello","expiration":"2016-09-02T09:31:18.221701998Z","ttl":17,"modifiedIndex":306840,"createdIndex":306840}}

返回的action为set的值,其中的ttl值应与自己设置的ttl值一致。如果该值与设置的ttl值不一致,就极有可能是时间不同步原因造成的。

所以解决方法是将三台机器进行时间同步,就不再出现ttl失效时间不准确的问题。

Linux性能调优工具

监控指标

  • load 特定事时间间隔内运行队列中的平均线程数
  • user time CPU执行用户进程所占用的时间
  • system time CPU在内核所花费的时间
  • nice time 系统在调整进程优先级的时候所花费的时间
  • idle time 系统空闲等待进程运行的时间
  • waiting time CPU在等待IO操作所花费的时间
  • hard irq time 系统处理硬件中断所占用的时间
  • soft irq time 系统处理软件中断所占用的时间
  • steal time 被强制等待虚拟机CPU的时间,占比较高表示当前虚拟机与该宿主其他虚拟机争用CPU频繁
  • 磁盘剩余空间 使用df和du命令查看
  • 网络traffic 使用sar命令查看 sar -n DEV 1 1
  • 磁盘IO 使用iostat命令查看 iostat -d -k
  • 内存使用 使用free命令查看
  • swap IO 使用vmstat命令查看

CPU

  • 使用top或uptime看过去1分钟、5分钟、15分钟机器的负载。按照经验,若数值小于 0.7 * CPU核数,则系统工作正常
  • 通过vmstat查看CPU上下文切换次数, 上下文切换的场景:
    • 时间片用完,CPU正常调度下一个任务
    • 被其它优先级更高的任务抢占
    • 执行任务碰到I/O阻塞,挂起当前任务,切换到下一个任务
    • 户代码主动挂起当前任务让出CPU
    • 多任务抢占资源,由于没有抢到被挂起
    • 硬件中断

Memory

  • 操作系统角度,内存关注应用进程是否足够,可以使用free –m查看内存的使用情况。
  • 通过top查看进程使用的虚拟内存VIRT和物理内存RES,根据公式VIRT = SWAP + RES可以推算出具体应用使用的交换分区(Swap)情况

I/O

  • I/O包括磁盘I/O和网络 I/O,一般情况下磁盘更容易出现I/O瓶颈。
  • 通过iostat可查看磁盘的读写情况,通过CPU的I/O wait可以看出磁盘I/O是否正常。

System Call

strace常用来跟踪进程执行时的系统调用和所接收的信,常见选项:

  • -c 统计每一系统调用的所执行的时间,次数和出错的次数等
  • -d 输出strace关于标准错误的调试信息
  • -f 跟踪由fork调用所产生的子进程
  • -ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中, pid是各进程的进程号
  • -F 尝试跟踪vfork调用.在-f时,vfork不被跟踪
  • -h 输出简要的帮助信息
  • -i 输出系统调用的入口指针
  • -q 禁止输出关于脱离的消息
  • -r 打印出相对时间关于,,每一个系统调用
  • -t 在输出中的每一行前加上时间信息
  • -tt 在输出中的每一行前加上时间信息,微秒级
  • -ttt 微秒级输出,以秒了表示时间
  • -T 显示每一调用所耗的时间
  • -v 输出所有的系统调用一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出
  • -V 输出strace的版本信息
strace -tt -f -p {pid}

Others

# 抓包
tcpdump -i eth2 -w capture.cap tcp port 9501 and dst host 172.16.1.31

zabbix3.2监控linux内存

通过free -m查看当前内存

未分类

可用内存:Available memory=free+buffers+cached,即31068=759+66+30243

已用内存:Used memory=used-buffers-cached,即1030=31339-66-30243

我这里不使用zabbix自带的监控模板,手动设置监控项。

1、手动创建一个应用集,应用集名称为Memory

2、创建监控项

  • 先创建一个Total memory

未分类

  • 再创建一个Available memory

未分类

  • 最后再创建Used memory

监控内存计算公式,用总内存减去可用内存获得准确的使用内存(注意这里双引号”,是英文的”,网上很多教程都是用的中文双引号,所以添加后会报错误)

(last("vm.memory.size[total]")-last("vm.memory.size[available]"))

未分类

3、创建图形

监控项这里我添加了,Total memory和Used memory

未分类

4、预览图形

未分类

未分类

未分类

Linux下查看进程所使用的环境变量

在Linux下直接执行env命令即可获取当前的环境变量

[xxxx ~]$$ env
HOSTNAME=iZ94lykym6iZ
TERM=linux
SHELL=/bin/bash
HISTSIZE=1000
...

进程的环境变量可以在/proc//environ查看,其中为进程id

获取进程id

使用ps获取pid

[xxxx ~]$ ps -ef | grep java
500   3345  1 0 Sep06 ?    00:48:57 /usr/bin/java -Djava.util.logging.config.file=/home/xxx/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/home/xxx/tomcat/endorsed -classpath /home/xxx/tomcat/bin/bootstrap.jar:/home/xxx/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/home/xxx/tomcat -Dcatalina.home=/home/xxx/tomcat -Djava.io.tmpdir=/home/xxx/tomcat/temp org.apache.catalina.startup.Bootstrap start

其中3345就是pid。

使用pidof获取pid

pidof命令需要知道进程的可执行的命令。

[xxxx ~]$ pidof java
24299 3345

它会列出所有执行此命令的进程id。

列出进程的环境变量

直接查看

cat /proc/<pid>/environ

美化输出查看

xargs --null --max-args=1 < /proc/<pid>/environ