Fork me on GitHub
Suzf  Blog

Archive Linux

LB 简单比较 - F5、NetScaler、LVS、Nginx、Haproxy

负载均衡技术是构建大型网站必不可少的架构策略之一。它的目的是,把用户的请求分发到多台后端的设备上,用以均衡服务器的负载。我们可以把负载均衡器划分为两大类:硬件负载均衡器和软件负载均衡器。

硬件负载均衡器,常见的有NetScaler、F5、Radware和Array等,这些设备为专业的厂商开发的负载均衡器,价格比较高昂,但也提供了高 可用性和高稳定性,同时还提供专业的技术服务,这些设备往往都是一些大企业(非IT类)所热衷的。因为这些企业不缺乏资金,也没有专业的it团队来开发和 运维类似的负载均衡套件。

软件负载均衡器,较流行的有LVS,haproxy,nginx。这三种软件负载均衡器都为开源软件,任何个人或企业都可以无偿使用,所以对于一些小企业 或者比较专业的大型IT或者互联网企业来说,使用这些软件负载均衡器成为了一种必然趋势。下面简单分析一些这三种开源负载均衡器的特点:

LVS特点是:
1. 首先它是基于4层的网络协议的,抗负载能力强,对于服务器的硬件要求除了网卡外,其他没有太多要求;
2. 配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,大大减少了人为出错的几率;
3. 应用范围比较广,不仅仅对web服务做负载均衡,还可以对其他应用(mysql)做负载均衡;
4. LVS架构中存在一个虚拟IP的概念,需要向IDC多申请一个IP来做虚拟IP。

Nginx负载均衡器的特点是:
1. 工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构;
2. Nginx安装和配置比较简单,测试起来比较方便;
3. 也可以承担高的负载压力且稳定,一般能支撑超过上万次的并发;
4. Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测;
5. Nginx对请求的异步处理可以帮助节点服务器减轻负载;
6. Nginx能支持http和Email,这样就在适用范围上面小很多;
7. 默认有三种调度算法: 轮询、weight以及ip_hash(可以解决会话保持的问题),还可以支持第三方的fair和url_hash等调度算法;

HAProxy的特点是:
1. HAProxy是工作在网络7层之上;
2. 支持Session的保持,Cookie的引导等;
3. 支持url检测后端的服务器出问题的检测会有很好的帮助;
4. 支持的负载均衡算法:动态加权轮循(Dynamic Round Robin),加权源地址哈希(Weighted Source Hash),加权URL哈希和加权参数哈希(Weighted Parameter Hash);
5. 单纯从效率上来讲HAProxy更会比Nginx有更出色的负载均衡速度;
6. HAProxy可以对Mysql进行负载均衡,对后端的DB节点进行检测和负载均衡。

 

Linux Web 服务器网站故障分析常用的命令

系统连接状态篇
1.查看 TCP 连接状态

netstat -nat |awk '{print $6}'|sort|uniq -c|sort -rn
netstat -n | awk '/^tcp/ {++S[$NF]};END {for(a in S) print a, S[a]}'
netstat -n | awk '/^tcp/ {++state[$NF]}; END {for(key in state) print key,"t",state[key]}'
netstat -n | awk '/^tcp/ {++arr[$NF]};END {for(k in arr) print k,"t",arr[k]}'
netstat -n |awk '/^tcp/ {print $NF}'|sort|uniq -c|sort -rn
netstat -ant | awk '{print $NF}' | grep -v '[a-z]' | sort | uniq -c

2.查找请求数请20个IP(常用于查找攻来源):

netstat -anlp|grep 80|grep tcp|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n20
netstat -ant |awk '/:80/{split($5,ip,":");++A[ip[1]]}END{for(i in A) print A[i],i}' |sort -rn|head -n20

3.用tcpdump嗅探80端口的访问看看谁最高

tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." '{print $1"."$2"."$3"."$4}' | sort | uniq -c | sort -nr |head -20

4.查找较多 time_wait 连接

netstat -n|grep TIME_WAIT|awk '{print $5}'|sort|uniq -c|sort -rn|head -n20

5.找查较多的 SYN 连接

netstat -an | grep SYN | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr | more

6.根据端口列进程

netstat -ntlp | grep 80 | awk '{print $7}' | cut -d/ -f1

 

网站日志分析篇

1(Apache)
1.获得访问前10位的ip地址

cat access.log|awk '{print $1}'|sort|uniq -c|sort -nr|head -10
cat access.log|awk '{counts[$(11)]+=1}; END {for(url in counts) print counts[url], url}'

2.访问次数最多的文件或页面,取前20

cat access.log|awk '{print $11}'|sort|uniq -c|sort -nr|head -20

