CentOS 7实战Kubernetes部署

来源:http://www.open-open.com/lib/view/open1417658852542.html

1. 前言

本文作者将带领大家如何在本地部署、配置Kubernetes集群网络环境以及通过实例演示跨机器服务间的通信,主要包括如下内 容:

  • 部署环境介绍
  • Kubernetes集群逻辑架构
  • 部署Open vSwitch、Kubernetes、Etcd组件
  • 演示Kubernetes管理容器

2. 部署环境

  • VMware Workstation:10.0.3
  • VMware Workstation网络模式:NAT
  • 操作系统信息:CentOS 7 64位
  • Open vSwitch版本信息:2.3.0
  • Kubernetes版本信息:0.5.2
  • Etcd版本信息:0.4.6
  • Docker版本信息:1.3.1
  • 服务器信息:
            | Role      | Hostname   | IP Address  |
    	|:---------:|:----------:|:----------: |
    	|APIServer  |kubernetes  |192.168.230.3|
    	|Minion     | minion1    |192.168.230.4|
    	|Minion     | minion2    |192.168.230.5|

3. Kubernetes集群逻辑架构

在详细介绍部署Kubernetes集群前,先给大家展示下集群的逻辑架构。从下图可知,整个系统分为两部分,第一部分是Kubernetes APIServer,是整个系统的核心,承担集群中所有容器的管理工作;第二部分是minion,运行Container Daemon,是所有容器栖息之地,同时在minion上运行Open vSwitch程序,通过GRE Tunnel负责minion之间Pod的网络通信工作。

CentOS 7实战Kubernetes部署

4. 部署Open vSwitch、Kubernetes、Etcd组件

4.1 安装Open vSwitch及配置GRE

为了解决跨minion之间Pod的通信问题,我们在每个minion上安装Open vSwtich,并使用GRE或者VxLAN使得跨机器之间Pod能相互通信,本文使用GRE,而VxLAN通常用在需要隔离的大规模网络中。对于 Open vSwitch的具体安装步骤,可参考这篇博客,我们在这里就不再详细介绍安装步骤了。安装完Open vSwitch后,接下来便建立minion1和minion2之间的隧道。首先在minion1和minion2上建立OVS Bridge,

[root@minion1 ~]# ovs-vsctl add-br obr0

接下来建立gre,并将新建的gre0添加到obr0,在minion1上执行如下命令,

[root@minion1 ~]# ovs-vsctl add-port obr0 gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.230.5

在minion2上执行,

[root@minion2 ~]# ovs-vsctl add-port obr0 gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.230.4

至此,minion1和minion2之间的隧道已经建立。然后我们在minion1和minion2上创建Linux网桥kbr0替代 Docker默认的docker0(我们假设minion1和minion2都已安装Docker),设置minion1的kbr0的地址为 172.17.1.1/24, minion2的kbr0的地址为172.17.2.1/24,并添加obr0为kbr0的接口,以下命令在minion1和minion2上执行。

[root@minion1 ~]# brctl addbr kbr0               //创建linux bridge
[root@minion1 ~]# brctl addif kbr0 obr0          //添加obr0为kbr0的接口
[root@minion1 ~]# ip link set dev docker0 down   //设置docker0为down状态
[root@minion1 ~]# ip link del dev docker0        //删除docker0

为了使新建的kbr0在每次系统重启后任然有效,我们在/etc/sysconfig/network-scripts/目录下新建minion1的ifcfg-kbr0如下:

DEVICE=kbr0
ONBOOT=yes
BOOTPROTO=static
IPADDR=172.17.1.1
NETMASK=255.255.255.0
GATEWAY=172.17.1.0
USERCTL=no
TYPE=Bridge
IPV6INIT=no

同样在minion2上新建ifcfg-kbr0,只需修改ipaddr为172.17.2.1和gateway为172.17.2.0即可,然后 执行systemctl restart network重启系统网络服务,你能在minion1和minion2上发现kbr0都设置了相应的IP地址。为了验证我们创建的隧道是否能通信,我们 在minion1和minion2上相互ping对方kbr0的IP地址,从下面的结果发现是不通的,经查找这是因为在minion1和minion2上 缺少访问172.17.1.1和172.17.2.1的路由,因此我们需要添加路由保证彼此之间能通信。

[root@minion1 network-scripts]# ping 172.17.2.1
PING 172.17.2.1 (172.17.2.1) 56(84) bytes of data.
^C
--- 172.17.2.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1000ms

[root@minion2 ~]#  ping 172.17.1.1
PING 172.17.1.1 (172.17.1.1) 56(84) bytes of data.
^C
--- 172.17.1.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1000ms

由于通过ip route add添加的路由会在下次系统重启后失效,为此我们在/etc/sysconfig/network-scripts目录下新建一个文件route-eth0存储路由,这里需要注意的是route-eth0和ifcfg-eth0的 黑体部分必须保持一致,否则不能工作,这样添加的路由在下次重启后不会失效。为了保证两台minion的kbr0能相互通信,我们在minion1的 route-eth0里添加路由172.17.2.0/24 via 192.168.230.5 dev eno16777736,eno16777736是minion1的网卡,同样在minion2的route-eth0里添加路由 172.17.1.0/24 via 192.168.230.4 dev eno16777736。重启网络服务后再次验证,彼此kbr0的地址可以ping通,如:

[root@minion2 network-scripts]# ping 172.17.1.1
PING 172.17.1.1 (172.17.1.1) 56(84) bytes of data.
64 bytes from 172.17.1.1: icmp_seq=1 ttl=64 time=2.49 ms
64 bytes from 172.17.1.1: icmp_seq=2 ttl=64 time=0.512 ms
^C
--- 172.17.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.512/1.505/2.498/0.993 ms

到现在我们已经建立了两minion之间的隧道,而且能正确的工作。下面我们将介绍如何安装Kubernetes APIServer及kubelet、proxy等服务。

4.2 安装Kubernetes APIServer

在安装APIServer之前,我们先下载Kubernetes及Etcd,做一些准备工作。在kubernetes上的具体操作如下:

[root@kubernetes ~]# mkdir /tmp/kubernetes
[root@kubernetes ~]# cd /tmp/kubernetes/
[root@kubernetes kubernetes]# wget https://github.com/GoogleCloudPlatform/kubernetes/releases/download/v0.5.2/kubernetes.tar.gz
[root@kubernetes kubernetes]# wget https://github.com/coreos/etcd/releases/download/v0.4.6/etcd-v0.4.6-linux-amd64.tar.gz

然后解压下载的kubernetes和etcd包,并在kubernetes、minion1、minion2上创建目录/opt/kubernetes/bin,

[root@kubernetes kubernetes]# mkdir -p /opt/kubernetes/bin
[root@kubernetes kubernetes]# tar xf kubernetes.tar.gz
[root@kubernetes kubernetes]# tar xf etcd-v0.4.6-linux-amd64.tar.gz
[root@kubernetes kubernetes]# cd ~/kubernetes/server
[root@kubernetes server]# tar xf kubernetes-server-linux-amd64.tar.gz
[root@kubernetes kubernetes]# /tmp/kubernetes/kubernetes/server/kubernetes/server/bin

复制kube-apiserver,kube-controller-manager,kube-scheduler,kubecfg到 kubernetes的/opt/kubernetes/bin目录下,而kubelet,kube-proxy则复制到minion1和minion2 的/opt/kubernetes/bin,并确保都是可执行的。

[root@kubernetes amd64]# cp kube-apiserver kube-controller-manager kubecfg kube-scheduler /opt/kubernetes/bin
[root@kubernetes amd64]# scp kube-proxy kubelet root@192.168.230.4
:/opt/kubernetes/bin
[root@kubernetes amd64]# scp kube-proxy kubelet root@192.168.230.5
:/opt/kubernetes/bin

为了简单我们只部署一台etcd服务器,如果需要部署etcd的集群,请参考官方文档,在本文中将其跟Kubernetes APIServer部署同一台机器上,而且将etcd放置在/opt/kubernetes/bin下,etcdctl跟ectd同一目录。

[root@kubernetes kubernetes]# cd /tmp/kubernetes/etcd-v0.4.6-linux-amd64
[root@kubernetes etcd-v0.4.6-linux-amd64]# cp etcd etcdctl /opt/kubernetes/bin

需注意的是kubernetes和minion上/opt/kubernetes/bin目录下的文件都必须是可执行的。到目前,我们准备工作已经 差不多,现在开始给apiserver,controller-manager,scheduler,etcd配置unit文件。首先我们用如下脚本 etcd.sh配置etcd的unit文件,

#!/bin/sh

ETCD_PEER_ADDR=192.168.230.3:7001
ETCD_ADDR=192.168.230.3:4001
ETCD_DATA_DIR=/var/lib/etcd
ETCD_NAME=kubernetes

! test -d $ETCD_DATA_DIR && mkdir -p $ETCD_DATA_DIR
cat </usr/lib/systemd/system/etcd.service
[Unit]
Description=Etcd Server

[Service]
ExecStart=/opt/kubernetes/bin/etcd \\
    -peer-addr=$ETCD_PEER_ADDR \\
    -addr=$ETCD_ADDR \\
    -data-dir=$ETCD_DATA_DIR \\
    -name=$ETCD_NAME \\
    -bind-addr=0.0.0.0

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable etcd
systemctl start etcd

对剩下的apiserver,controller-manager,scheduler的unit文件配置的脚本,可以在github 上GetStartingKubernetes找到,在此就不一一列举。运行相应的脚本后,在APIServer上etcd, apiserver, controller-manager, scheduler服务就能正常运行。

4.3 安装Kubernetes Kubelet及Proxy

根据Kubernetes的设计架构,需要在minion上部署docker, kubelet, kube-proxy,在4.2节部署APIServer时,我们已经将kubelet和kube-proxy已经分发到两minion上,所以只需配置docker,kubelet,proxy的unit文件,然后启动服务就即可,具体配置见GetStartingKubernetes

5. 演示Kubernetes管理容器

为了方便,我们使用Kubernetes提供的例子Guestbook来演示Kubernetes管理跨机器运行的容器,下面我们根据Guestbook的步骤创建容器及服务。在下面的过程中如果是第一次操作,可能会有一定的等待时间,状态处于pending,这是因为第一次下载images需要一段时间。

5.1 创建redis-master Pod和redis-master服务

[root@kubernetes ~]# cd /tmp/kubernetes/kubernetes/examples/guestbook
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c redis-master.json create pods
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c redis-master-service.json create services

完成上面的操作后,我们可以看到如下redis-master Pod被调度到192.168.230.4。

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list pods
Name                                   Image(s)                   Host                Labels                                       Status
----------                             ----------                 ----------          ----------                                   ----------
redis-master                           dockerfile/redis           192.168.230.4/      name=redis-master                            Running

但除了发现redis-master的服务之外,还有两个Kubernetes系统默认的服务kubernetes-ro和kubernetes。 而且我们可以看到每个服务都有一个服务IP及相应的端口,对于服务IP,是一个虚拟地址,根据apiserver的portal_net选项设置的 CIDR表示的IP地址段来选取,在我们的集群中设置为10.10.10.0/24。为此每新创建一个服务,apiserver都会在这个地址段中随机选 择一个IP作为该服务的IP地址,而端口是事先确定的。对redis-master服务,其服务地址为10.10.10.206,端口为6379。

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list services
Name                Labels              Selector                                  IP                  Port
----------          ----------          ----------                                ----------          ----------
kubernetes-ro                           component=apiserver,provider=kubernetes   10.10.10.207        80
redis-master        name=redis-master   name=redis-master                         10.10.10.206        6379
kubernetes                              component=apiserver,provider=kubernetes   10.10.10.161        443

5.2 创建redis-slave Pod和redis-slave服务

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c redis-slave-controller.json create replicationControllers
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c redis-slave-service.json create services

然后通过list命令可知新建的redis-slave Pod根据调度算法调度到两台minion上,服务IP为10.10.10.92,端口为6379

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list pods
Name                                   Image(s)                   Host                Labels                                       Status
----------                             ----------                 ----------          ----------                                   ----------
redis-master                           dockerfile/redis           192.168.230.4/      name=redis-master                            Running
8c0ddbda-728c-11e4-8233-000c297db206   brendanburns/redis-slave   192.168.230.5/      name=redisslave,uses=redis-master            Running
8c0e1430-728c-11e4-8233-000c297db206   brendanburns/redis-slave   192.168.230.4/      name=redisslave,uses=redis-master            Running

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list services
Name                Labels              Selector                                  IP                  Port
----------          ----------          ----------                                ----------          ----------
redisslave          name=redisslave     name=redisslave                           10.10.10.92         6379
kubernetes                              component=apiserver,provider=kubernetes   10.10.10.161        443
kubernetes-ro                           component=apiserver,provider=kubernetes   10.10.10.207        80
redis-master        name=redis-master   name=redis-master                         10.10.10.206        6379

5.3 创建Frontend Pod和Frontend服务

在创建之前修改frontend-controller.json的Replicas数量为2,这是因为我们的集群中只有2台minion,如果按 照frontend-controller.json的Replicas默认值3,那会导致有2个Pod会调度到同一台minion上,产生端口冲突,有 一个Pod会一直处于pending状态,不能被调度。

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c frontend-controller.json create replicationControllers
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c frontend-service.json create services

通过查看可知Frontend Pod也被调度到两台minion,服务IP为10.10.10.220,端口是80。

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list pods
Name                                   Image(s)                   Host                Labels                                       Status
----------                             ----------                 ----------          ----------                                   ----------
redis-master                           dockerfile/redis           192.168.230.4/      name=redis-master                            Running
8c0ddbda-728c-11e4-8233-000c297db206   brendanburns/redis-slave   192.168.230.5/      name=redisslave,uses=redis-master            Running
8c0e1430-728c-11e4-8233-000c297db206   brendanburns/redis-slave   192.168.230.4/      name=redisslave,uses=redis-master            Running
a880b119-7295-11e4-8233-000c297db206   brendanburns/php-redis     192.168.230.4/      name=frontend,uses=redisslave,redis-master   Running
a881674d-7295-11e4-8233-000c297db206   brendanburns/php-redis     192.168.230.5/      name=frontend,uses=redisslave,redis-master   Running

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list services
Name                Labels              Selector                                  IP                  Port
----------          ----------          ----------                                ----------          ----------
kubernetes-ro                           component=apiserver,provider=kubernetes   10.10.10.207        80
redis-master        name=redis-master   name=redis-master                         10.10.10.206        6379
redisslave          name=redisslave     name=redisslave                           10.10.10.92         6379
frontend            name=frontend       name=frontend                             10.10.10.220        80
kubernetes                              component=apiserver,provider=kubernetes   10.10.10.161        443

除此之外,你可以删除Pod、Service及更新ReplicationController的Replicas数量等操作,如删除Frontend服务:

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 delete services/frontend
Status
----------
Success

还可以更新ReplicationController的Replicas的数量,下面是更新Replicas之前ReplicationController的信息。

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list replicationControllers
Name                   Image(s)                   Selector            Replicas
----------             ----------                 ----------          ----------
redisSlaveController   brendanburns/redis-slave   name=redisslave     2
frontendController     brendanburns/php-redis     name=frontend       2

现在我们想把frontendController的Replicas更新为1,则这行如下命令,然后再通过上面的命令查看frontendController信息,发现Replicas已变为1。

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 resize frontendController 1

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list replicationControllers
Name                   Image(s)                   Selector            Replicas
----------             ----------                 ----------          ----------
redisSlaveController   brendanburns/redis-slave   name=redisslave     2
frontendController     brendanburns/php-redis     name=frontend       1

5.4 演示跨机器服务通信

完成上面的操作后,我们来看当前Kubernetes集群中运行着的Pod信息。