3.列出传输最大的几个exe文件(分析下载站的时候常用)

cat access.log |awk '($7~/.exe/){print $10 " " $1 " " $4 " " $7}'|sort -nr|head -20

4.列出输出大于200000byte(约200kb)的exe文件以及对应文件发生次数

cat access.log |awk '($10 > 200000 && $7~/.exe/){print $7}'|sort -n|uniq -c|sort -nr|head -100

5.如果日志最后一列记录的是页面文件传输时间,则有列出到客户端最耗时的页面

cat access.log |awk '($7~/.php/){print $NF " " $1 " " $4 " " $7}'|sort -nr|head -100

6.列出最最耗时的页面(超过60秒的)的以及对应页面发生次数

cat access.log |awk '($NF > 60 && $7~/.php/){print $7}'|sort -n|uniq -c|sort -nr|head -100

7.列出传输时间超过 30 秒的文件

cat access.log |awk '($NF > 30){print $7}'|sort -n|uniq -c|sort -nr|head -20

8.统计网站流量(G)

cat access.log |awk '{sum+=$10} END {print sum/1024/1024/1024}'

9.统计404的连接

awk '($9 ~/404/)' access.log | awk '{print $9,$7}' | sort

10. 统计 http status

cat access.log |awk '{counts[$(9)]+=1}; END {for(code in counts) print code, counts[code]}'
cat access.log |awk '{print $9}'|sort|uniq -c|sort -rn

10.蜘蛛分析,查看是哪些蜘蛛在抓取内容。

/usr/sbin/tcpdump -i eth0 -l -s 0 -w - dst port 80 | strings | grep -i user-agent | grep -i -E 'bot|crawler|slurp|spider'

网站日分析2(Squid篇)

按域统计流量

zcat squid_access.log.tar.gz| awk '{print $10,$7}' |awk 'BEGIN{FS="[ /]"}{trfc[$4]+=$1}END{for(domain in trfc){printf "%st%dn",domain,trfc[domain]}}'

 

数据库篇
1.查看数据库执行的sql

/usr/sbin/tcpdump -i eth0 -s 0 -l -w - dst port 3306 | strings | egrep -i 'SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER|CALL'

 

系统Debug分析篇
1.调试命令
strace -p pid
2.跟踪指定进程的PID
gdb -p pid

Hello world!

Welcome to my blog. This is a happy day, a new website has born.

Puppet 将模块绘制成依赖关系图

依赖使关系迅速变得复杂,并且很容易结束循环依赖,(其中A依赖B,B又依赖A)这将引起
puppet编译错误并停止工作,幸运的是,puppet的图表选项可以很容易生成一个资源之间的依赖
关系图,它可以帮助我们解决这些问题。

Web_Faq: TCP: time wait bucket table overflow

前几日 查看自己的 VPS 主机 返现 有报错信息如下:
kernel: TCP: time wait bucket table overflow
kernel: TCP: time wait bucket table overflow
kernel: TCP: time wait bucket table overflow
(TCP:时间等待桶表)

根据报错提示,需要更改net.ipv4.tcp_max_tw_buckets这个内核参数。这个参数是系统同时保持timewait套接字的最大数量。如果超过这个数字,time-wait套接字将立刻被清除并打印警告信息。这个限制仅仅是为了防止简单的 DoS攻击,你绝对不能过分依靠它或者人为地减小这个值,如果网络实际需要大于缺省值,更应该增加这个值(如果增加了内存之后)。

解决方法:增大 tcp_max_tw_buckets的值,并不是这个值越小越好,我看了我系统中TIME_WAIT 大部是由php-fpm产生的,是属于正常的现象。
系统在同时所处理的最大timewait sockets 数目。如果超过此数的话﹐time-wait socket 会被立即砍除并且显示警告信息。之所以要设定这个限制﹐纯粹为了抵御那些简单的 DoS 攻击﹐千万不要人为的降低这个限制﹐不过﹐如果网络条件需要比默认值更多﹐则可以提高它(或许还要增加内存)。

netstat -an | grep 9000 | awk '{print $6}' | sort | uniq -c | sort -rn
netstat -an | grep 80 | awk '{print $6}' | sort | uniq -c | sort -rn

排查步骤:

1. 查看服务器网络连接情况;

# netstat -pant |awk '/^tcp/ {++state[$6]} END {for(key in state) printf("%-10s\t%d\n",key,state[key]) }'
TIME_WAIT 6798
CLOSE_WAIT 1
ESTABLISHED 592
SYN_RECV 69
CLOSING 39
LAST_ACK 19
LISTEN 107

2.查看内核参数
#sysctl -a | grep net.ipv4.tcp_max_tw_buckets
net.ipv4.tcp_max_tw_buckets = 8192