[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list pods
Name                                   Image(s)                   Host                Labels                                       Status
----------                             ----------                 ----------          ----------                                   ----------
a881674d-7295-11e4-8233-000c297db206   brendanburns/php-redis     192.168.230.5/      name=frontend,uses=redisslave,redis-master   Running
redis-master                           dockerfile/redis           192.168.230.4/      name=redis-master                            Running
8c0ddbda-728c-11e4-8233-000c297db206   brendanburns/redis-slave   192.168.230.5/      name=redisslave,uses=redis-master            Running
8c0e1430-728c-11e4-8233-000c297db206   brendanburns/redis-slave   192.168.230.4/      name=redisslave,uses=redis-master            Running

通过上面的结果可知当前提供前端服务的PHP和提供数据存储的后端服务Redis master的Pod分别运行在192.168.230.5和192.168.230.4上,即容器运行在不同主机上,还有Redis slave也运行在两台不同的主机上,它会从Redis master同步前端写入Redis master的数据。下面我们从两方面验证Kubernetes能提供跨机器间容器的通信:

  • 在浏览器打开http://${IPAddress}:8000,IPAddress为PHP容器运行的minion的IP地址,其暴漏的端口为8000,这里IP_Address为192.168.230.5。打开浏览器会显示如下信息:CentOS 7实战Kubernetes部署你可以输入信息并提交,如”Hello Kubernetes”、”Container”,然后Submit按钮下方会显示你输入的信息。CentOS 7实战Kubernetes部署

    由于前端PHP容器和后端Redis master容器分别在两台minion上,因此PHP在访问Redis master服务时一定得跨机器通信,可见Kubernetes的实现方式避免了用link只能在同一主机上实现容器间通信的缺陷,对于 Kubernetes跨机器通信的实现方法,以后我会详细介绍。

  • 从上面的结果,可得知已经实现了跨机器的通信,现在我们从后端数据层验证不同机器容器间的通信。根据上面的输出结果发现Redis slave和Redis master分别调度到两台不同的minion上,在192.168.230.4主机上执行docker exec -ti c41711cc8971 /bin/sh,c41711cc8971是Redis master的容器ID,进入容器后通过redis-cli命令查看从浏览器输入的信息如下:CentOS 7实战Kubernetes部署如果我们在192.168.230.5上运行的Redis slave容器里查到跟Redis master容器里相同的信息,那说明Redis master和Redis slave之间的数据同步正常工作,下面是从192.168.230.5上运行的Redis slave容器查询到的信息:CentOS 7实战Kubernetes部署

    由此可见Redis master和Redis slave之间数据同步正常,OVS GRE隧道技术使得跨机器间容器正常通信。

6. 结论

本文主要介绍如何在本地环境部署Kubernetes集群和演示如何通过Kubernetes管理集群中运行的容器,并通过OVS管理集群不同 minion的Pod之间的网络通信。接下来会对Kubernetes各个组件源码进行详细分析,阐述Kubernetes的工作原理。

五分钟理解一致性哈希算法(consistent hashing)

    一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简 单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用。
    一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义:
1、平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。
2、单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。
3、分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。
4、负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同 的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。
    在分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操作是分布式集群管理最基本的功能。如果采用常用的hash(object)%N算法,那么在有机器添加或者删除后,很多原有的数据就无法找到了,这样严重的违反了单调性原则。接下来主要讲解一下一致性哈希算法是如何设计的:
环形Hash空间
按照常用的hash算法来将对应的key哈希到一个具有2^32次方个桶的空间中,即0~(2^32)-1的数字空间中。现在我们可以将这些数字头尾相连,想象成一个闭合的环形。如下图
                                                                         
把数据通过一定的hash算法处理后映射到环上
现在我们将object1、object2、object3、object4四个对象通过特定的Hash函数计算出对应的key值,然后散列到Hash环上。如下图:
    Hash(object1) = key1;
    Hash(object2) = key2;
    Hash(object3) = key3;
    Hash(object4) = key4;
                                                           
将机器通过hash算法映射到环上
在采用一致性哈希算法的分布式集群中将新的机器加入,其原理是通过使用与对象存储一样的Hash算法将机器也映射到环中(一般情况下对机器的hash计算是采用机器的IP或者机器唯一的别名作为输入值),然后以顺时针的方向计算,将所有对象存储到离自己最近的机器中。
假设现在有NODE1,NODE2,NODE3三台机器,通过Hash算法得到对应的KEY值,映射到环中,其示意图如下:
Hash(NODE1) = KEY1;
Hash(NODE2) = KEY2;
Hash(NODE3) = KEY3;
                                                             
通过上图可以看出对象与机器处于同一哈希空间中,这样按顺时针转动object1存储到了NODE1中,object3存储到了NODE2中,object2、object4存储到了NODE3中。在这样的部署环境中,hash环是不会变更的,因此,通过算出对象的hash值就能快速的定位到对应的机器中,这样就能找到对象真正的存储位置了。
机器的删除与添加
普通hash求余算法最为不妥的地方就是在有机器的添加或者删除之后会照成大量的对象存储位置失效,这样就大大的不满足单调性了。下面来分析一下一致性哈希算法是如何处理的。
1. 节点(机器)的删除
    以上面的分布为例,如果NODE2出现故障被删除了,那么按照顺时针迁移的方法,object3将会被迁移到NODE3中,这样仅仅是object3的映射位置发生了变化,其它的对象没有任何的改动。如下图:
                                                              
2. 节点(机器)的添加
    如果往集群中添加一个新的节点NODE4,通过对应的哈希算法得到KEY4,并映射到环中,如下图:
                                                              
    通过按顺时针迁移的规则,那么object2被迁移到了NODE4中,其它对象还保持这原有的存储位置。通过对节点的添加和删除的分析,一致性哈希算法在保持了单调性的同时,还是数据的迁移达到了最小,这样的算法对分布式集群来说是非常合适的,避免了大量数据迁移,减小了服务器的的压力。
平衡性
根据上面的图解分析,一致性哈希算法满足了单调性和负载均衡的特性以及一般hash算法的分散性,但这还并不能当做其被广泛应用的原由,因为还缺少了平衡性。下面将分析一致性哈希算法是如何满足平衡性的。hash算法是不保证平衡的,如上面只部署了NODE1和NODE3的情况(NODE2被删除的图),object1存储到了NODE1中,而object2、object3、object4都存储到了NODE3中,这样就照成了非常不平衡的状态。在一致性哈希算法中,为了尽可能的满足平衡性,其引入了虚拟节点。
    ——“虚拟节点”( virtual node )是实际节点(机器)在 hash 空间的复制品( replica ),一实际个节点(机器)对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在 hash 空间中以hash值排列。
以上面只部署了NODE1和NODE3的情况(NODE2被删除的图)为例,之前的对象在机器上的分布很不均衡,现在我们以2个副本(复制个数)为例,这样整个hash环中就存在了4个虚拟节点,最后对象映射的关系图如下:
                                                                 
根据上图可知对象的映射关系:object1->NODE1-1,object2->NODE1-2,object3->NODE3-2,object4->NODE3-1。通过虚拟节点的引入,对象的分布就比较均衡了。那么在实际操作中,正真的对象查询是如何工作的呢?对象从hash到虚拟节点到实际节点的转换如下图:
                                         
“虚拟节点”的hash计算可以采用对应节点的IP地址加数字后缀的方式。例如假设NODE1的IP地址为192.168.1.100。引入“虚拟节点”前,计算 cache A 的 hash 值:
Hash(“192.168.1.100”);
引入“虚拟节点”后,计算“虚拟节”点NODE1-1和NODE1-2的hash值:
Hash(“192.168.1.100#1”); // NODE1-1
Hash(“192.168.1.100#2”); // NODE1-2

nginx 负载均衡5种配置方式

nginx 负载均衡5种配置方式

1、轮询(默认)

每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

2、weight
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
例如:
upstream bakend {
server 192.168.0.14 weight=10;
server 192.168.0.15 weight=10;
}

3、ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
例如:
upstream bakend {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}

4、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backend {
server server1;
server server2;
fair;
}

5、url_hash(第三方)

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。

例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法

upstream backend {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}

tips:

upstream bakend{#定义负载均衡设备的Ip及设备状态
ip_hash;
server 127.0.0.1:9090 down;
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:6060;
server 127.0.0.1:7070 backup;
}
在需要使用负载均衡的server中增加
proxy_pass http://bakend/;

每个设备的状态设置为:
1.down 表示单前的server暂时不参与负载
2.weight 默认为1.weight越大,负载的权重就越大。
3.max_fails :允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream 模块定义的错误
4.fail_timeout:max_fails次失败后,暂停的时间。
5.backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。

nginx支持同时设置多组的负载均衡,用来给不用的server来使用。

client_body_in_file_only 设置为On 可以讲client post过来的数据记录到文件中用来做debug
client_body_temp_path 设置记录文件的目录 可以设置最多3层目录

location 对URL进行匹配.可以进行重定向或者进行新的代理 负载均衡

0

nginx的五种负载算法模式

nginx 负载均衡5种配置方式

1、轮询(默认)

每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

2、weight
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
例如:
upstream bakend {
server 192.168.0.14 weight=10;
server 192.168.0.15 weight=10;
}

3、ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
例如:
upstream bakend {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}

4、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backend {
server server1;
server server2;
fair;
}

5、url_hash(第三方)

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。

例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法

upstream backend {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}

tips:

upstream bakend{#定义负载均衡设备的Ip及设备状态
ip_hash;
server 127.0.0.1:9090 down;
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:6060;
server 127.0.0.1:7070 backup;
}
在需要使用负载均衡的server中增加
proxy_pass http://bakend/;

每个设备的状态设置为:
1.down 表示单前的server暂时不参与负载
2.weight 默认为1.weight越大,负载的权重就越大。
3.max_fails :允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream 模块定义的错误
4.fail_timeout:max_fails次失败后,暂停的时间。
5.backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。

nginx支持同时设置多组的负载均衡,用来给不用的server来使用。

client_body_in_file_only 设置为On 可以讲client post过来的数据记录到文件中用来做debug
client_body_temp_path 设置记录文件的目录 可以设置最多3层目录

location 对URL进行匹配.可以进行重定向或者进行新的代理 负载均衡

简述Socket,IP,TCP三次握手,HTTP协议

来源:http://blog.csdn.net/u014649598/article/details/32308033?utm_source=tuicool&utm_medium=referral

我在这里简述Socket,IP,TCP三次握手,HTTP协议(有助于理解、记忆和学习面试时方便回答)

1、socket原理

Socket支持网上点对点的通信
服务的一种技术,服务端端实现监听连接,客户端实现发送连接请求,建立连接后进行发送和接收数据。
服务器端建立一个serversocket,设置好本机的ip和监听的端口与socket进行绑定,并开始监听连接请求,当接收到连接请求后,发送确认,同客户端建立连接,开始与客户端进行通信。
客户端建立一个socket,设置好服务器端的IP和提供服务的端口,发出连接请求,接收到服务器的确认后,尽力连接,开始与服务器进行通信。
服务器端和客户端的连接及它们之间的数据传送均采用同步方式。
2、IP 
IP是一个无连接的协议,主要就是负责在主机间寻址并为数据包设定路由,在交换数据前它并不建立会话。因为它不保证正确传递,另一方面,数据在被收到时,IP不需要收到确认,所以它是不可靠的
3、TCP
TCP是一种可靠的面向连接的传送服务。它在传送数据时是分段进行的,主机交换数据必须建立一个会话。它用比特流通信,即数据被作为无结构的字节流。
通过每个TCP传输的字段指定顺序号,以获得可靠性。如果一个分段被分解成几个小段,接收主机会知道是否所有小段都已收到。通过发送应答,用以确认别的主机收到了数据。对于发送的每一个小段,接收主机必须在一个指定的时间返回一个确认。如果发送者未收到确认,数据会被重新发送;如果收到的数据包损坏,接收主机会舍弃它,因为确认未被发送,发送者会重新发送分段。

端口
SOCKETS实用程序使用一个协议端口号来标明自己应用的唯一性。端口可以使用0到65536之间的任何数字。在服务请求时,操作系统动态地为客户端的应用程序分配端口号。

套接字
套接字在要领上与文件句柄类似,因为其功能是作为网络通信的终结点。一个应用程序通过定义三部分来产生一个套接字:主机IP地址、服务类型(面向连接的服务是TCP,无连接服务是UDP)、应用程序所用的端口。

TCP端口
TCP端口为信息的传送提供定地点,端口号小于256的定义为常用端口。

TCP的三次握手
TCP对话通过三次握手来初始化。三次握手的目的是使数据段的发送和接收同步;告诉其它主机其一次可接收的数据量,并建立虚连接。
我们来看看这三次握手的简单过程:
(1)初始化主机通过一个同步标志置位的数据段发出会话请求。
(2)接收主机通过发回具有以下项目的数据段表示回复:同步标志置位、即将发送的数据段的起始字节的顺序号、应答并带有将收到的下一个数据段的字节顺序号。
(3)请求主机再回送一个数据段,并带有确认顺序号和确认号。

位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)

Sequence number(顺序号码) Acknowledge number(确认号码)

第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;

第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包

第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。

完成三次握手,主机A与主机B开始传送数据。
4、HTTP协议
HTTP协议的主要特点可概括如下:
1.支持客户/服务器模式。
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

LVS+Keepalived+Squid+Nginx+MySQL主从 高性能集群架构配置

来源:http://www.linuxidc.com/Linux/2012-07/65547.htm

LVS+Keepalived+Squid+Nginx+MySQL主从 高性能集群架构配置:

不足之处,请指出~~~~~~~~~

先进行优化:

vi /etc/sysctl.conf   # 编辑sysctl.conf文件添加以下内容
  1. net.ipv4.tcp_rmem = 4096 87380 4194304
  2. net.ipv4.tcp_wmem = 4096 65536 4194304
  3. net.core.wmem_default = 8388608
  4. net.core.rmem_default = 8388608
  5. net.core.rmem_max = 16777216
  6. net.core.wmem_max = 16777216
  7. net.core.netdev_max_backlog = 262144
  8. net.core.somaxconn = 262144
  9. net.ipv4.tcp_max_orphans = 3276800
  10. net.ipv4.tcp_max_syn_backlog = 8192
  11. net.ipv4.tcp_max_tw_buckets = 5000
  12. net.ipv4.tcp_timestamps = 0
  13. net.ipv4.tcp_synack_retries = 1
  14. net.ipv4.tcp_syn_retries = 1
  15. net.ipv4.tcp_tw_recycle = 1
  16. net.ipv4.tcp_tw_reuse = 1
  17. net.ipv4.tcp_mem = 786432 1048576 1572864
  18. net.ipv4.tcp_fin_timeout = 30
  19. net.ipv4.tcp_keepalive_time = 1200
  20. net.ipv4.ip_local_port_range = 1024 65000

以上配置说明:
net.ipv4.tcp_rmem = 4096 87380 4194304:TCP读buffer,可参考的优化值: 32768 436600 873200

net.ipv4.tcp_wmem = 4096 65536 4194304:TCP写buffer,可参考的优化值: 8192 436600 873200

net.core.wmem_default:表示发送套接字缓冲区大小的缺省值(以字节为单位)

net.core.rmem_default:表示接收套接字缓冲区大小的缺省值(以字节为单位)

net.core.rmem_max :表示接收套接字缓冲区大小的最大值(以字节为单位)

net.core.wmem_max:表示发送套接字缓冲区大小的最大值(以字节为单位)

net.core.netdev_max_backlog = 262144:每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。

net.core.somaxconn = 262144:web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。

net.ipv4.tcp_max_orphans = 3276800:系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。

net.ipv4.tcp_max_syn_backlog = 8192:表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。

net.ipv4.tcp_max_tw_buckets = 5000:表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。减少它的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。

net.ipv4.tcp_timestamps = 0:时间戳可以避免序列号的卷绕。一个1Gbps的链路肯定会遇到以前用过的序列号,时间戳能够让内核接受这种“异常”的数据包,这里需要将其关掉。
net.ipv4.tcp_tw_recycle = 1:表示开启TCP连接中TIME-WAIT sockets的快速回收。

net.ipv4.tcp_tw_reuse = 1:表示开启重用,允许将TIME-WAIT sockets重新用于新的TCP连接。

net.ipv4.tcp_mem = 786432 1048576 1572864:同样有3个值,net.ipv4.tcp_mem[0]:低于此值,TCP没有内存压力;net.ipv4.tcp_mem[1]:在此值下,进入内存压力阶段;net.ipv4.tcp_mem[2]:高于此值,TCP拒绝分配socket。可根据物理内存大小进行调整,如果内存足够大的话,可适当往上调。建议94500000 915000000 927000000。

net.ipv4.tcp_fin_timeout = 30:表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。

net.ipv4.tcp_keepalive_time = 1200:表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。

net.ipv4.ip_local_port_range = 1024 65000:表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为1024到65000。

 

使配置立即生效:
/sbin/sysctl -p

 LVS + keepalived 配置~~~~~

master的配置

  1. mkdir /usr/local/src/lvs
  2. cd /usr/local/src/lvs
  3. wget http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.24.tar.gz
  4. wget http://www.keepalived.org/software/keepalived-1.1.15.tar.gz
  5. lsmod |grep ip_vs
  6. uname -r
  7. ln -s /usr/src/kernels/$(uname -r)/usr/src/linux
  8. #ln -s /usr/src/kernels/2.6.* /usr/src/linux
  9. tar zxvf ipvsadm-1.24.tar.gz
  10. cd ipvsadm-1.24
  11. make && make install
  12. tar zxvf keepalived-1.1.15.tar.gz
  13. cd keepalived-1.1.15
  14. ./configure&& make && make install
  15. cp /usr/local/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
  16. cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig/
  17. mkdir /etc/keepalived
  18. cp /usr/local/etc/keepalived/keepalived.conf /etc/keepalived/
  19. cp /usr/local/sbin/keepalived /usr/sbin/
  20. #you can service keepalived start|stop
  21. cat >> /usr/local/etc/keepalived/keepalived.conf <<EOF
  22. ! Configuration File for keepalived
  23. global_defs {
  24.    notification_email {
  25.         rfyiamcool@163.com
  26.    }
  27.    notification_email_from Alexandre.Cassen@firewall.loc
  28.    smtp_server 127.0.0.1
  29.    router_id LVS_DEVEL
  30. }
  31. vrrp_instance VI_1 {
  32.     state MASTER    #  BACKUP
  33.     interface eth0
  34.     virtual_router_id 51
  35.     priority 100    #  另一端 90
  36.     advert_int 1
  37.     authentication {
  38.         auth_type PASS
  39.         auth_pass 1111
  40.     }
  41.     virtual_ipaddress {
  42.         10.10.10.88
  43.     }
  44. }
  45. virtual_server 10.10.10.88 80 {
  46.     delay_loop 6
  47.     lb_algo rr
  48.     lb_kind DR
  49.     persistence_timeout 50
  50.     protocol TCP
  51.     real_server 10.10.10.21 80 {
  52.         weight 3
  53.         TCP_CHECK {
  54.         connect_timeout 10
  55.         nb_get_retry 3
  56.         delay_before_retry 3
  57.         connect_port 80
  58.         }
  59.     }
  60.     real_server 10.10.10.22 80 {
  61.         weight 3
  62.         TCP_CHECK {
  63.         connect_timeout 10
  64.         nb_get_retry 3
  65.         delay_before_retry 3
  66.         connect_port 80
  67.         }
  68. real_server 10.10.10.23 80 {
  69.         weight 3
  70.         TCP_CHECK {
  71.         connect_timeout 10
  72.         nb_get_retry 3
  73.         delay_before_retry 3
  74.         connect_port 80
  75.         }
  76.     }
  77. }
  78. EOF
  79. service keepalived start

backup主机的配置

  1. mkdir /usr/local/src/lvs
  2. cd /usr/local/src/lvs
  3. wget http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.24.tar.gz
  4. wget http://www.keepalived.org/software/keepalived-1.1.15.tar.gz
  5. lsmod |grep ip_vs
  6. uname -r
  7. ln -s /usr/src/kernels/$(uname -r)/usr/src/linux
  8. #ln -s /usr/src/kernels/2.6.* /usr/src/linux
  9. tar zxvf ipvsadm-1.24.tar.gz
  10. cd ipvsadm-1.24
  11. make && make install
  12. tar zxvf keepalived-1.1.15.tar.gz
  13. cd keepalived-1.1.15
  14. ./configure&& make && make install
  15. cp /usr/local/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
  16. cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig/
  17. mkdir /etc/keepalived
  18. cp /usr/local/etc/keepalived/keepalived.conf /etc/keepalived/
  19. cp /usr/local/sbin/keepalived /usr/sbin/
  20. #you can service keepalived start|stop
  21. cat >> /usr/local/etc/keepalived/keepalived.conf <<EOF
  22. ! Configuration File for keepalived
  23. global_defs {
  24.    notification_email {
  25.         rfyiamcool@163.com
  26.    }
  27.    notification_email_from Alexandre.Cassen@firewall.loc
  28.    smtp_server 127.0.0.1
  29.    router_id LVS_DEVEL
  30. }
  31. vrrp_instance VI_1 {
  32.     state BACKUP
  33.     interface eth0
  34.     virtual_router_id 51
  35.     priority 90
  36.     advert_int 1
  37.     authentication {
  38.         auth_type PASS
  39.         auth_pass 1111
  40.     }
  41.     virtual_ipaddress {
  42.         10.10.10.88
  43.     }
  44. }
  45. virtual_server 10.10.10.88 80 {
  46.     delay_loop 6
  47.     lb_algo rr
  48.     lb_kind DR
  49.     persistence_timeout 50
  50.     protocol TCP
  51.     real_server 10.10.10.21 80 {
  52.         weight 3
  53.         TCP_CHECK {
  54.         connect_timeout 10
  55.         nb_get_retry 3
  56.         delay_before_retry 3
  57.         connect_port 80
  58.         }
  59.     }
  60.     real_server 10.10.10.22 80 {
  61.         weight 3
  62.         TCP_CHECK {
  63.         connect_timeout 10
  64.         nb_get_retry 3
  65.         delay_before_retry 3
  66.         connect_port 80
  67.         }
  68.    real_server 10.10.10.23 80 {
  69.         weight 3
  70.         TCP_CHECK {
  71.         connect_timeout 10
  72.         nb_get_retry 3
  73.         delay_before_retry 3
  74.         connect_port 80
  75.         }
  76.     }
  77. }
  78. EOF
  79. service keepalived start
  80. Squid缓存反向代理配置
    1. #!/bin/bash
    2. wget  http://www.squid-cache.org/Versions/v2/2.6/squid-2.6.STABLE6.tar.bz2
    3. tar jxvf squid-2.6.STABLE6.tar.bz2
    4. ./configure –prefix=/usr/local/squid \
    5. –enable-async-io=320 \
    6. –enable-storeio=“aufs,diskd,ufs” \
    7. –enable-useragent-log \
    8. –enable-referer-log \
    9. –enable-kill-parent-hack \
    10. –enable-forward-log \
    11. –enable-snmp \
    12. –enable-cache-digests \
    13. –enable-default-err-language=Simplify_Chinese \
    14. –enable-epoll \
    15. –enable-removal-policies=“heap,lru” \
    16. –enable-large-cache-files \
    17. –disable-internal-dns \
    18. –enable-x-accelerator-vary \
    19. –enable-follow-x-forwarded-for \
    20. –disable-ident-lookups \
    21. –with-large-files \
    22. –with-filedescriptors=65536
    23. cat >> /usr/local/squid/etc/squid.conf <<EOF
    24. visible_hostname cache1.taobao.com
    25. http_port 192.168.1.44:80 vhost vport
    26. icp_port 0
    27. cache_mem 512 MB
    28. cache_swap_low 90
    29. cache_swap_high 95
    30. maximum_object_size 20000 KB
    31. maximum_object_size_in_memory 4096 KB
    32. cache_dir ufs /tmp1 3000 32 256
    33. cache_store_log none
    34. emulate_httpd_log on
    35. efresh_pattern ^ftp:           1440    20%     10080
    36. refresh_pattern ^gopher:        1440    0%      1440
    37. refresh_pattern .               0       20%     4320
    38. negative_ttl 5 minutes
    39. positive_dns_ttl 6 hours
    40. negative_dns_ttl 1 minute
    41. connect_timeout 1 minute
    42. read_timeout 15 minutes
    43. request_timeout 5 minutes
    44. client_lifetime 1 day
    45. half_closed_clients on
    46. maximum_single_addr_tries 1
    47. uri_whitespace strip
    48. ie_refresh off
    49. logformat combined %>a %ui %un [%tl] “%rm %ru HTTP/%rv” %Hs %<st “%{Referer}>h” “%{User-Agent}>h” %Ss:%Sh
    50. pid_filename /var/log/squid/squid.pid
    51. cache_log /var/log/squid/cache.log
    52. access_log /var/log/squid/access.log combined
    53. acl all src 0.0.0.0/0.0.0.0
    54. acl QUERY urlpath_regex cgi-bin .php .cgi .avi .wmv .rm .ram .mpg .mpeg .zip .exe
    55. cache deny QUERY
    56. acl picurl url_regex -i \.bmp$ \.png$ \.jpg$ \.gif$ \.jpeg$
    57. acl mystie1 referer_regex -i aaa
    58. http_access allow mystie1 picurl
    59. acl mystie2 referer_regex -i bbb
    60. http_access allow mystie2 picurl
    61. acl nullref referer_regex -i ^$
    62. http_access allow nullref
    63. acl hasref referer_regex -i .+
    64. http_access deny hasref picurl
    65. cache_peer 10.10.10.56 parent 80 0 no-query originserver name=web1 round-robin
    66. cache_peer 10.10.10.57 parent 80 0 no-query originserver name=web2 round-robin
    67. #请自己改域名 比如123.com www.123.com *.123.com
    68. cache_peer_domain all .123.com
    69. cache_effective_user nobody
    70. cache_effective_group nobody
    71. acl localhost src 127.0.0.1
    72. acl my_other_proxy srcdomain .a.com
    73. follow_x_forwarded_for allow localhost
    74. follow_x_forwarded_for allow all   #允许转发 head ip 头
    75. acl_uses_indirect_client on     #只有2.6才有这这个个参数
    76. delay_pool_uses_indirect_client on  #只有2.6才有这这个个参数
    77. log_uses_indirect_client on    # 只有2.6才有这这个个参数
    78. #refresh_pattern ^ftp: 60 20% 10080
    79. #refresh_pattern ^gopher: 60 0% 1440
    80. #refresh_pattern ^gopher: 60 0% 1440
    81. #refresh_pattern . 0 20% 1440
    82. refresh_pattern -i \.css$       360     50%     2880
    83. refresh_pattern -i \.js$        1440    50%     2880
    84. refresh_pattern -i \.html$      720     50%     1440
    85. refresh_pattern -i \.jpg$       1440    90%     2880
    86. refresh_pattern -i \.gif$       1440    90%     2880
    87. refresh_pattern -i \.swf$       1440    90%     2880
    88. refresh_pattern -i \.jpg$       1440    50%     2880
    89. refresh_pattern -i \.png$       1440    50%     2880
    90. refresh_pattern -i \.bmp$       1440    50%     2880
    91. refresh_pattern -i \.doc$       1440    50%     2880
    92. refresh_pattern -i \.ppt$       1440    50%     2880
    93. refresh_pattern -i \.xls$       1440    50%     2880
    94. refresh_pattern -i \.pdf$       1440    50%     2880
    95. refresh_pattern -i \.rar$       1440    50%     2880
    96. refresh_pattern -i \.zip$       1440    50%     2880
    97. refresh_pattern -i \.txt$       1440    50%     2880
    98. EOF
    99. #建立缓存和日志目录,并改变权限使squid能写入
    100. mkdir /tmp1
    101. mkdir /var/log/squid
    102. chown -R nobody:nobody /tmp1
    103. chmod 666 /tmp1
    104. chown -R nobody:nobody /var/log/squid
    105. #首次运行squid要先建立缓存
    106. /usr/local/squid/sbin/squid -z
    107. #启动squid
    108. echo “65535” > /proc/sys/fs/file-max
    109. ulimit -HSn 65535
    110. /usr/local/squid/sbin/squid
    111. *取得squid运行状态信息: squidclient -p 80 mgr:info

      *取得squid内存使用情况: squidclient -p 80 mgr:mem

      *取得squid已经缓存的列表: squidclient -p 80 mgr:objects. use it carefully,it may crash

      *取得squid的磁盘使用情况: squidclient -p 80 mgr:diskd

      缓存的清理脚本

      格式:

      qingli.sh      www.linuxidc.com

      qingli.sh      jpg

      qingli.sh       linuxidc.com 123  bbb  jpg

      1. #!/bin/sh
      2. squidcache_path=“/squidcache”
      3. squidclient_path=“/home/local/squid/bin/squidclient”
      4. #grep -a -r $1 $squidcache_path/* | grep “http:” | awk -F ‘http:’ ‘{print “http:”$2;}’ | awk -F\’ ‘{print $1}’ > cache.txt
      5. if [[ “$1” == “swf” || “$1” == “png” || “$1” == “jpg” || “$1” == “ico” || “$1” == “gif” || “$1” == “css” || “$1” == “js” || “$1” == “html” || “$1” == “shtml” || “$1” == “htm”   ]]; then
      6. grep -a -r .$1 $squidcache_path/* | strings | grep “http:” | awk -F ‘http:’ ‘{print “http:”$2;}’ | awk -F\’ ‘{print $1}’ | grep “$1$” | uniq > cache.txt
      7. else
      8. grep -a -r $1 $squidcache_path/* | strings | grep “http:” |grep $2$ |grep $3$|grep $4$|grep $5$ |grep $6$| awk -F ‘http:’ ‘{print “http:”$2;}’ | awk -F\’ ‘{print $1}’ | uniq > cache.txt
      9. fi
      10. sed -i “s/\”;$//g” cache.txt
      11. cat cache.txt | while read LINE
      12. do
      13. $squidclient_path -p 80 -m PURGE $LINE
      14. done

      下面是3.1的安装,针对需要3.1部分模块的朋友,但是不推荐用3.1

       

      1. tar -zxvf squid-3.1.20-20120610-r10455.tar.gz
      2. cd squid-3.1.20-20120610-r10455
      3. ./configure –prefix=/usr/local/squid –enable-async-io=100 –disable-delay-pools –disable-mem-gen-trace –disable-useragent-log –enable-kill-parent-hack –disable-arp-acl –enable-epoll –disable-ident-lookups –enable-snmp –enable-large-cache-files –with-large-files
      4. make && make install
      5. groupadd squid   #创建squid用户组
      6. useradd -g squid -s /sbin/nologin squid   #创建squid用户,并加入到squid组里,不允许登录系统
      7. chown -R squid /usr/local/squid/   #修改squid的安装目录所属用户为squid用户
      8. mkdir -p /var/cache     #创建squid的第一个缓存目录
      9. mkdir -p /var/squid    #创建squid的第二个缓存目录
      10. chown squid.squid -R /var/cache /var/squid  #设置目录所有者
      11. chmod -R 777 /var/cache /var/squid    #设置目录权限
      12. mv /usr/local/squid/etc/squid.conf /usr/local/squid/etc/squid.conf.bak
      13. vi  /usr/local/squid/etc/squid.conf
      14. cache_effective_user squid    #运行squid的用户
      15. cache_effective_group squid   #运行squid的用户所在的组
      16. visible_hostname squid1.cache.cn   #设定squid的主机名,如无此项squid将无法启动
      17. http_port 80 accel vhost vport   #代理端口
      18. icp_port 3130   #icp端口
      19. # 配置其他缓存服务器,当squid1在其缓存中没有找到请求的资源时,通过ICP查询去其邻居中取得缓存
      20. cache_peer 10.10.10.21 sibling 80 3130
      21. cache_peer 10.10.10.22 sibling 80 3130
      22. cache_peer 10.10.10.23 sibling 80 3130
      23. # 后端web服务器配置,round-robin表示通过轮询方式将请求分发到其中一台web节点
      24. cache_peer 10.10.10.56 parent 80 0 no-query originserver round-robin  name=webServer1
      25. cache_peer 10.10.10.57 parent 80 0 no-query originserver round-robin  name=webServer2
      26. cache_peer_domain webServer1 webServer2  .123.com  #根据通配域名xuad.com来进行转发
      27. # 下面三行是配置访问控制的
      28. http_access allow all   #允许以上所有规则通过
      29. # URL中包含cgi-bin和以https:\\开头的都不缓存,asp、cgi、php、jsp等动态页面也不缓存
      30. hierarchy_stoplist cgi-bin ?
      31. hierarchy_stoplist -i ^https:\\ ?
      32. acl QueryString urlpath_regex -i cgi-bin \? \.asp \.php \.jsp \.cgi
      33. acl denyssl urlpath_regex -i ^https:\\
      34. no_cache deny QueryString
      35. no_cache deny denyssl
      36. # 日志和缓存目录的设置
      37. cache_log /usr/local/squid/var/logs/cache.log   #cache.log日志文件存放目录
      38. access_log /usr/local/squid/var/logs/access.log squid   #access.log日志文件存放目录
      39. cache_dir aufs /var/cache 1024 16 256   #设定缓存目录cache,目录容量最大1024M,16*256级子目录
      40. cache_dir aufs /var/squid 3072 16 256   #设定缓存目录squid,目录容量最大3072M,16*256级子目录
      41. cache_mem 128 MB    #squid用于缓存的内存容量
      42. # 当缓存目录空间使用达到95%以上时,新的内容将取代旧的内容,直到空间又下降到90%才停止这一活动
      43. cache_swap_low 90
      44. cache_swap_high 95
      45. # 设置存储策略
      46. maximum_object_size 4096 KB    #能缓存的最大对象为4M
      47. maximum_object_size_in_memory 80 KB   #内存中缓存的最大对象80K
      48. ipcache_size 1024   #缓存DNS解析得到的IP,最大单个对象为1024K
      49. ipcache_low 90
      50. ipcache_high 95
      51. cache_replacement_policy lru   #缓存替换策略
      52. memory_replacement_policy lru   #内存替换策略
      53. memory_pools on   #开启内存池
      54. memory_pools_limit 32 MB   #限制内存池大小为32MB
      55. forwarded_for on   #开启转发
      56. log_icp_queries off   #关闭icp查询日志
      57. forward_timeout 20 seconds   #允许转发超时20秒
      58. connect_timeout 30 seconds   #连接到其他机器的最大尝试时间
      59. read_timeout 3 minutes   #允许读取超时3分钟
      60. request_timeout 1 minutes    #允许返回超时1分钟
      61. persistent_request_timeout 30 seconds   #允许持续连接超时30秒
      62. client_lifetime 15 minutes   #客户端会话保持
      63. shutdown_lifetime 5 seconds
      64. negative_ttl 30 seconds   #设置错误信息的生存时间
      65. # 允许一个IP最大并发数为50
      66. acl OverConnLimit maxconn 50
      67. http_access deny OverConnLimit
      68. client_persistent_connections off   #对客户端长连接KeepAlive这个参数的支持
      69. server_persistent_connections on  # 开启服务端的KeepAlive,web端要开启KeepAlive,不然这里打开是没用的
      70. tcp_recv_bufsize 65535 bytes   #TCP套接字接收缓冲区大小
      71. half_closed_clients off  #当客户与squid的连接处于半关闭状态时,允许squid立即关闭连接
      72. via on   #开启转发循环的检测
      73. request_header_access via deny all   #避免由于两台squid的主机名一样而返回403错误
      74. httpd_suppress_version_string off   #错误页面不显示squid的版本信息
      75. ie_refresh off   #是否允许对旧版本的IE浏览器强制刷新页面
      /usr/local/squid/sbin/squid -N –z
      /usr/local/squid/sbin/squid
      配置lvs客户端模式~

      1. #!/bin/bash
      2. SNS_VIP=10.10.10.88
      3. source /etc/rc.d/init.d/functions
      4. case “$1” in
      5. start)
      6.        ifconfig lo:0 $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP
      7.        /sbin/route add -host $SNS_VIP dev lo:0
      8.        echo “1” >/proc/sys/net/ipv4/conf/lo/arp_ignore
      9.        echo “2” >/proc/sys/net/ipv4/conf/lo/arp_announce
      10.        echo “1” >/proc/sys/net/ipv4/conf/all/arp_ignore
      11.        echo “2” >/proc/sys/net/ipv4/conf/all/arp_announce
      12.        echo “RealServer Start OK”
      13.        ;;
      14. stop)
      15.        ifconfig lo:0 down
      16.        route del $SNS_VIP >/dev/null 2>&1
      17.        echo “0” >/proc/sys/net/ipv4/conf/lo/arp_ignore
      18.        echo “0” >/proc/sys/net/ipv4/conf/lo/arp_announce
      19.        echo “0” >/proc/sys/net/ipv4/conf/all/arp_ignore
      20.        echo “0” >/proc/sys/net/ipv4/conf/all/arp_announce
      21.        echo “RealServer Stoped”
      22.        ;;
      23. *)
      24.        echo “Usage: $0 {start|stop}”
      25.        exit 1
      26. esac
      27. exit 0

       

       

      lnmp自动安装脚本,含有eaccelerator memcache组件

      这个是完整的配置脚本,可以把mysql部分取消~

      版本我选择的是

      pcre-8.01.tar.gz,  nginx-1.0.2.tar.gz,  mysql-5.1.41.tar.gz,   php-5.3.3.tar.bz2,   memcache-2.2.5.tgz

      1. #!/bin/sh
      2. srcpath=/usr/src
      3. apppath=/usr/local
      4. sleep 5
      5. if
      6. [ $UID -ne 0 ];then
      7. echo “This script must use administrator or root user ,please exit …….”
      8. sleep 2
      9. exit 1
      10. fi
      11. Download ()
      12. {
      13. cd $srcpath && wget http://blog.mgcrazy.com/download/{pcre-8.01.tar.gz,nginx-1.0.2.tar.gz,mysql-5.1.41.tar.gz,php-5.3.3.tar.bz2,memcache-2.2.5.tgz,php-fpm.conf,php.ini,nginx.conf,fcgi.conf,eaccelerator-0.9.6.1.tar.bz2}
      14. echo “THIS IS STARTING SHELL MAKE INSTALL SHELL ,PLEASE WAITING ………………………..”
      15. sleep 2s
      16. if [ $? -eq 0 ];then
      17. echo -n “DownLoad Linux source packages End ,Please Waiting Install………………”
      18. else
      19. echo -n “Download Linux source packages Failed ,Please Check………………”
      20. fi
      21. }
      22. Nginx_install ()
      23. {
      24. cd $srcpath && tar xzf pcre-8.01.tar.gz && cd pcre-8.01 && ./configure –prefix=$apppath/pcre && make &&make install
      25. if
      26. [ $? -eq 0 ];then
      27. echo “This pcre make install end ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++”
      28. else
      29. echo “Pcre install failed ,please check install shell or system gcc configuration ,exiting ……….”
      30. sleep 1s
      31. exit 1
      32. fi
      33. echo “pcre install end ………..,please install nginx …………………”
      34. useradd www ; cd $srcpath && tar xzf nginx-1.0.2.tar.gz && cd nginx-1.0.2 && ./configure –prefix=$apppath/nginx –with-http_stub_status_module –with-cc-opt=’-O3′ –with-cpu-opt=opteron –with-openssl=/usr/ –with-pcre=/usr/src/pcre-8.01 –user=www –group=www ; make ; make install
      35. cp -r $srcpath/{nginx.conf,fcgi.conf} $apppath/nginx/conf/
      36. if [ $? -eq 0 ];then
      37. echo -n “Nginx Install success ………………”
      38. else
      39. echo -n “Nginx Install Failed ,Please Check………………”
      40. exit 1
      41. fi
      42. echo “nginx install end …………………..,Next install mysql …………………………..”
      43. }
      44. Mysql_install ()
      45. {
      46. cd $srcpath && tar xzf mysql-5.1.41.tar.gz && cd mysql-5.1.41 && ./configure –prefix=$apppath/mysql/ –enable-assembler –with-extra-charsets=complex –enable-thread-safe-client –with-big-tables –with-readline –with-ssl –with-embedded-server –enable-local-infile –with-plugins=innobase && make &&make install
      47. if [ $? -eq 0 ];then
      48. echo -n “Mysql Install success ………………”
      49. else
      50. echo -n “Mysql Install Failed ,Please Check………………”
      51. exit 1
      52. fi
      53. echo “init mysql server , ……….please waiting ………………………………….”
      54. cd /usr/local/mysql && useradd mysql ; chown -R mysql:mysql /usr/local/mysql && /usr/local/mysql/bin/mysql_install_db –user=mysql && chown -R mysql:mysql var/
      55. echo “Now install php ,please waiting………………………………….”
      56. }
      57. Php_install ()
      58. {
      59. yum clean all && yum install -y libevent* &&cd $srcpath &&tar jxvf php-5.3.3.tar.bz2 && cd php-5.3.3 && ./configure –prefix=$apppath/php5 –with-config-file-path=$apppath/php5/etc –with-mysql=$apppath/mysql –with-mysqli=$apppath/mysql/bin/mysql_config –with-iconv-dir=/usr/local –with-freetype-dir –with-jpeg-dir –with-png-dir –with-zlib –with-libxml-dir=/usr –enable-xml –disable-rpath –enable-discard-path –enable-safe-mode –enable-bcmath –enable-shmop –enable-sysvsem –enable-inline-optimization –with-curl –with-curlwrappers –enable-mbregex –enable-fpm –enable-sockets && make &&make install
      60. if
      61. [ $? -eq 0 ];then
      62. echo “This PHP make install end ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++”
      63. else
      64. echo “This PHP failed ,please check install shell ,exiting ……….”
      65. sleep 2s
      66. echo “This PHP failed ,please check install shell ,exiting ……….” |mail -s “PHP make install failed” wgkgood@139.com
      67. exit 2
      68. fi
      69. cp -r $srcpath/php.ini $apppath/php5/etc/
      70. cp $srcpath/php-5.3.3/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm ;chmod o+x /etc/init.d/php-fpm
      71. }
      72. Eacce_install ()
      73. {
      74. echo “Now install eaccelerator …………….,please waiting……………………..”
      75. cd /usr/src && tar jxvf eaccelerator-0.9.6.1.tar.bz2 && cd eaccelerator-0.9.6.1 && $apppath/php5/bin/phpize && ./configure –enable-eaccelerator=shared –with-php-config=$apppath/php5/bin/php-config &&make &&make test &&make install &&mkdir -p /tmp/eaccelerator && chmod 777 -R /tmp/eaccelerator
      76. if
      77. [ $? -eq 0 ];then
      78. echo “Install eaccelerator success ”
      79. else
      80. echo “Install eaccelerator failed ,please check ………………………”
      81. fi
      82. }
      83. Mem_install ()
      84. {
      85. ###########now install memcached #######################
      86. echo “next install memcached……………………………………..”
      87. cd $srcpath && tar xzf memcache-2.2.5.tgz && cd memcache-2.2.5 && /usr/local/php5/bin/phpize && ./configure –prefix=$apppath/memcached –with-php-config=$apppath/php5/bin/php-config &&make &&make install
      88. if
      89. [ $? -eq 0 ];then
      90. echo “Install Memcache success ”
      91. else
      92. echo “Install Memcache failed ,please check ………………………”
      93. fi
      94. }
      95. EXIT ()
      96. {
      97. echo “Now not Install ,Please exit …………………..”
      98. exit 0
      99. }
      100. PS3=”Please Select Install Linux Packages: ”
      101. select option in Download Nginx_install Mysql_install Php_install Eacce_install Mem_install EXIT
      102. do
      103. $option
      104. done

      memcached 缓存安装配置

      1. #!/bin/bash
      2. PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
      3. export PATH
      4. # Check if user is root
      5. if [ $(id -u) != “0” ]; then
      6.     echo “Error: You must be root to run this script, please use root to install lnmp”
      7.     exit 1
      8. fi
      9. clear
      10. cur_dir=$(pwd)
      11.     get_char()
      12.     {
      13.     SAVEDSTTY=`stty -g`
      14.     stty -echo
      15.     stty cbreak
      16.     dd if=/dev/tty bs=1 count=1 2> /dev/null
      17.     stty -raw
      18.     stty echo
      19.     stty $SAVEDSTTY
      20.     }
      21.     echo “”
      22.     echo “Press any key to start install Memcached…”
      23.     char=`get_char`
      24. printf “=========================== install memcached ======================\n”
      25. wget -c http://soft.vpser.net/lib/libevent/libevent-2.0.13-stable.tar.gz
      26. tar zxvf libevent-2.0.13-stable.tar.gz
      27. cd libevent-2.0.13-stable/
      28. ./configure –prefix=/usr/local/libevent
      29. make&& make install
      30. cd ../
      31. ln -s /usr/local/libevent/lib/libevent-2.0.so.5  /lib/libevent-2.0.so.5
      32. wget -c http://soft.vpser.net/web/memcached/memcached-1.4.7.tar.gz
      33. tar zxvf memcached-1.4.7.tar.gz
      34. cd memcached-1.4.7/
      35. ./configure –prefix=/usr/local/memcached
      36. make &&make install
      37. cd ../
      38. ln /usr/local/memcached/bin/memcached /usr/bin/memcached
      39. cp conf/memcached-init /etc/init.d/memcached
      40. chmod +x /etc/init.d/memcached
      41. useradd -s /sbin/nologin nobody
      42. if [ -s /etc/debian_version ]; then
      43. update-rc.d -f memcached defaults
      44. elif [ -s /etc/RedHat-release ]; then
      45. chkconfig –level 345 memcached on
      46. fi
      47. echo “Starting Memcached…”
      48. /etc/init.d/memcached start

        mysql安装配置,已开启了indodb的支持

      1. read mima
      2. wget -c http://soft.vpser.net/datebase/mysql/mysql-5.1.60.tar.gz
      3. tar -zxvf mysql-5.1.60.tar.gz
      4. cd mysql-5.1.60/
      5. ./configure –prefix=/usr/local/mysql –with-extra-charsets=all –enable-thread-safe-client –enable-assembler –with-charset=utf8 –with-plugins=max –enable-thread-safe-client –with-extra-charsets=all –with-big-tables –with-readline –with-ssl –with-embedded-server –enable-local-infile –with-innodb
      6. make && make install
      7. cd ../
      8. groupadd mysql
      9. useradd -s /sbin/nologin -M -g mysql mysql
      10. cp -f /usr/local/mysql/share/mysql/my-medium.cnf /etc/my.cnf
      11. sed -i ‘s/skip-locking/skip-external-locking/g’ /etc/my.cnf
      12. /usr/local/mysql/bin/mysql_install_db –user=mysql
      13. chown -R mysql /usr/local/mysql/var
      14. chgrp -R mysql /usr/local/mysql/.
      15. cp -f /usr/local/mysql/share/mysql/mysql.server /etc/init.d/mysql
      16. chmod 755 /etc/init.d/mysql
      17. cat > /etc/ld.so.conf.d/mysql.conf<<EOF
      18. /usr/local/mysql/lib/mysql
      19. /usr/local/lib
      20. EOF
      21. ldconfig
      22. ln -s /usr/local/mysql/lib/mysql /usr/lib/mysql
      23. ln -s /usr/local/mysql/include/mysql /usr/include/mysql
      24. /etc/init.d/mysql start
      25. ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql
      26. ln -s /usr/local/mysql/bin/mysqldump /usr/bin/mysqldump
      27. ln -s /usr/local/mysql/bin/myisamchk /usr/bin/myisamchk
      28. /usr/local/mysql/bin/mysqladmin -u root password $mima
      29. /etc/init.d/mysql restart

      mysql主从设置~~~~

       

      1. (1)首先确保主从服务器上的Mysql版本相同
      2. (2)在主服务器上,设置一个从数据库的账户,使用REPLICATION SLAVE赋予权限,如:
      3. mysql> GRANT REPLICATION SLAVE ON *.* TO ‘slave001’@’10.10.10.59’ IDENTIFIED BY
      4. ‘123123’;
      5. Query OK, 0 rows affected (0.13 sec)
      6. (3)修改主数据库的配置文件my.cnf,开启BINLOG,并设置server-id的值,修改之后必须重启Mysql服务
      7. [mysqld]
      8. log-bin=mysql-bin
      9. binlog-ignore-db= mysql
      10. server-id=1
      11. (4)之后可以得到主服务器当前二进制日志名和偏移量,这个操作的目的是为了在从数据库启动后,从这个点开始进行数据的恢复
      12. mysql> show master status\G;
      13. *************************** 1. row ***************************
      14. File: mysql-bin.000003
      15. Position: 243
      16. Binlog_Do_DB:
      17. Binlog_Ignore_DB:
      18. 1 row in set (0.00 sec)
      19. (5)好了,现在可以停止主数据的的更新操作,并生成主数据库的备份,我们可以通过mysqldump到处数据到从数据库,当然了,你也可以直接用cp命令将数据文件复制到从数据库去
      20. 注意在导出数据之前先对主数据库进行READ LOCK,以保证数据的一致性
      21. mysql> flush tables with read lock;
      22. Query OK, 0 rows affected (0.19 sec)
      23. 之后是mysqldump
      24. mysqldump -h127.0.0.1 -p3306 -uroot -p test > /home/chenyz/test.sql
      25. 最好在主数据库备份完毕,恢复写操作
      26. mysql> unlock tables;
      27. Query OK, 0 rows affected (0.28 sec)
      28. (6)将刚才主数据备份的test.sql复制到从数据库,进行导入
      29. (7)接着修改从数据库的my.cnf,增加server-id参数,指定复制使用的用户,主数据库服务器的ip,端口以及开始执行复制日志的文件和位置
      30. [mysqld]
      31. server-id=2
      32. log-bin=mysql-bin
      33. master-host =10.10.10.58
      34. master-user=test
      35. master-pass=123123
      36. master-port =3306
      37. master-connect-retry=60
      38. replicate-do-db =test
      39. (8)在从服务器上,启动slave进程
      40. mysql> start slave;
      41. (9)在从服务器进行show salve status验证
      42. mysql> SHOW SLAVE STATUS\G
      43. *************************** 1. row ***************************
      44. Slave_IO_State: Waiting for master to send event
      45. Master_Host: localhost
      46. Master_User: root
      47. Master_Port: 3306
      48. Connect_Retry: 3
      49. Master_Log_File: mysql-bin.003
      50. Read_Master_Log_Pos: 79
      51. Relay_Log_File: gbichot-relay-bin.003
      52. Relay_Log_Pos: 548
      53. Relay_Master_Log_File: mysql-bin .003
      54. Slave_IO_Running: Yes
      55. Slave_SQL_Running: Yes
      56. (10)好了,现在可以在我们的主服务器做一些更新的操作,然后在从服务器查看是否已经更新

解决MySql “Host is blocked because of many connection error” 的问题

解决MySql “Host is blocked because of many connection error” 的问题

      这些天,连接MySql出现了

     Host is blocked because of many connection error” In MySQL的问题,从网上搜索了一些解决方式,现记录如下:

Today, I got following MySQL error in a PHP application: Host ‘host_name’ is blocked because of many connection errors; unblock with ‘mysqladmin flush-hosts’. It means that mysqld has received many connection requests from the given host. Default max_connect_errors value is 10, that is remote host will be blocked if there is more than 10 connection errors.

To fix, type the following command

# mysqladmin flush-hosts

To avoid this happening again, edit my.cnf

# vi /etc/my.cnf

Add the following line

max_connect_errors=10000

The value of the max_connect_errors system variable determines how many successive interrupted connection requests are permitted. Restart MySQL to reload configuration file

# service mysqld restart

Or, the value ‘max_connect_errors’ can also be set at runtime, type the following commands

# mysql -uroot -p
# mysql> SET GLOBAL max_connect_errors=10000;

activeMQ+stomp+php实现消息队列

一、ActiveMQ的安装与配置

1、安装JDK

2、安装ActiveMQ

wget http://mirror.esocc.com/apache/activemq/apache-activemq/5.8.0/apache-activemq-5.8.0-bin.tar.gz

3、配置ActiveMQ,使其支持stomp

在配置文件/usr/local/activemq/conf/activemq.xml,添加

<transportConnectors>
<!– DOS protection, limit concurrent connections to 1000 and frame size to 100MB –>
<transportConnector name=”openwire” uri=”tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600″/>
<transportConnector name=”amqp” uri=”amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600″/>
<transportConnector name=”stomp” uri=”stomp://localhost:61613″/>
</transportConnectors>

4、启动ActiveMQ

/usr/local/activemq/bin/activemq start

二、安装php的stomp扩展

查看最新的stomp

http://pecl.php.net/package/stomp

wget http://pecl.php.net/get/stomp-1.0.5.tgz

tar -zxf  stomp-1.0.5.tgz

/usr/bin/phpize5

./configure –enable-stomp –with-php-config=/usr/bin/php-config5

make & make install

在php.ini中添加

extension = stomp.so

三、php—实现定时从消息队列里取出数据

从队列里取出数据(此程序以守护进行的方式运行),代码如下:

<?php
/**
* ActiveMQ Client
*
* @author yiluxiangbei<2498038528@qq.com>
*/

class MessageQueueApp extends BaseAppEx
{

/**
* Default prefetch size
*
* @var int
*/
public $prefetchSize = 1000;
/**
* sleep of time (unit sencond)
*
* @var int
*/
private $_sleepIntval = 60;

private $_stomp    = null;

private $_mysqli   = null;

public function run()
{
while(true){
try{
//connecting database
try {
} catch (Exception $ex) {
die(‘MySQL connection failed: ‘.$ex->getMessage());
}
//connecting activemq
try {
$this->_stomp = new Stomp($this->conf[‘MessageQueue’][‘stompUri’]);
} catch (StompException $e) {
die(‘Connection failed: ‘.$e->getMessage());
}

$this->_stomp->subscribe($this->conf[‘MessageQueue’][‘queueUri’], array(‘activemq.prefetchSize’ => $this->prefetchSize));

$frame = null;
$data = array();
while (TRUE == $this->_stomp->hasFrame())
{
$temp = array();
$frame = $this->_stomp->readFrame();
if (FALSE !== $frame)
{
//file_put_contents(ROOT_PATH.’/cache/MQ’, $frame->body.”\n”, FILE_APPEND);
//operate dataBase
$temp = json_decode($frame->body, true);

$data = array_merge($data, $temp);

$this->_stomp->ack($frame);

} else {
continue;
}
}

$result = $this->_handleData1($data);

}catch (Exception $e){
echo “Exception is: “.$e->getMessage().”\n\n”;
}
echo “Statistic Over, {$this->_sleepIntval} seconds to next statistics..\n\n”;
$this->_stomp->unsubscribe($this->conf[‘MessageQueue’][‘queueUri’]);
unset($this->_stomp);
$this->_mysqli->close();
sleep($this->_sleepIntval);
}
}

/*
* data to store(The three table is not related)
*
* @param data array
* @return result bool
*/
private function _handleData1($data)
{
$insert_1 = “INSERT INTO `msg1`(`info`, `time`) VALUES”;
$insert_2 = “INSERT INTO `msg2`(`relateId`, `info`, `time`) VALUES”;
$insert_3 = “INSERT INTO `msg3`(`relateId`, `info`, `time`) VALUES”;
$count = count($data);

if (!empty($data)) {
$i = 0;
foreach ($data as $randId => $val) {
if ($i == 0) {
$insert_1 = $insert_1.”(‘{$val[0][0]}’, ‘{$val[0][1]}’)”;
$insert_2 = $insert_2.”(2, ‘{$val[1][0]}’, ‘{$val[1][1]}’)”;
$insert_3 = $insert_3.”(3, ‘{$val[2][0]}’, ‘{$val[2][1]}’)”;
} else {
$insert_1 = $insert_1.”,(‘{$val[0][0]}’, ‘{$val[0][1]}’)”;
$insert_2 = $insert_2.”,(2, ‘{$val[1][0]}’, ‘{$val[1][1]}’)”;
$insert_3 = $insert_3.”,(3, ‘{$val[2][0]}’, ‘{$val[2][1]}’)”;
}

$i++;
}
}
//echo $insert_1,PHP_EOL;
//echo $insert_2,PHP_EOL;
//echo $insert_3,PHP_EOL;
$success = TRUE;
$this->_mysqli->autocommit(0);

$this->_mysqli->query($insert_1);
echo $this->_mysqli->affected_rows,PHP_EOL;
if ($count != $this->_mysqli->affected_rows) {
$success = FALSE;
}

$this->_mysqli->query($insert_2);
echo $this->_mysqli->affected_rows,PHP_EOL;
if ($count != $this->_mysqli->affected_rows) {
$success = FALSE;
}

$this->_mysqli->query($insert_3);
echo $this->_mysqli->affected_rows,PHP_EOL;
if ($count != $this->_mysqli->affected_rows) {
$success = FALSE;
}

if ($success) {
$this->_mysqli->commit();
} else {
$this->_mysqli->rollback();
}

$this->_mysqli->autocommit(1);

}

/*
* data to store(The three table is related)
*
* @param data array
* @return result bool
*/
private function _handleData($data)
{
$this->_mysqli->commit();
} else {
$this->_mysqli->rollback();
}

$this->_mysqli->autocommit(1);

}

/*
* data to store(The three table is related)
*
* @param data array
* @return result bool
*/
private function _handleData($data)
{
$success = TRUE;

$this->_mysqli->autocommit(0);

$insert_1 = “INSERT INTO `msg1`(`info`, `time`) VALUES(‘{$data[0][0]}’, ‘{$data[0][1]}’)”;
$result1 = $this->_mysqli->query($insert_1);
if (!$result1 || $this->_mysqli->affected_rows!=1) {
$success = FALSE;
}

$relateId = $this->_mysqli->insert_id;

$insert_2 = “INSERT INTO `msg2`(`relateId`, `info`, `time`) VALUES({$relateId},'{$data[1][0]}’,'{$data[1][1]}’)”;
$result2  = $this->_mysqli->query($insert_2);
if (!$result2 || $this->_mysqli->affected_rows!=1) {
$success = FALSE;
}

$insert_3 = “INSERT INTO `msg3`(`relateId`, `info`, `time`) VALUES({$relateId},'{$data[2][0]}’,'{$data[2][1]}’)”;
$result3  = $this->_mysqli->query($insert_3);
if (!$result3 || $this->_mysqli->affected_rows!=1) {
$success = FALSE;
}

if ($success) {
$this->_mysqli->commit();
} else {
$this->_mysqli->rollback();
}

$this->_mysqli->autocommit(1);

return $success;
}
}
?>

将数据插入队列中

<?php
class DebugApp extends BaseAppEx
{
/**
* test
*/

public function index()
{

$randId = uniqid();
$time = date(‘Y-m-d H:i:s’, time());

$data = array();

$data[$randId][0] = array(‘msg1’, $time);
$data[$randId][1] = array(‘msg2’, $time);
$data[$randId][2] = array(‘msg3’, $time);

$data = json_encode($data);

$this->_sendMQ($data);
}
private function _sendMQ($data)
{
try {
$stomp = new Stomp($this->conf[‘MessageQueue’][‘stompUri’]);
} catch (StompException $e) {
//die(‘Connection failed: ‘.$e->getMessage());
throw new Exception($e->getMessage());
}

if (empty($data)) {
throw new Exception(‘Parameter must not be empty!’);
}

$isSucc = $stomp->send($this->conf[‘MessageQueue’][‘queueUri’], $data, array(‘persistent’ => ‘true’));
if (false == $isSucc)
{
throw new Exception(“$data send failed!”);
}

unset($stomp);
}
}
?>

四、参考资料

http://activemq.apache.org/

http://activemq.apache.org/version-5-getting-started.html

http://activemq.apache.org/examples.html

http://activemq.apache.org/contributing.html

ActiveMQ+In+Action.pdf

Linux 下 strace 命令用法总结

Linux 下 strace 命令用法总结

1 功能说明
strace 命令是一种强大的工具, 能够显示任何由用户空间程式发出的系统调用. strace 显示这些调用的参数并返回符号形式的值. strace 从内核接收信息, 而且无需以任何特别的方式来构建内核. strace 的每一行输出包括系统调用名称, 然后是参数和返回值.

下面记录几个常用option:

-f -F选项告诉strace同时跟踪fork和vfork出来的进程

-o xxx.txt 输出到某个文档.

-e execve 只记录 execve 这类系统调用.

2 详细用法
usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] … [-o file]

[-p pid] … [-s strsize] [-u username] [-E var=val] …

[command [arg …]]

or: strace -c [-e expr] … [-O overhead] [-S sortby] [-E var=val] …

[command [arg …]]

-c — count time, calls, and errors for each syscall and report summary

-f — follow forks, -ff — with output into separate files

-F — attempt to follow vforks, -h — print help message

-i — print instruction pointer at time of syscall

-q — suppress messages about attaching, detaching, etc.

-r — print relative timestamp, -t — absolute timestamp, -tt — with usecs

-T — print time spent in each syscall, -V — print version

-v — verbose mode: print unabbreviated argv, stat, termio[s], etc. args

-x — print non-ascii strings in hex, -xx — print all strings in hex

-a column — alignment COLUMN for printing syscall results (default 40)

-e expr — a qualifying expression: option=[!]all or option=[!]val1[,val2]…

options: trace, abbrev, verbose, raw, signal, read, or write

-o file — send trace output to FILE instead of stderr

-O overhead — set overhead for tracing syscalls to OVERHEAD usecs

-p pid — trace process with process id PID, may be repeated

-s strsize — limit length of print strings to STRSIZE chars (default 32)

-S sortby — sort syscall counts by: time, calls, name, nothing (default time)

-u username — run command as username handling setuid and/or setgid

-E var=val — put var=val in the environment for command

-E var — remove var from the environment for command

3 参数说明
-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的版本信息.

-x 以十六进制形式输出非标准字符串.

-xx 所有字符串以十六进制形式输出.

-a column 设置返回值的输出位置.默认 为40.

-e expr 指定一个表达式,用来控制如何跟踪.格式如下:

[qualifier=][!]value1[,value2]…

qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其它调用.有两个特殊的符号 all 和 none. 注意有些shell使用!来执行历史记录里的命令,所以要使用\\.

-e trace=set 只跟踪指定的系统调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.

-e trace=file 只跟踪有关文件操作的系统调用.

-e trace=process 只跟踪有关进程控制的系统调用.

-e trace=network 跟踪与网络有关的所有系统调用.

-e strace=signal 跟踪所有与系统信号有关的系统调用.

-e trace=ipc 跟踪所有与进程通讯有关的系统调用.

-e abbrev=set 设定strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.

-e raw=set 将指定的系统调用的参数以十六进制显示.

-e signal=set 指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.

-e read=set 输出从指定文件中读出的数据.例如-e read=3,5

-e write=set 输出写入到指定文件中的数据.

-o filename 将strace的输出写入文件filename

-p pid 跟踪指定的进程pid.

-s strsize 指定输出的字符串的最大长度.默认为32.文件名一直全部输出.

-u username 以username 的UID和GID执行被跟踪的命令.
3 用strace调试程序

在理想世界里, 每当一个程序不能正常执行一个功能 时, 它就会给出一个有用的错误提示, 告诉在足够的改正错误的线索. 但遗憾的是, 我们不是生活在理想世界里, 起码不总是生活在理想世界里. 有时 候一个程序出现了问题, 无法找到原因. 这就是调试程序出现的原因. strace是一个必不可少的调试工具, strace用来监视系统调用. 不仅 可以调试一个新开始的程序, 也可以调试一个已经在运行的程序(把strace绑定到一个已有的PID上 面).

首先让我们看一个真实的例子:

启动KDE时出现问题, 前一段时间, 我在启动KDE的时候出了问题, KDE 的错误信息无法给我任何有帮助的线索.
_KDE_IceTransSocketCreateListener: failed to bind listener
_KDE_IceTransSocketUNIXCreateListener: …SocketCreateListener() failed
_KDE_IceTransMakeAllCOTSServerListeners: failed to create listener for local

Cannot establish any listening sockets DCOPServer self-test failed.

对我来说这个错误信息没有太多意义, 只是一个对KDE 来说至关重要的负责进程间通信的程序无法启动. 我还可以知道这个错误和ICE协议(Inter Client Exchange)有关, 除此之 外, 我不知道什么是KDE启动出错的原因. 我决定采用strace看一下在启动 dcopserver时到底程序做了什么:
strace -f -F -o ~/dcop-strace.txt dcopserver

这里 -f -F选项告诉strace同时跟踪fork 和vfork出来的进程, -o选项把所有strace输出写到~/dcop-strace.txt里 面, dcopserver是要启动和调试的程 序. 再次出现错误之后, 我检查了错误输出文件dcop-strace.txt, 文件里有很多系统调用的记录. 在程序运行出错前的有关记录如下:

其中第一行显示程序试图创建/tmp/.ICE- unix目录, 权限为0777, 这个操作因为目录已经存在而失败了. 第二个系统调用(lstat64)检查了目录状态, 并显示这个目录的权限是 0755, 这里出现了第一个程序运行错误的线索: 程序试图创建属性为0777的目录, 但是已经存在了一个属性为 0755的目录. 第三个系统调用 (unlink)试图删除一个文件, 但是这个文件并不存在. 这并不奇怪, 因为这个操作只是试图删掉可能存在的老文件.

但是, 第四行确认了错误所在. 它试图绑定到/tmp /.ICE-unix/dcop27207-1066844596, 但是出现了拒绝访问错误. ICE_unix目录的用户和组都是root, 并且只 有所有者具有写权限. 一个非root用户无法在这个目录下面建立文件, 如果把目录属性改成0777,  则前面的操作有可能可以执行, 而这正是第一 步错误出现时进行过的操作.

所以我运行了chmod 0777 /tmp /.ICE-unix之后KDE就可以正常启动了, 问题解决了, 用strace进行跟踪调试只需要花很短的几分钟时间跟踪程序运行, 然后检查并分析 输出文件.

说明: 运行chmod 0777只是一个测试, 一般 不要把一个目录设置成所有用户可读写, 同时不设置粘滞位(sticky bit). 给目录设置粘滞位可以阻止一个用户随意删除可写目录下面其它人的文 件. 一般会发现/tmp目录因为这个原因设置了粘滞位. KDE可以正常启动之后, 运行chmod +t /tmp/.ICE-unix 给.ICE_unix设置粘滞位.

2 用strace解决库依赖问题
starce 的另一个用处是解决和动态库相关的问题. 当对一个可执行文件运行ldd 时, 它会告诉程序使用的动态库和找到动态库的位置. 但是如果正在使用一个比较老的glibc版本(2.2或更早), 可能会有一个有bug的ldd程 序, 它可能会报告在一个目录下发现一个动态库, 但是真正运行程序时动态连接程序 (/lib/ld-linux.so.2)却可能到另外一个目录去找 动态连接库. 这通常因为/etc/ld.so.conf和 /etc/ld.so.cache文件不一致, 或者/etc/ld.so.cache被破 坏. 在glibc 2.3.2版本上这个错误不会出现, 可能ld-linux的这个bug已经被解决了.

尽管这样, ldd并不能把所有程序依赖的动态库列出 来, 系统调用dlopen可以在需要的时候自动调入需要的动态库, 而这些库可能不会被ldd列出来. 作为glibc的一部分的 NSS(Name Server Switch)库就是一个典型的例子, NSS的一个作用就是告诉应用程序到哪里去寻找系统帐号数据库. 应用程序不会 直接连接到NSS库, glibc则会通 过dlopen自动调入NSS库. 如果这样的库偶然丢失, 不会被告知存在库依赖问题, 但这样的程序就无法 通过用户名解析得到用户ID了.

让我 们看一个例子:

whoami程序会给出自己的用户名, 这个程序在一些 需要知道运行程序的真正用户的脚本程序里面非常有用, whoami的一个示 例输出如下:
27207 mkdir(“/tmp/.ICE-unix”, 0777) = -1 EEXIST (File exists)
27207 lstat64(“/tmp/.ICE-unix”, {st_mode=S_IFDIR|S_ISVTX|0755, st_size=4096, …}) = 0
27207 unlink(“/tmp/.ICE-unix/dcop27207-1066844596″) = -1 ENOENT (No such file or directory)
27207 bind(3, {sin_family=AF_UNIX, path=”/tmp/.ICE-unix/dcop27207-1066844596”}, 38) = -1 EACCES (Permission denied)
27207 write(2, “_KDE_IceTrans”, 13) = 13
27207 write(2, “SocketCreateListener: failed to “…, 46) = 46
27207 close(3) = 0 27207 write(2, “_KDE_IceTrans”, 13) = 13
27207 write(2, “SocketUNIXCreateListener: …Soc”…, 59) = 59
27207 umask(0) = 0 27207 write(2, “_KDE_IceTrans”, 13) = 13
27207 write(2, “MakeAllCOTSServerListeners: fail”…, 64) = 64
27207 write(2, “Cannot establish any listening s”…, 39) = 39

假设因为某种原因在升级 glibc的过程中负责用户名 和用户ID转换的库NSS丢失, 我们可以通过把nss库改名来模拟这个环境:
# whoami
root

这里可以看到, 运行whoami时出现了错 误, ldd程序的输出不会提供有用的帮助:

只会看到whoami依赖Libc.so.6和ld-linux.so.2, 它没有给出运行 whoami所必须的其它库. 这里时用strace跟踪 whoami时的输出:
# mv /lib/libnss_files.so.2 /lib/libnss_files.so.2.backup
# whoami
whoami: cannot find username for UID 0

可以发现在不同目录下面查找libnss.so.2的尝 试, 但是都失败了. 如果没有strace这样的工具, 很难发现这个错误是由于缺少动态库造成的. 现在只需要找到libnss.so.2并把它放回 到正确的位置就可以了.

3 限制strace只跟踪特定的系统调用
如果 已经知道要找什么, 可以让strace只跟踪一些类型的系统调用. 例如, 需要看看在configure脚本里面执行的程序, 需要监视的系统调用就 是execve. 让strace只记录execve的调用用这个命令:
# ldd /usr/bin/whoami
libc.so.6 => /lib/libc.so.6 (0x4001f000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

部分输出结果为:

已经看到了, strace不仅可以被程序员使用, 普 通系统管理员和用户也可以使用strace来调试系统错误. 必须承认, strace的输出不总是容易理解, 但是很多输出对大多数人来说是不重要 的. 会慢慢学会从大量输出中找到可能需要的信息, 像权限错误, 文件未找到之类的, 那时strace就会成为一个有力的工具了.

gearman + php

向一个机器添加Gearman需要两步:

1.构建并启动这个守护进程

2.构建与php(或Python等)版本相匹配的PHP扩展。

我安装版本是Gearman 1.1.5:

1. 安装依赖包:

sudo apt-get update

sudo apt-get upgrade
sudo apt-get install gcc autoconf bison flex libtool make libboost-all-dev libcurl4-openssl-dev curl libevent-dev memcached uuid-dev libsqlite3-dev libmysqlclient-dev

2.下载Gearman版本

wget https://launchpad.net/gearmand/1.2/1.1.5/+download/gearmand-1.1.5.tar.gz

3.解压、编译、安装源码包

tar xvzf gearmand-1.1.5.tar.gz
cd gearmand-1.1.5
./configure
make
make install

注:这个过程中可能无法编译成功,这时候要根据个人实际情况,看它报的是什么错,然后根据报错,更新或者安装共享库。

sudo apt-get install ***等。

4.为大多数最新的共享库创建必须的链接和缓存。其中可能报:

error: gearman: error while loading shared libraries: libgearman.so.6: cannot open shared object file: No such file or directory

解决办法:sudo ldconfig

5.通过pecl安装gearman

sudo apt-get install php-pear
sudo pecl install gearman
sudo gedit /etc/php5/cgi/php.ini

注:有些版本的php.ini可能不在/etc/php5/cgi/这个路径下,我的是在/etc/php5/cli/这个路径下。

另外,可能你的机器上没安装php5这个工具,如果没安装的话,可以直接通过在先安装:sudo apt-get install php5

如果上面的方法无法安装gearman的php扩展,可以尝试下下面方法:

$ wget http://pecl.php.net/get/gearman-1.1.1.tgz
$ tar zxvf gearman-1.0.2.tgz
$ cd gearman-1.0.2/
$ phpize
$ make
$ make install
$ sudo echo “extension = gearman.so” > /etc/php5/conf.d/gearman.ini

6. 在php.ini文件末尾添加”extension=gearman.so”

7. 检测扩展是否安装成功

$ php –info | grep “gearman support”
gearman support => enabled

显示出:gearman support => enabled,就表示安装成功啦。

8 测试

1)sudo ldconfig

2)启动gearmand: gearmand -d &

这一步可能会遇到:

启动这个 agent,即 Gearman 守护程序:
/usr/local/sbin/gearmand –daemon
报错:Could not open log file “/usr/local/var/log/gearmand.log”, from “/usr/sbin”, switching to stderr. (No such file or directory)
解决:
mkdir -p /usr/local/var/log/
cd /usr/local/var/log/
touch gearmand.log
再次尝试启动:
/usr/local/sbin/gearmand –daemon
成功运行.查看进程:ps -ef | grep gearmand
root     19390     1  0 17:50 ?        00:00:00 gearmand –daemon
root     19403     1  0 17:54 ?        00:00:00 /usr/local/sbin/gearmand –daemon
root     19406  1556  0 17:54 pts/3    00:00:00 grep gearmand

3)查看gearmand是否在运行:ps auxw | grep [g]earmand

4)检查germand的任务检测端口4730:sudo lsof -i tcp:4730

9.例子:从PHP使用Gearman

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

从 PHP 使用 Gearman 类似于之前的示例,惟一的区别在于这里是在 PHP 内创建 producer 和 consumer。
每个 consumer 的工作均封装在一个或多个 PHP 函数内。
先用 PHP 编写的一个 Gearman worker。将这些代码保存在一个名为 worker.php 的文件中。
<?php
$worker= new GearmanWorker();
$worker->addServer();
$worker->addFunction(“title”, “title_function”);
while ($worker->work());

function title_function($job)
{
return ucwords(strtolower($job->workload()));
}
?>

再用 PHP 编写的一个 producer,或 client。将此代码保存在一个名为 client.php 的文件内。
<?php
$client= new GearmanClient();
$client->addServer();
print $client->do(“title”, “All The World’s a stage!”);
print “\n”;
?>

现在,可以用如下的命令行连接客户机与 worker 了:
php worker.php &
php client.php
结果:
All The World’s a stage!

10. 对上面的例子中代码的一些分析:

首先, PHP Gearman Extension 提供了一个名为 GearmanClient 的类别,它可以让程式安排工作给 Job Server 。而 addServer 方法表示要通知的是哪些 Job Server ,也就是说如果有多台 Job Server 的话,就可以透过 addServer 新增。然后我们将要呼叫哪个 Worker 以及该 Worker 所需要的资料,利用 GearmanClient 的 doBackground 方法传送过去。 doBackground 方法顾名思义就是在背景执行, Client 在丢出需求后就可以继续处理其他的程式,也就是我们常说的「射后不理」。
doBackground 方法的第一个参数是告诉 Job Server 要执行哪个功能,而这个功能则是由 Worker 提供的;要注意是,这个参数只是识别用的,并不是真正的函式名称。而第二个参数是要传给 Worker 的资料,它必须是个字串;因此如果要传送的是阵列的话,我们就要用 PHP 的 serialize 函式来对这些资料做序列化。
PHP 的 Gearman Extension 也提供了一个 GearmanWorker 类别,让我们可以实作 Worker 。而 GearmanWorker 类别也提供了addServer 方法,让所生成的 Worker 物件可以注册到 Job Server 中。
另外 GearmanWorker 类别也提供了 addFuncton 方法,告诉 Job Server 自己可以处理哪些工作。 addFunction 的第一个参数就是对应到 GearmanClient::doBackground 方法的第一个参数,也就是功能名称;这使得 Client 和 Worker 能透过这个名称来互相沟通。而第二个参数则是一个callback函式,它会指向真正应该要处理该工作的函式或类别方法等。
最后因为 Worker 因为要随时准备服务,是不能被中断的,因此我们透过一个无限迴圈来让它常驻在 Job Server 中。

 

 

 

已守护进程运行worker.php

# nohup php -c /usr/local/php/etc/php.ini worker.php >/dev/null 2>&1 &


这里,有几点需要说明一下:
1、这里直接用php cli方式运行,添加-c参数是为了加载php.ini配置文件,以加载gearman扩展
2、worker应该做成守护进程(CLI模式),可以开启多个,这样client发起的任务就会分发到各个worker分别来执行(自动负载均衡 )
这个例子由于太过简单,即使开启多个worker也无法看出效果,不过可以通过终止其中一个,可以看出系统自动切换到其他worker继续正常执行
3、同理,client也是可以开启多个的(模型请参考之前的那边日志)

4、同时,job也可以开启多个,以避免单点故障