改为:net.ipv4.tcp_max_tw_buckets = 10000

3.使更改的内核参数生效
sysctl -p

4. 再次查看服务器网络连接情况;

# netstat -pant |awk '/^tcp/ {++state[$6]} END {for(key in state) printf("%-10s\t%d\n",key,state[key]) }'
TIME_WAIT 6644
...

5.再看/var/log/messages和dmesg的信息,已经不再报错了
看来net.ipv4.tcp_max_tw_buckets=10000暂时是够用了

6.原因

服务器的TCP连接数,超出了内核定义最大数。

 

[Warning] Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.

问题描述

发现网站反应比较慢 , 顺便查看了一下mysql的错误日志,发现产生了很多warning的日志:
150527 21:15:28 [Warning] Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe Statement: INSERT INTO 'xxx'

问题原因

查了下原因,xxx 这个表上有2个唯一键。则使用INSERT ... ON DUPLICATE KEY UPDATE ,且当前数据库binlog_format是statement格式,这种sql语句就会报unsafe。

查了下手册

INSERT ... ON DUPLICATE KEY UPDATE statements on tables with multiple primary or unique keys.When executed against a table that contains more than one primary or unique key, this statement is considered unsafe, being sensitive to the order in which the storage engine checks the keys, which is not deterministic, and on which the choice of rows updated by the MySQL Server depends.

INSERT ... ON DUPLICATE KEY UPDATEstatement against a table having more than one unique or primary key is marked as unsafe for statement-based replication beginning with MySQL 5.6.6. (Bug #11765650, Bug #58637)

link : http://dev.mysql.com/doc/refman/5.6/en/replication-rbr-safe-unsafe.html
binlog format : http://dev.mysql.com/doc/refman/5.6/en/replication-options-binary-log.html#sysvar_binlog_format

看官方解释,是server层把数据传给innodb引擎,innodb引擎检查key值比较敏感造成的。

问题解决
两种办法:
1.修改binlog_format格式为mixed;
登陆mysql,执行 set global binlog_format=MIXED; FLUSH LOGS;

注意:
如果是 master->slave 结构的数据库架构。并且 slave上开启了 log_slave_updates。那么在master上修改完binlog格式,开启了log_slave_updates的从库,会同布中断。
所以,需要先在 slave上,设置 binlog_format=mixed,之后再在master上设置。slave报错信息如下:
Last_SQL_Errno: 1666
Last_SQL_Error: Error executing row event: 'Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT.'

2.不要使用这类sql;

Puppet之安装dashboard 成功版

Puppet Dasshboard是由支持Puppet开发的公司Puppetlabs创建的,是Ruby on Rails程序。可以作为一个ENC(外部节点分类器)以及一个报告工具,并且正在逐渐成为一个包含许多Puppet新功能的集成界面,例如审计和资源管 理功能。 Puppet Dashboard是一个Ruby on Rails程序,用于显示Puppet master和agent的相关信息。它允许你查看从一个或多个Puppet master汇总的图形和报告数据。它同时从一个或者多个Puppet master上收集来自于Puppet agent的资产数据(主机的Fact和其他信息)。最后,它能作为一个ENC来配置Puppet节点,并指定这些节点上的类和参数。

Puppet 自定义facter 简述

在使用puppet作为配置管理工具的同时,facter是一个非常有用的系统盘点工具,自定义fact可以让节点增加更多的标签。这个工具可以通过一些预先设定好变量定位一台主机,比如可 以通过变量lsbdistrelease便可以知道当前系统的版本号,通过osfamily便可以知道系统是RedHat还是SLES,还是其它等等。但 是这些预先设定好的变量毕竟有限,在整个自动化运维过程中,由于系统应用的多样性,更多需要通过应用的名称、角色的名称进行标示,这样就需要自定义一些 fact并赋值到每个节点上去,相当于给节点打上标签。

Jeffrey带你一步步安装ORACLE_RAC STEP:TWO

说明:由于图片过于多没有一一截图,还望大家见谅。
3、集群的 Oracle Grid Infrastructure 的安装:

所需的oracle软件如下:

o 适用于 Linux 的 Oracle Database 11g 第 2 版 Grid Infrastructure (11.2.0.1.0)

o 适用于 Linux 的 Oracle Database 11g 第 2 版 (11.2.0.1.0)

o Oracle Database 11g 第 2 版 Examples(可选)

安装用于 Linux 的 cvuqdisk 程序包

在两个 Oracle RAC 节点上安装操作系统程序包 cvuqdisk。如果没有 cvuqdisk,集群验证实用程序就无法发现共享磁盘,当运行(手动运行或在 Oracle Grid Infrastructure 安装结束时自动运行)集群验证实用程序时,您会收到这样的错误消息:“Package cvuqdisk not installed”。使用适用于您的硬件体系结构(例如,x86_64 或 i386)的 cvuqdisk RPM。

cvuqdisk RPM 包含在 Oracle Grid Infrastructure 安装介质上的 rpm 目录中。
3.1 安装cvuqdisk

设置环境变量 CVUQDISK_GRP,使其指向作为 cvuqdisk 的所有者所在的组(本文为 oinstall):
[root@OceanI ~]# CVUQDISK_GRP=oinstall; export CVUQDISK_GRP
[root@OceanV ~]# CVUQDISK_GRP=oinstall; export CVUQDISK_GRP

在保存 cvuqdisk RPM 的目录中,使用以下命令在两个 Oracle RAC 节点上安装 cvuqdisk 程序包:
[root@OceanI rpm]# pwd
/data/grid/rpm
[root@OceanI rpm]# rpm -ivh cvuqdisk-1.0.7-1.rpm
[root@OceanV rpm]# rpm -ivh cvuqdisk-1.0.7-1.rpm

使用 CVU 验证是否满足 Oracle 集群件要求

记住要作为 grid 用户在将要执行 Oracle 安装的节点 (racnode1) 上运行。此外,必须为 grid 用户配置通过用户等效性实现的 SSH 连通性。

在grid软件目录里运行以下命令:

[root@OceanI grid]#$./runcluvfy.sh stage -pre crsinst -n OceanI,OceanV -fixup -verbose

使用 CVU 验证硬件和操作系统设置

[root@OceanI grid]#./runcluvfy.sh stage -post hwos -n OceanI,OceanV -verbose

查看 CVU 报告。CVU 执行的所有其他检查的结果报告应该为“passed”,之后才能继续进行 Oracle Grid Infrastructure 的安装。

3.2、为集群安装 Oracle Grid Infrastructure:
su - grid
#./runInstaller

此处省略 N 张图 ........

当弹出执行脚本的时候一定要先 local node 然后再remote node 切记不可一味图块

3.3、检验cluster安装是否成功

1.检查集群中的结点状态

2.检查SCAN是否产生,是否能ping通

3.检查所有服务的状态

4.检查ASM实例的状态

4、安装database soft & database
4.1、创建asm_group
su - grid
asmca

4.2、使用oracle用户调用图形界面进行安装Oracle Database
$./runInstaller

4.3、使用oracle用户调用dbca创建数据库
$dbca

4.4、查看整个集群状态
#crs_stat -t

其它注意事项:

1.给votedisk和ocr创建ASM时,如果选择normal模式,则需要3个ASM disk。

2.安装Oracle Grid Infrastructure的ORACLE_HOME目录与ORACLE_BASE目录不能存在从属关系;而安装Oracle Database的ORACLE_HOME又必须在ORACLE_BASE目录下。

5、部分错误整理:

错误1:

在第一个节点执行root.sh时报错:

error while loading shared libraries:libcap.so.1:cannot open shared object file: No such file or directory

解决办法:

确定libcap包已经安装

rpm -q libcap

find / -name '*libcap*' -print

创建链接

ln -s /lib64/libcap.so.2.16 /lib64/libcap.so.1

删掉root.sh的配置:

./roothas.pl -deconfig -verbose -force

再次运行root.sh即可。

错误2:

这个错误会在Redhat6.x/CentOS6.x上安装Oracle11gR2 11.2.0.1 RAC时出现。

在第一个节点执行root.sh时报错(各个节点都会出现这个问题):

Adding daemon to inittab

CRS-4124: Oracle High Availability Services startup failed.

CRS-4000: Command Start failed, or completed with errors.

解决办法:(临时)

在生成了文件/var/tmp/.oracle/npohasd文件后,使用root立即执行以下命令命令:

/bin/dd if=/var/tmp/.oracle/npohasd of=/dev/null bs=1024 count=1

如果懒得看npohasd有没有生成,就用下面的命令让它自动完成

watch -n 0.5 /bin/dd if=/var/tmp/.oracle/npohasd of=/dev/null bs=1024 count=1

错误3:

通过dbca方式, 在基于ASM存储建库时, 报以下错误:

ORA-12547: TNS:lost contact

原因:

In environment where listener home (including SCAN listener which resides in Grid Infrastructure/ASM home) and database home are owned by different OS user, ORA-12537 could happen when connecting through listener, when creating database through DBCA, or when installing database software and creating a database in runInstaller. Job Role Separation is a typical example as SCAN and local grid home listener is owned differently than database.

解决办法:

检查grid安装的SCAN listener目录和Oracle Database目录的owner是不是一样的。如果不一样,改成一样或将目录设置为770权限。