0%

灯光暗灭,前奏响起。那场执念多年的演唱会终于拉开了帷幕。

如我在开场时发的微博,那天虽然忙碌,可是安心坐下来的时候仍然怀疑他在合肥的演唱会真的能开始了吗,这场景本应存在于梦里才对。

演唱会当天仍然不可避免的忙碌。虽淡出许久,可是对于安徽的活动总是有些牵挂。而至于这份牵挂的由来,可能要追溯回2010年跟小伙伴们相识的年份吧。那一年的一场商演,我误打误撞的认识了那样的一群人。那时候的安徽分会,也在那群人秉承着的某种意志下建立起来了。

虽然那一年的商演最后由他的一句“不见不散”,变成了“因病缺席”。可是这一群人却变成了我年少时期几乎所有幸福的源头。于是他们所坚守的“安徽”也渐渐成为了我的执念。

故事的开头总是美好的,故事的结局也总是被想象的很美好。原本大家约定安排妥当后借着一场活动完美告别。可是因为一些不解与愤慨,最后这场告别以一群人的裸退收场。而当我面对这样一个大家曾经那么用心经营的地方时,心里却满满的惋惜。想着让它茁壮成长下去才对得起他们那么多年那么多的用心吧。虽然刚开始的那半年忍受过多不解,可是最后也算坚持下来了。而且经过这场演唱会的验收,的确现在那些年轻的孩子们已经做的很棒很让人欣慰了。

记得在这场演唱会只是公布行程的时候,就期待着能在奥体举办。因为他对这座场馆说过太多次的“不见不散”,但最终又因为各种说辞未能如约。甚至这场演唱会在开始前的一个月,都因为主办与经济公司之间的沟通不悦差点夭折,所以格外珍惜着最终的时线。更何况我曾听过从这座场馆里拨出的那么暖心连线的五月天,亲眼见过满场粉海的周杰伦,所以对于能在这里看到紫海便更加执念。

所谓圆梦与遗憾,大体是人生里面最磨人的小妖精了吧。这场看似圆梦的演唱会,也因为一些遗憾,让我更深刻的纪念着。

嗯,也谢谢今天所有的生日快乐。Love U U.

如我六月初申请离职时谈到的,自己总是一个对时间点比较在意的人:上半年的决定,总是希望能在上半年结束掉。所以很感激合肥公司的领导能理解我的固执,在六月的尾巴帮我成功离职了。

说到这家合肥的公司,我总是抱以最大的期许希望她能成功。因为我希望我的合肥有更多说得上的互联网公司(乐堂就不提了,瞧不上之);因为我曾参与其中,亲眼见证了一个产品诞生路上的坎坷。我也庆幸自己曾参与于这样一个创业团队,在这里我实实在在的开拓了视野。虽然因为自己个人的原因中途从中掉队,但离开后却不妨碍我祝福她。而最真切的祝福大概就是希望她发展的好到我以后会为我当下的决定后悔吧。

每天无事可做但工资尚可的上半年,自己陷入了一个很惶恐的心境。而从合肥离职后,算是结束了这样的生活。可能自己生来就是工作狂吧,竟发现13年在上海时,每天自己留下来加班的生活是最让自己热血沸腾的时候。所以赋闲下来之后,当上海的领导来找我时,我犹豫了一些日子最终答应了重新回来折腾一番。

回来的这段时间,果不其然有满满的工作安排,尤记得入职第一天面临扑面而来的任务时,内心亢奋的感觉,用一句话比喻就像是天晴了雨停了感觉自己又行了。就像后来调侃似的说,在这里两个星期做的事情,完全相当于在合肥待两年做的事情。只不过这里的忙碌也剥夺了平时学习的时间和热情,而且在推进工作计划过程中还会因为一些突发事件打乱自己的节奏。目前更多的是感觉自己像个消防员,工作起来还是很被动,没办法专注于自己的计划。希望接下来能适应这种节奏,然后看能不能改变公司现在面临的这种尴尬,不能总想着灭火才是。而对于另一个回来的原因,希望自己能如当初跟朋友聊天时所说的那样,保留好最初的想法,希望不会因为冲动而坏了念想。

寡欢清淡的上半年,和可想而知充实到死的下半年。这样的本命年还真的是让人印象深刻,也希望下一个本命年能因为现在的决定而变得更不一样。

2015.08.01

于上海

建立本地YUM源的初衷是按照自己的需求打包rpm包并在内网装机时直接部署。所以先来介绍一下RPM包的打包工具,我选择的是FPM来打包。

FPM on github:https://github.com/jordansissel/fpm

FPM安装

1
2
3
4
5
6
7
8
9
10
11
12
13
#FPM基于ruby开发,所以先yum安装ruby以及rubygems
yum install ruby rubygems ruby-devel ruby-rdoc rpm-build gcc -y

#删除默认RubyGems源并添加使用淘宝的RubyGems源
gem sources --remove http://rubygems.org/
gem sources -a https://ruby.taobao.org/
gem sources -l
*** CURRENT SOURCES ***

https://ruby.taobao.org
# 请确保只有 ruby.taobao.org

gem install fpm #使用gem安装fpm

FPM使用编译好的软件目录打包RPM,所以在打包之前,需要先编译好软件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
FPM常用打包命令解析(更多命令请fpm --help):
fpm -s dir \ #定义导入的是何种类型
-t rpm \ #定义输出的包是何种类型
-n smm-nginx \ #定义包的名称
-v 1.8.0 \ #定义版本信息
--iteration 1 \ #定义周期版本号
-d 'pcre >= 7.8' \ #定义依赖,可多次使用该参数
-d 'pcre-static >= 7.8' \
-d 'pcre-devel >= 7.8' \
-d 'openssl-perl >= 1.0.1e' \
-d 'openssl-static >= 1.0.1e' \
-d 'openssl >= 1.0.1e' \
-d 'openssl-devel >= 1.0.1e' \
-d 'openssl098e >= 0.9.8e' \
-m \ #定义维护者,一般留邮箱
--vendor SMM IT \ #定义RPM包的提供者
--description SMM Nginx Version \ #定义包的描述
--url http://www.smm.cn \ #定义链接
--before-install pre-nginx.sh \ #定义安装前运行的脚本,按需添加(此处需使用完整路径)
--after-remove \ #定义卸载后运行的脚本,按需添加(此处需使用完整路径)
--rpm-init nginx \ #定义安装后需要键入系统服务的运行脚本,按需添加(此处需使用完整路径)
/usr/local/webserver/nginx/ #定义编译后的程序路径

有了自定义的RPM之后,就可以自建本地yum源了

1
2
3
yum install createrepo -y
createrepo -p -d -o /yum/Packages/ /yum/Packages/ #新建源
createrepo --update /yum/Packages #更新源

前言

LVS(Linux Virtual Server)Linux虚拟服务器,是一个虚拟的服务器集群系统。本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一。通过LVS提供的负载均衡技术和Linux操作系统可实现一个高性能、高可用的服务器群集,从而以低成本实现最优的服务性能。

集群基础

集群简介

集群(Cluster)是一组相互独立的、通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理。一个客户与集群相互作用时,集群像是一个独立的服务器。集群配置是用于提高可用性和可缩放性。集群系统的主要优点:高可扩展性、高可用性、高性能、高性价比。

集群类型

LB:Load Balancing 高可拓展,伸缩集群
HA:High Availability 高可用集群
HP:High Performance 高性能集群

集群方案

LB:
硬件级:F5 BIG-IP、Citrix Netscaler、 A10 A10、Array、Redware
软件级:lvs (传输层)、haproxy, nginx (应用层)

HA:
heartbeat 、corosync + pacemaker、 cman + rgmanager、cman + pacemaker、keepalived

HP:
hadoop

LVS详解

LVS组成

ipvsadm:用于管理集群服务的命令行工具,工作于Linux系统中的用户空间。
ipvs:为lvs提供服务的内核模块,工作于内核空间

LVS术语

VIP:Director用来向外部提供服务的IP地址,也就是DNS通过域名解析到的IP
RIP:集群节点(后台真正提供服务的服务器)所使用的IP地址
DIP:Director用来和RIP进行交互的IP地址
CIP:客户端使用的IP或公网IP
RS:集群节点服务器Real server

LVS类型

LVS-NAT:Network Address Translation 网络地址转换
LVS-DR:Direct Routing 直连路由
LVS-TUN:Tunneling 隧道

LVS各类型特性

NAT类型的特性:
①RS应用使用私有地址,RS的网关必须指向DIP
②请求和响应都要经过Director,高负载场景中,Director易成为性能瓶颈
③支持端口映射
④RS可以使用任意OS

DR类型的特性:
①保证前端路由将目标地址为VIP的报文统统发往Directory,而不能是RS
解决方案:
(1) 静态地址绑定:在前端路由器上操作
前提:必须要有路由操作权限
(2) aprtables
(3) 修改RS上内核参数,将RS上的VIP配置在lo接口的别名上,并限制其不能响应对VIP地址解析请求

②RS可以使用私有地址,但也可以使用公网地址,此时可通过互联网通过RIP对其直接访问
③RS跟Directory必须在同一物理网络中
④请求报文经由Director,但响应报文必须不能经过Director
⑤不支持端口映射
⑥RS可以是大多数常见的OS
⑦RS的网关绝不允许指向DIP

TUN类型的特性:
①RIP、VIP、DIP全部是公网地址
②RS的网关不会也不可能指向DIP
③请求报文经由Director,但响应报文必须不能经过Director
④不支持端口映射
⑤RS的OS必须支持隧道功能

LVS调度算法

静态方法:仅根据调度算法本身进行调度

1
2
3
4
rr: round robin,轮流,轮询,轮叫
wrr: weighted round robin, 加权轮询
sh:source hashing,session绑定
dh: destination hashing, 目标地址hash

动态方法:根据算法及各RS当前的负载状况进行调度

1
2
3
4
5
6
lc: least connection,最少连接
wlc: weighted lc,加权最少连接
sed: shortest expection delay,最少期望延迟
nq: never queue,永不排队
lblc: Locality-Based Least Connection,基于局部性的最少连接
lblcr:Replicated lblc,基于局部性的带复制功能的最少连接

LVS配置(ipvsadm)

命令格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ipvsadm -A|E -t|u|f service-address [-s scheduler]
[-p [timeout]] [-M netmask]
ipvsadm -D -t|u|f service-address
ipvsadm -C
ipvsadm -R
ipvsadm -S [-n]
ipvsadm -a|e -t|u|f service-address -r server-address
[-g|i|m] [-w weight] [-x upper] [-y lower]
ipvsadm -d -t|u|f service-address -r server-address
ipvsadm -L|l [options]
ipvsadm -Z [-t|u|f service-address]
ipvsadm --set tcp tcpfin udp
ipvsadm --start-daemon state [--mcast-interface interface]
[--syncid syncid]
ipvsadm --stop-daemon state
ipvsadm -h

命令详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
定义集群服务:

-A 添加一个集群服务
-D 删除一个集群服务
-E 修改一个集群服务
-t VIP:端口 定义集群服务的类型为TCP的某个端口
-u VIP:端口 定义集群服务的类型为UDP的某个端口
-f 防火墙标记 定义集群服务的类型为防火墙标记
-s 调度算法 指定集群服务的调度算法
定义集群节点:
-a 添加一个节点到集群服务
-d 从集群服务中删除一个节点
-e 修改集群服务器中的节点
-r 节点IP:端口 定义节点的IP及类型
-m 定义为NAT模型
-g 定义为DR模型
-i 定义为TUN模型
-w 权重 定义服务器的权重
查看已经定义的集群服务及RS:
ipvsadm -L -n
-c: 查看各连接
--stats: 统计数据
--rate: 速率
--exact: 精确值
从集群服务中删除RS:
ipvsadm -d -t|u|f service-address -r server-address
删除集群服务:
ipvsadm -D -t|u|f service-address
清空所有的集群服务:
ipvsadm -C
保存集群服务定义:
ipvsadm -S > /path/to/some_rule_file
ipvsadm-save > /path/to/some_rule_file
让规则文件中的规则生效:
ipvsadm -R < /path/from/some_rule_file
ipvsadm-restore < /path/from/some_rule_file

LVS-NAT模型

配置过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#以下实验都是临时性配置,若要永久生效,请自行配置

Real Server 1
#ifconfig eth0 172.16.10.100/16 up
#route add default gw 172.16.10.12
Real Server 2
#ifconfig eth0 172.16.10.212/16 up
#route add default gw 172.16.10.12
Director Server
#ifconfig eth0 192.168.1.10/24 up
#ifconfig eth1 172.16.10.12/16 up
#yum -y install ipvsadm
#echo 1 > /proc/sys/net/ipv4/ip_forward
#ipvsadm -A -t 192.168.1.10:80 -s rr
#ipvsadm -a -t 192.168.1.10:80 -r 172.16.10.100 -m
#ipvsadm -a -t 192.168.1.10:80 -r 172.16.10.212 -m

LVS-DR模型

上面说了NAT模型的实现方式,但NAT模型有个缺陷,因为进出的每个数据包都要经过Director Server,当集群系统负载过大的时候Director Server将会成为整个集群系统的瓶颈,而DR模型就避免了这样的情况发生,DR模型在只有请求的时候才会经过Director Server, 回应的数据包由Real Server 直接响应用户不需要经过Director Server。

配置过程

1
2
3
4
5
6
7
8
内核参数:
arp_ignore: 定义接收到ARP请求时的响应级别
0:只要本地配置的有相应地址,就给予响应
1:仅在请求的目标地址配置请求到达的接口上的时候,才给予响应
arp_announce:定义将自己地址向外通告时的通告级别
0:将本地任何接口上的任何地址向外通告
1:试图仅向目标网络通告与其网络匹配的地址
2:仅向与本地接口上地址匹配的网络进行通告
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Real Server 1
#ifconfig eth0 172.16.10.100/16 up
#echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_ignore
#echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
#echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
#echo 2 > /proc/sys/net/ipv4/conf/eth0/arp_announce
#ifconfig lo:0 192.168.1.10 netmask 255.255.255.255 broadcast 192.168.1.10 up
#route add -host 192.168.1.10 dev lo:0
Real Server 2
#ifconfig eth0 172.16.10.212/16 up
#echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_ignore
#echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
#echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
#echo 2 > /proc/sys/net/ipv4/conf/eth0/arp_announce
#ifconfig lo:0 192.168.1.10 netmask 255.255.255.255 broadcast 192.168.1.10 up
#route add -host 192.168.1.10 dev lo:0
Director Server
#ifconfig eth0 172.16.10.12/16 up
#ifconfig eth0:0 192.168.1.10 netmask 255.255.255.255 broadcast 192.168.1.10 up
#echo 1 > /proc/sys/net/ipv4/ip_forward
#route add -host 192.168.1.10 dev eth0:0
#yum install ipvsadm -y
#ipvsadm -A -t 192.168.1.10:80 -s rr
#ipvsadm -a -t 192.168.1.10:80 -r 172.16.10.100 -g
#ipvsadm -a -t 192.168.1.10:80 -r 172.16.10.212 -g

基于LVS实现web服务器负载均衡

实验拓扑

环境介绍

系统环境:CentOS6.6
Director Server:192.168.1.10(VIP) 172.16.10.12(DIP)
Real Server 1:192.168.1.10(VIP) 172.16.10.100(RIP)
Real Server 2:192.168.1.10(VIP) 172.16.10.212(RIP)

PHP服务器:172.16.10.110 

NFS服务器:172.16.10.110

数据库服务器:172.16.10.211

要求:web服务器上部署discuz,基于LVS实现负载均衡

NFS服务器配置

创建共享目录,并设置权限

编辑配置文件,设置共享目录及客户端

1
2
[root@scholar ~]# vim /etc/exports 
/web/discuz 172.16.10.100(rw,sync) 172.16.10.212(rw,sync)

站点文件准备

1
2
3
4
[root@scholar ~]# unzip Discuz_7.2_FULL_SC_GBK.zip
[root@scholar ~]# chmod -R 777 upload
[root@scholar ~]# mv upload/* /web/discuz/
[root@scholar ~]# chown -R apache.apache /web/discuz

启动服务,设置开机自启

数据库服务器配置

RS1和RS2配置

配置VIP

配置虚拟主机

1
2
3
4
5
6
7
[root@RS1 ~]# vim /etc/httpd24/extra/httpd-vhosts.conf 

<VirtualHost *:80>
DocumentRoot "/web/discuz"
ProxyRequests Off
ProxyPassMatch ^/(.*\.php)$ fcgi://172.16.10.110:9000/web/discuz/$1
</VirtualHost>

挂载共享目录

1
2
3
4
#可设置开机自动挂载
[root@scholar ~]# vim /etc/fstab

172.16.10.110:/web/discuz /web/discuz nfs defaults,_netdev 0 0

检查语法,启动服务

Director Server配置

配置VIP

定义集群

安装测试及访问测试

安装完成,我们来发一个帖子测试一下

过一会儿,刷新一下页面

此过程中是否实现了负载均衡,我们在Director Server上查看一下是哪台服务器响应的请求就知道了

由此可见,基于LVS实现web服务器的负载均衡功能已完成

The end

OK,基于LVS的负载均衡就说到这里了,负载均衡集群的配置还是比较简单的,几条命令就搞定了,不要因为简单看一眼就略过,只有理解原理结合实践才能真正掌握知识,配置过程中遇到问题可留言呦。以上仅为个人学习整理,如有错漏,大神勿喷~~~

转载自:http://www.178linux.com/archives/4855

好久没更关于zabbix的东西了,今天完善了一下内网zabbix监控的邮件告警功能。

这里就不赘述使用服务器自带邮件发信了,直接介绍使用maix联合自有常用邮箱实现发送邮件的功能。

  • 配置发信功能

首先使用which mailx检查服务器是否安装mailx,若没有安装直接yum安装。

然后编辑其配置文件,在末尾加上发信邮箱等信息

1
2
3
4
5
vim /etc/mail.rc
#For zabbix media
set from=你的邮箱 smtp=你的邮箱smtp服务器
set smtp-auth-user=你的邮箱 smtp-auth-password=邮箱密码
set smtp-auth=login

测试新加的配置信息是否正常

1
echo "zabbix test mail" |mail -s "zabbix" yyy@qq.com

若QQ邮箱成功收信,则配置成功

  • 配置zabbix

1.新建媒介

点击Administration→Media types→Create media type

Type选择Script,根据自己习惯,自定义Name字段以及Script name字段。其中Script name字段为待会新建的发信脚本名称。

2.设置报警邮箱

点击Administration→Users,选择Members列的用户,为其配置Media

3.设置报警触发行为

点击Configuration→Actions,我们可以直接修改现有的Report problems to Zabbix administrators。选择Opreations页,Edit现有的触发行为,注意修改如下几项并最后update

4.编辑发信脚本

zabbix默认脚本目录位于zabbix安装目录下的share/zabbix/alertscripts。我们在这里新建一个前面命名的mail.sh文件,内容如下

1
2
#!/bin/sh
echo "$3" | mail -s "$2" $1

若该脚本发信时,邮箱收到的中文显示乱码,且正文为空,同时显示收到一个命名规则为tcmime.***.***.***.bin的附件,可yum安装dos2unix

1
2
3
4
5
6
#!/bin/bash
export LANG=zh_CN.UTF-8
FILE=/tmp/mailinfo.txt
echo "$3" >$FILE
dos2unix -k $FILE
mail -s "$2" $1 < $FILE

保存并修改脚本所属用户以及赋予执行权限

1
2
chown zabbix zabbix mail.sh
chmod +x mail.sh
  • 测试报警

关闭监控服务器上的zabbix_agentd,等待若干分钟会收到错误报警的邮件。开启zabbix_agentd,等待若干分钟会收到服务恢复的邮件。

锋寒 技术保障 基础平台 技术专家

 

在Linux上做网络应用的性能优化时,一般都会对TCP相关的内核参数进行调节,特别是和缓冲、队列有关的参数。网上搜到的文章会告诉你需要修改哪些参数,但我们经常是知其然而不知其所以然,每次照抄过来后,可能很快就忘记或混淆了它们的含义。本文尝试总结TCP队列缓冲相关的内核参数,从协议栈的角度梳理它们,希望可以更容易的理解和记忆。注意,本文内容均来源于参考文档,没有去读相关的内核源码做验证,不能保证内容严谨正确。作为Java程序员没读过内核源码是硬伤。

下面我以server端为视角,从 连接建立、 数据包接收 和 数据包发送 这3条路径对参数进行归类梳理。

一、连接建立

简单看下连接的建立过程,客户端向server发送SYN包,server回复SYN+ACK,同时将这个处于SYN_RECV状态的连接保存到半连接队列。客户端返回ACK包完成三次握手,server将ESTABLISHED状态的连接移入accept队列,等待应用调用accept()。

可以看到建立连接涉及两个队列:

  • 半连接队列,保存SYN_RECV状态的连接。队列长度由net.ipv4.tcp_max_syn_backlog设置
  • accept队列,保存ESTABLISHED状态的连接。队列长度为min(net.core.somaxconn, backlog)。其中backlog是我们创建ServerSocket(int port,int backlog)时指定的参数,最终会传递给listen方法:
1
2
#include 
int listen(int sockfd, int backlog);

如果我们设置的backlog大于net.core.somaxconn,accept队列的长度将被设置为net.core.somaxconn

另外,为了应对SYN flooding(即客户端只发送SYN包发起握手而不回应ACK完成连接建立,填满server端的半连接队列,让它无法处理正常的握手请求),Linux实现了一种称为SYN cookie的机制,通过net.ipv4.tcp_syncookies控制,设置为1表示开启。简单说SYN cookie就是将连接信息编码在ISN(initial sequence number)中返回给客户端,这时server不需要将半连接保存在队列中,而是利用客户端随后发来的ACK带回的ISN还原连接信息,以完成连接的建立,避免了半连接队列被攻击SYN包填满。对于一去不复返的客户端握手,不理它就是了。

二、数据包的接收

先看看接收数据包经过的路径:

数据包的接收,从下往上经过了三层:网卡驱动、系统内核空间,最后到用户态空间的应用。Linux内核使用sk_buff(socket kernel buffers)数据结构描述一个数据包。当一个新的数据包到达,NIC(network interface controller)调用DMA engine,通过Ring Buffer将数据包放置到内核内存区。Ring Buffer的大小固定,它不包含实际的数据包,而是包含了指向sk_buff的描述符。当Ring Buffer满的时候,新来的数据包将给丢弃。一旦数据包被成功接收,NIC发起中断,由内核的中断处理程序将数据包传递给IP层。经过IP层的处理,数据包被放入队列等待TCP层处理。每个数据包经过TCP层一系列复杂的步骤,更新TCP状态机,最终到达recv Buffer,等待被应用接收处理。有一点需要注意,数据包到达recv Buffer,TCP就会回ACK确认,既TCP的ACK表示数据包已经被操作系统内核收到,但并不确保应用层一定收到数据(例如这个时候系统crash),因此一般建议应用协议层也要设计自己的确认机制。

上面就是一个相当简化的数据包接收流程,让我们逐层看看队列缓冲有关的参数。

1.网卡Bonding模式

当主机有1个以上的网卡时,Linux会将多个网卡绑定为一个虚拟的bonded网络接口,对TCP/IP而言只存在一个bonded网卡。多网卡绑定一方面能够提高网络吞吐量,另一方面也可以增强网络高可用。Linux支持7种Bonding模式:

  • Mode 0 (balance-rr) Round-robin策略,这个模式具备负载均衡和容错能力
  • Mode 1 (active-backup) 主备策略,在绑定中只有一个网卡被激活,其他处于备份状态
  • Mode 2 (balance-xor) XOR策略,通过源MAC地址与目的MAC地址做异或操作选择slave网卡
  • Mode 3 (broadcast) 广播,在所有的网卡上传送所有的报文
  • Mode 4 (802.3ad) IEEE 802.3ad 动态链路聚合。创建共享相同的速率和双工模式的聚合组
  • Mode 5 (balance-tlb) Adaptive transmit load balancing
  • Mode 6 (balance-alb) Adaptive load balancing

 

详细的说明参考内核文档Linux Ethernet Bonding Driver HOWTO。我们可以通过cat /proc/net/bonding/bond0查看本机的Bonding模式:

一般很少需要开发去设置网卡Bonding模式,自己实验的话可以参考这篇文档

2.网卡多队列及中断绑定

随着网络的带宽的不断提升,单核CPU已经不能满足网卡的需求,这时通过多队列网卡驱动的支持,可以将每个队列通过中断绑定到不同的CPU核上,充分利用多核提升数据包的处理能力。

首先查看网卡是否支持多队列,使用lspci -vvv命令,找到Ethernet controller项:

如果有MSI-X, Enable+ 并且Count > 1,则该网卡是多队列网卡。

然后查看是否打开了网卡多队列。使用命令cat /proc/interrupts,如果看到eth0-TxRx-0表明多队列支持已经打开:

最后确认每个队列是否绑定到不同的CPU。cat /proc/interrupts查询到每个队列的中断号,对应的文件/proc/irq/${IRQ_NUM}/smp_affinity为中断号IRQ_NUM绑定的CPU核的情况。以十六进制表示,每一位代表一个CPU核:

1
2
3
(00000001)代表CPU0
(00000010)代表CPU1
(00000011)代表CPU0和CPU1

如果绑定的不均衡,可以手工设置,例如:

1
2
3
4
5
6
7
8
echo "1" > /proc/irq/99/smp_affinity  
echo "2" > /proc/irq/100/smp_affinity
echo "4" > /proc/irq/101/smp_affinity
echo "8" > /proc/irq/102/smp_affinity
echo "10" > /proc/irq/103/smp_affinity
echo "20" > /proc/irq/104/smp_affinity
echo "40" > /proc/irq/105/smp_affinity
echo "80" > /proc/irq/106/smp_affinity

3.Ring Buffer

Ring Buffer位于NIC和IP层之间,是一个典型的FIFO(先进先出)环形队列Ring Buffer没有包含数据本身,而是包含了指向sk_buffsocket kernel buffers)的描述符。

可以使用ethtool -g eth0查看当前Ring Buffer的设置:

上面的例子接收队列为4096,传输队列为256。可以通过ifconfig观察接收和传输队列的运行状况:

        1.RX errors: 收包总的错误数

        2.RX dropped: 表示数据包已经进入了Ring Buffer,但是由于内存不够等系统原因,导致在拷贝到内存的过程中被丢弃。

        3.RX overruns: overruns意味着数据包没到Ring Buffer就被网卡物理层给丢弃了,而CPU无法及时的处理中断是造成Ring Buffer满的原因之一,例如中断分配的不均匀。当dropped数量持续增加,建议增大Ring Buffer,使用ethtool -G进行设置。

4.Input Packet Queue(数据包接收队列)

当接收数据包的速率大于内核TCP处理包的速率,数据包将会缓冲在TCP层之前的队列中。接收队列的长度由参数net.core.netdev_max_backlog设置。

5.recv Buffer

recv buffer是调节TCP性能的关键参数。BDP(Bandwidth-delay product,带宽延迟积) 是网络的带宽和与RTT(round trip time)的乘积,BDP的含义是任意时刻处于在途未确认的最大数据量。RTT使用ping命令可以很容易的得到。为了达到最大的吞吐量,recv Buffer的设置应该大于BDP,即recv Buffer >= bandwidth * RTT。假设带宽是100Mbps,RTT是100ms,那么BDP的计算如下:

1
BDP = 100Mbps * 100ms = (100 / 8) * (100 / 1000) = 1.25MB

Linux在2.6.17以后增加了recv Buffer自动调节机制,recv buffer的实际大小会自动在最小值和最大值之间浮动,以期找到性能和资源的平衡点,因此大多数情况下不建议将recv buffer手工设置成固定值。

net.ipv4.tcp_moderate_rcvbuf设置为1时,自动调节机制生效,每个TCP连接的recv Buffer由下面的3元数组指定:

1
net.ipv4.tcp_rmem =   

最初recv buffer被设置为,同时这个缺省值会覆盖net.core.rmem_default的设置。随后recv buffer根据实际情况在最大值和最小值之间动态调节。在缓冲的动态调优机制开启的情况下,我们将net.ipv4.tcp_rmem的最大值设置为BDP

net.ipv4.tcp_moderate_rcvbuf被设置为0,或者设置了socket选项SO_RCVBUF,缓冲的动态调节机制被关闭。recv buffer的缺省值由net.core.rmem_default设置,但如果设置了net.ipv4.tcp_rmem,缺省值则被覆盖。可以通过系统调用setsockopt()设置recv buffer的最大值为net.core.rmem_max。在缓冲动态调节机制关闭的情况下,建议把缓冲的缺省值设置为BDP

注意这里还有一个细节,缓冲除了保存接收的数据本身,还需要一部分空间保存socket数据结构等额外信息。因此上面讨论的recv buffer最佳值仅仅等于BDP是不够的,还需要考虑保存socket等额外信息的开销。Linux根据参数net.ipv4.tcp_adv_win_scale计算额外开销的大小:

如果net.ipv4.tcp_adv_win_scale的值为1,则二分之一的缓冲空间用来做额外开销,如果为2的话,则四分之一缓冲空间用来做额外开销。因此recv buffer的最佳值应该设置为:

三、数据包的发送

发送数据包经过的路径:

和接收数据的路径相反,数据包的发送从上往下也经过了三层:用户态空间的应用、系统内核空间、最后到网卡驱动。应用先将数据写入TCP send buffer,TCP层将send buffer中的数据构建成数据包转交给IP层。IP层会将待发送的数据包放入队列QDisc(queueing discipline)。数据包成功放入QDisc后,指向数据包的描述符sk_buff被放入Ring Buffer输出队列,随后网卡驱动调用DMA engine将数据发送到网络链路上。

同样我们逐层来梳理队列缓冲有关的参数。

1.send Buffer

recv Buffer类似,和send Buffer有关的参数如下:

1
2
3
net.ipv4.tcp_wmem =   
net.core.wmem_default
net.core.wmem_max

发送端缓冲的自动调节机制很早就已经实现,并且是无条件开启,没有参数去设置。如果指定了tcp_wmem,则net.core.wmem_defaulttcp_wmem的覆盖。send Buffertcp_wmem的最小值和最大值之间自动调节。如果调用setsockopt()设置了socket选项SO_SNDBUF,将关闭发送端缓冲的自动调节机制,tcp_wmem将被忽略,SO_SNDBUF的最大值由net.core.wmem_max限制。

2.QDisc

QDisc(queueing discipline )位于IP层和网卡的ring buffer之间。我们已经知道,ring buffer是一个简单的FIFO队列,这种设计使网卡的驱动层保持简单和快速。而QDisc实现了流量管理的高级功能,包括流量分类,优先级和流量整形(rate-shaping)。可以使用tc命令配置QDisc

QDisc的队列长度由txqueuelen设置,和接收数据包的队列长度由内核参数net.core.netdev_max_backlog控制所不同,txqueuelen是和网卡关联,可以用ifconfig命令查看当前的大小:

使用ifconfig调整txqueuelen的大小:

1
ifconfig eth0 txqueuelen 2000

3.Ring Buffer

和数据包的接收一样,发送数据包也要经过Ring Buffer,使用ethtool -g eth0查看:

其中TX项是Ring Buffer的传输队列,也就是发送队列的长度。设置也是使用命令ethtool -G

4.TCP Segmentation和Checksum Offloading

操作系统可以把一些TCP/IP的功能转交给网卡去完成,特别是Segmentation(分片)和checksum的计算,这样可以节省CPU资源,并且由硬件代替OS执行这些操作会带来性能的提升。

一般以太网的MTU(Maximum Transmission Unit)为1500 bytes,假设应用要发送数据包的大小为7300bytes,MTU1500字节 - IP头部20字节 - TCP头部20字节=有效负载为1460字节,因此7300字节需要拆分成5个segment:

Segmentation(分片)操作可以由操作系统移交给网卡完成,虽然最终线路上仍然是传输5个包,但这样节省了CPU资源并带来性能的提升:

可以使用ethtool -k eth0查看网卡当前的offloading情况:

上面这个例子checksum和tcp segmentation的offloading都是打开的。如果想设置网卡的offloading开关,可以使用ethtool -K(注意K是大写)命令,例如下面的命令关闭了tcp segmentation offload:

1
sudo ethtool -K eth0 tso off

5.网卡多队列和网卡Bonding模式

在数据包的接收过程中已经介绍过了

至此,终于梳理完毕。整理TCP队列相关参数的起因是最近在排查一个网络超时问题,原因还没有找到,产生的“副作用”就是这篇文档。再想深入解决这个问题可能需要做TCP协议代码的profile,需要继续学习,希望不久的将来就可以再写文档和大家分享了。

 

参考文档

Queueing in the Linux Network Stack

TCP Implementation in Linux: A Brief Tutorial

Impact of Bandwidth Delay Product on TCP Throughput

Java程序员也应该知道的系统知识系列之网卡

说说网卡中断处理

 

原文链接:http://blog.sina.com.cn/s/blog_e59371cc0102vg4n.html

  • 前言

一年一度的春晚再次落下帷幕,而微博也顺利地陪伴大家度过除夕之夜。

谈及马年春晚,人们首先想到的不是春晚上精彩的节目,而是微博上的吐槽,边看春晚,边刷微博,边吐槽,已经成了国人的习惯。看春晚不再是为了看节目,而是为了能够在微博上吐槽,知道大家在吐槽什么,更有人戏称不是春晚成就了微博,而是微博拯救了春晚。

马年春晚又格外引人注目,不仅仅是因为冯小刚亲自坐镇,担当总导演,更值得一提的是本届春晚首次将社交平台作为其与观众互动的主要途径,而新浪微博更是成为官方二维码独家合作方。在节目播出时,用户通用手机客户端,扫描屏幕右下角的官方二维码,即可参与春晚的话题讨论。不仅如此,参与讨论的观众,还可以免费获得微博红包,抽大奖的机会。如此一来,大大的提升了微博的活跃度瞬间提升,同时在线人数翻了几倍,给微博系统带来前所未有的访问压力。

根据以往统计的数据,春晚期间微博的访问量将激增到日常水平的数倍之多,而瞬时发表量更是飙升数十倍,如此场景丝毫不亚于淘宝双11和12306抢票时的“盛况”。

而最后的统计数据结果表明,马年春晚直播期间,微博的访问量和发表量都再创新高,而我们系统也自始至终平稳运行,经受住了此次高峰的考验。这成功的背后,是我们的工程师将近一个月的努力。其间面临了哪些问题,又是如何解决的呢?下面,我们一一为大家揭秘。

  • 挑战1:如何应对数倍于日常访问量的压力?

每年春运抢票时,12306都会崩溃;淘宝双11时,也会有短暂的购买失败的情况。究其原因还是,有限的服务器资源难以承受上千万人同时在线访问。同样,春晚的时候,微博的访问量也会激增,同时在线人数到达日常的数倍之多。面对突然增长的访问压力,大部分互联网公司都会临时扩容来加以应对,同样我们也需要进行扩容。那么如何进行扩容?哪些部分需要扩容?具体扩容多少?这都是厄需解决的问题。

需要提到一点的是,微博目前线上部署了几千台服务器,来保障日常的正常访问。假如面对原来数倍的访问压力时,如果简单粗暴通过线性扩容来应对的话,需要部署原来数倍的服务器,也就是需要上万台服务器。无论从硬件成本还是从管理成本上,这都是不可接受的。那么,又该如何做呢?

在线压测,找极限,最小化扩容前端机

众所周知,为了尽可能的保障线上运行的服务器的稳定,资源都是有一定冗余度的,一般安全值在30%以上。在面临5倍的访问量时,出于成本的考虑,单纯的扩容难以令人接受。这个时候,就要充分利用每台服务器,在不影响业务性能的前提下,使每台服务器的利用率发挥到极限,可以极大的降低资源扩容的数量。如何评估服务器的承受极限是其中的关键,为此我们在业务低峰时期,对线上的服务器进行了实际的压测。具体方法如下:

假如线上一个服务池里有300台 tomcat服务器在提供API服务,正常情况下,每台服务器的负载都小于1(为了简化模型,我们这里只提到了系统load这个指标,实际情况要比这个复杂的多,还要考虑CPU 利用率、带宽、io延迟等)。通过运维系统,我们以10%、20%、30%、40%、50%等比例逐步将该服务池里的300台 tomcat 机器503,通过观察一台 tomcat 服务器的负载以及 API 服务的接口性能,当服务器的负载达到极限或者 API 服务的接口性能达到阈值时,假设此时服务池里正常状态的 tomcat 服务器的数量是100台,那么我们就可以推断出该服务池,极限情况下可以承受3倍与日常的访问压力。同理,为了承担5倍的访问量,只需再扩容一倍机器即可。

  • 挑战2:如何应对瞬时可达几万/s 的发表量?

互联网应用有个显著特点,就是读多写少。针对读多有很多成熟的解决方案,比如可以通过cache 来缓存热数据来降低数据库的压力等方式来解决。而对于写多的情况,由于数据库本身写入性能瓶颈,相对较难解决。

微博系统在处理发表微博时,采用了异步消息队列。具体来讲,就是用户发表微博时,不是直接去更新数据库和缓存,而是先写入到 mcq消息队列中。再通过队列机处理程序读取消息队列中的消息,再写入到数据库和缓存中。那么,如何保证消息队列的读写性能,以及如何保证队列机处理程序的性能,是系统的关键所在。

按消息大小设置双重队列,保证写入速度。

众所知之,微博最大长度不超过140个字,而大部分用户实际发表的微博长度都比较小。为了提高写入消息队列的速度,我们针对不同长度的微博消息,写入不同大小的消息队列。比如以512字节为分界线,大于512字节的写入长队列,小于512字节的写入短队列,其中短队列的单机写入性能要远远高于长队列。实际在线结果表明,短队列的QPS 在万/s 级别,长队列的QPS 在千/s 级别,而99%的微博消息长度均小于512字节。这种优化,大大提高了微博消息的写入和读取性能。

堵塞队列,压队列机极限处理能力。

为了验证队列机处理程序的极限处理能力,我们在业务低峰时期,对线上队列机进行了实际的压测,具体方法如下:

通过开关控制,使队列机处理程序停止读取消息,从而堵塞消息队列,使堆积的消息分别达到10万,20万,30万,60万,100万,然后再打开开关,使队列机重新开始处理消息,整个过程类似于大坝蓄水,然后开闸泄洪,可想而知,瞬间涌来的消息对队列机将产生极大的压力。通过分析日志,来查找队列机处理程序最慢的地方,也就是瓶颈所在。

通过两次实际的压测模拟,出乎意料的是,我们发现系统在极限压力下,首先达到瓶颈的并非是数据库写入,而是缓存更新。因此,为了提高极限压力下,队列机处理程序的吞吐量,我们对一部分缓存更新进行了优化。

  • 挑战3:如何保证系统的可靠性?

无论是发微博,还是刷 feed,在微博系统内的处理过程都十分复杂,依赖着各种内部资源和外部服务,保证系统的可靠性显得尤为困难。

为此,我们内部开发了代号为试金石——TouchStone的压测系统,对系统的可靠性进行全面检测。

首先,我们对微博的各个接口进行了服务依赖和资源依赖的梳理,并针对每个服务和资源定义了相应的 SLA 和降级开关。然后,模拟资源或者服务出现异常,再来查看其对接口性能的影响。以 redis资源为例, 假设系统定义了redis的 SLA是300ms,相应的端口是6379,通过 TouchStone,使该端口不可用,从而模拟 redis 资源出现异常,然后验证依赖该资源的接口的性能,确保 SLA 。同时,通过降级开关,对该资源进行降级,验证降级开关的有效。

基于以上方法,对系统进行了全面的检测,并对各个服务和资源的 SLA 和降级开关进行梳理,总结成业务降级手册,保证在出现问题时,运维人员无需开发的介入,也能第一时间根据降级手册进行降级,确保问题能够尽快解决。

  • 挑战4:如何保证核心系统的稳定性?

任何一个系统,都包含核心系统和非核心系统。在出现异常的情况下,弃车保帅,只保障核心系统的稳定性也是可以接受的。

为此,我们降核心接口和非核心接口拆分,部分部署到不同的应用池子当中,确保非核心业务不会影响核心业务。比如发微博和刷 feed 属于核心业务,而评论,赞属于非核心业务,所以两者应当部署到不同的应用池中。在评论或者赞出现异常时,发微博和刷 feed 就不会受到影响,从而保障系统核心业务的稳定性。

同样,对于一个业务,也要区分核心逻辑和非核心逻辑。以发微博为例,更新缓存和写数据库属于核心逻辑,而给其它业务部门推送数据则属于非核心逻辑。因此,可以将推送数据进行异步化处理,交给单独的线程池处理,在出现异常时,不会对更新缓存和写数据库造成影响。

  • 挑战5:如何做到异地容灾?

近些年来,异地容灾成为全球性互联网企业面临的难题之一。无论是在国内,以微信为例,还是在国外,以 twitter 为例,都曾经出现过全球性宕机的事故。由此可见,异地容灾仍旧是一个挑战。

微博早在2010年就开始了多机房的部署,如今已经具备三大机房(分别针对联通、电信和海外用户)。

由于人为或者天气等不可抗拒因素,网络故障近年来时有发生。微博的三个机房,各自独立承担了一部分用户的访问。在一个机房出现故障或者压力过大的时候,通过DNS切换等手段,将流量迁移到另外两个机房,从而确保该访问该机房的用户不受影响。一个现实的情况例子,在马年春晚直播期间,由于观看人群的地域分布的特点,出现了联通机房的访问量突增,同时在线人数的增长超过了电信机房和广州机房,我们通过切换一部分联通机房的流量到电信机房,使得联通机房的负载降到了安全值的范围。

  • 挑战6:如何实时监控系统状态?

我们都知道,地震的发生都是有前兆的,比如一些动物的异常反应。同样,系统中的任何问题出现之前,也是有线索可寻的。这就需要对系统的关键指标做实时的监控,当指标出现异常时,能够第一时间发出报警信息。

为此,我们基于实时流处理系统 Storm 开发了一套监控系统——dashboard。有别于以往的监控系统,它能实时处理系统产生的海量日志,绘制出更加直观的曲线,方便运维进行管理。通过 dashborad,我们能够了解系统的实时状态,主要包括feed的访问量、微博的发表量、队列机的处理性能,消息队列的堆积量等指标。当某个监控指标出现异常时,能够第一时间在 dashboard 中反映出来,从而第一时间采取措施,解决问题,避免问题扩大化。

  • 后记

春晚已经过去一个月了,渐渐成为回忆。但春晚背后,我们的工程师所付出的巨大的努力所产生的价值,却是一笔宝贵的财富,希望这篇文章能给大家带来启发甚至帮助,也在此向为微博春晚默默贡献的工程师们致敬!

  • 关于作者

胡忠想(微博昵称:@古月中心相心),目前任职于新浪微博的平台研发部门,主要负责微博 Feed 服务相关工作,曾先后参与微博 Feed 存储、微博计数器、微博阅读数等重大业务产品的开发。2012年3月份毕业于北京航空航天大学计算系,同年4月份,加入新浪微博并工作至今。业余爱好户 外,曾徒步过贡嘎、雨崩,攀登过四姑娘三峰。

感谢张凯峰对本文的审校。

原文链接:http://www.infoq.com/cn/articles/technical-story-behind-the-spring-festival-weibo

编者按:经过2014年一年的酝酿,2015微信红包总量创下历史新高,峰值1400万次/秒,8.1亿次每分钟,微信红包收发达10.1亿次,系统整体运行平稳, 在这里我分享下微信红包背后的技术。

  • 核心功能&目标

首先,了解下微信红包的4个逻辑:摇/发/抢/拆。看似简单,实现可不简单再review下微信红包要实现目标:

摇:摇的流畅

快:抢的要快

爽:拆的爽

稳:能分享出去

  • 系统难点:

1.中国运营商网络环境复杂,覆盖面广,春节期间网络吃紧,容易出现网络故障

2.在尖峰摇时如何避免服务雪崩

3.在服务资源有限时,如何提供柔性服务

4.如何构造有损服务

5.如何构造set模型

6.如何解决并发抢

7.如何实现实现数据一致性

  • 系统整体架构图

  • 跨区域网络解决方案

微信客户端分布全球,接入点较多,用户资料靠近接入点,可以加速用户资料访问,但是红包的业务逻辑层并不全网分布,业务逻辑层访问数据层比较多,数据层有状态强一致性问题,只能同用一个数据副本,比如上海用户与深圳用户在同个群里,抢同一个红包,如果订单数据在上海与深圳都有,在抢的时候,无法保证数据同步,可用性低,所以,设计系统时,一定要梳理清楚系统间的调用关系,优化接入层的业务逻辑,把网络耗时降到最小,系统吞吐量才能提升。

跨区域网络问题,在物理实施上,也需要有备份绕行的能力,这个可以在系统的底层框架中实现,当指定专线出现故障时,快速切换网络,恢复服务

  • 如何构建有损服务

什么是有损服务?选择性牺牲一部分数据一致性和完整性从而保证核心功能绝大多数运行,经过一段时间窗口,数据一致性与完整性能得以恢复,这也是腾讯的一直运营策略,在有限资源前提下,量力而为,满足用户的核心需求

比如,春晚摇一摇,我们的核心点是摇/拆/分享,那系统的资源优先需要保证这些服务的响应,任何关联系统出现异常的时候马上进行系统降级,防止引起系统雪崩。

系统降级可以分为两个方面,一是把核心功能调用链路简化,减少依赖,通过辅助轻量化的服务实现,确保最短关键路径的可行,比方说在接入层置入摇红包逻辑,将每秒千万级请求转化为每秒万级的红包请求,再传到红包服务的后端逻辑,降低雪崩的可能性。

  • 柔性服务.打造好的产品体验

柔性可用是在有损服务价值观支持下的方法,重点在于实际上会结合用户使用场景,根据资源消耗,调整产品策略,设计几个级别不同的用户体验场景,保证尽可能成功返回关键数据,并正常接受请求,绝不轻易倒下。

比如,红包的核心功能拆,拆完需要记录用户头像昵称,转帐资金划转,同时输出同个订单下其它拆记录,拆过程这些操作都可能失败,但是核心操作获取红包是成功的,此时,我们至少可以告诉用户抢到金额,不至于让用户焦急等待,不断重试,未完成的操作(头像补全与资金转帐),可以通异步补尝方式重试。这样解决了用户的问题,也缓解了系统压力。

  • 如何构造set模型

Set模块就像一个集装箱,把各模块标准化,模块化,规模化,它为海量服务运营,特别是设备管理、网络架构,提供了宏观运营支撑框架,从而极大提高了海量服务运营效率。

微信红包的set模块,以拆服务为例,从接入层开始,数据开始sticky,按订单号路由,即按单号分set,同一个set尽可能在一个IDC 里,减少模块间调用的耗时,在同一个set内,逻辑层任何一台机器,调用方可实时摘除,如果是数据层发生故障,先在接入层,把新产生的红包订单号屏蔽有故障对应的set编号,比如,set1 数据库出现故障,为了避免在故障的set1 上继续产生新的支付请求,在订单生成器直接跳过set1的单号规则,把新请求导致其它set, 只有未抢完的部分红包,会提示故障,稍后恢复,阻止了故障引发的进一步恶化,在故障db上的数据,通过备机与业务逻辑层的数据核对,完成数据一致性的修复。

  • 如何解决并发抢

群里红包的规则是金额随机抢,在一个大群发一个红包出去,抢并发请求量高,在同一个资源上操作,需要增加锁操作,避免一个抢总数超过发送红包总数,众所周所,mysql的加锁操作,很多抢在一个锁上等,性能损耗大,吞吐量下降,对于海量服务的操作,是不能满足要求。

在set模块的基础上,我们把发/抢的资源请求都会落到同一个资源set,在最外层,cache红包的状态,如果红包已经被抢完了,即刻返回,如果红包未接完,对于一个红包进去抢环节还有限流,这是第一级保护,通过一致性hash算法,一一个单到dao层都会路由到同一个机器的同一个进程,dao到mysql在现一个连接上完成抢操作,把并发抢修改成串行化,mysql可以无锁等待,性能明显提升。

  • 如何实现数据一致性

谈到分布式系统,先回顾CAP理论

C:Consistency数据一致更新,所有变动都是同步的

A:高可用,好的响应性能

P: 分区容忍,可靠性

在我们的系统设计中,同样碰到这个问题,无法同时满足三个因子,移动互联网系统,高可用性是必要要求,数据分区也是分布式系统的条件,所以,我们设计系统时,只能尽量保证数据一致性,只要一定时间窗口内,完成数据一致,让用户满意。

微信红包的数据有几份,订单数据,用户数据,还有对应的cache数据,

N:数据副本份数红包有三份

R: 一次需读取的副本红包一次从一个副本可以全部读取需要数据

W: 一次写入数据2份实时写,一分异步化

R(1) + W(2) <=N从公式算出,我们的数据模型也是弱一致性

用户数据是异步更新,更新失败,通过消息中心,异步重试,根据DB资源负载设置调用方的调用阀值,除了实时重试,我们还有准实时数据核对,保证数据最终一致性。

 

原文链接:http://djt.qq.com/article/view/1349

Facebook的MySQL数据库,是世界上最庞大的MySQL数据库之一,在不同地区有数千个数据库服务器。因此,备份对他们来说是个巨大的挑战。为了解决这个问题,他们构建了一个高度自动化、非常有效的备份系统,每周移动多个PB的数据。Facebook数据团队的Eric Barrett通过一篇文章分享了他们的做法。

他们没有采用大量前载(front-loaded)测试,而是强调快速检测失败,并且进行快速、自动化纠正。部署几百个数据库服务器,只需很少人力干预。使用下面的三个措施,他们做到了有节奏的增长,同时具备支持上十亿用户的灵活性。

措施1:二进制日志和mysqldump

第一道防线称为“措施1”,或“机架”备份(rack backup),简称RBU。在每个数据库机架上,不论其类型为何,都有两个RBU存储服务器。以RBU作为数据库服务器放在同一个机架中,这可以保证最大的带宽和最小的延迟,它们同时可以作为缓存,在备份的下个措施使用。

收集二进制日志,是这些服务器的工作之一。二进制日志会不断以流形式,通过模拟从进程(simulated slave process)输送到RBU主机中。这样一来,不需要运行mysqld,RBU就可以接收到同样的更新作为复制版本。

在RBU上保存同步的二进制日志很重要:如果一个主数据库服务器离线,该服务器上的用户将无法更新状态或是上传照片。出现问题后,他们需要保证修复时间越短越好。有可用的二进制日志,就能让他们在数秒内启动另一个数据库作为主数据库。由于RBU中有秒级的二进制日志,即使某个旧主数据库完全不可用,也没有关系,只要利用将记录下的事务恢复到上一个备份中即可完成立即恢复。

RBU服务器的第二个工作是执行传统备份。MySQL备份有两种方式:二进制和逻辑(mysqldump)。Facebook使用逻辑备份,因为它与版本无关,提供更好的数据完整性,更紧凑,恢复起来更省事。不过,当为某个数据库构建全新复制时,他们仍然使用二进制拷贝。

mysqldump的一个主要好处是:磁盘上的数据损坏不会影响到备份中。如果磁盘某个扇区出现问题,或是写入错误,InnoDB页面校验和就会出错。在组合备份流时,MySQL会从内存中读取正确的内容,或是去磁盘读取,然后遇到错误的校验和,停止备份(以及数据库进程)。mysqldump的问题是:污染用来缓存InnoDB块的LRU缓存。不过,新版本的MySQL中,会将LRU插入操作从扫描时放到缓存结束。

对在自己权限范围内的所有数据库,每个RBU都有一个夜间备份。尽管有着天量级别的数据,Facebook的团队还是可以在几个小时内完成对所有数据的备份。

如果RBU失败,自动化软件会将其职责分配给同一集群中其他系统。当它恢复上线后,职责会自动返回到最初的RBU主机。

Facebook团队不会过分担心单个系统的数据保留问题,因为他们有措施2。

措施2:Hadoop DFS

在每个备份和二进制日志收集完成后,他们会马上将其复制到他们的大型定制化Hadoop集群中。这些集群是非常稳定的复制数据集,并有固定的保留时间。因为磁盘大小增长很快,较老的RBU可能不足以保存一到两天的备份。不过他们会按需要增长Hadoop集群,同时不需要担心底层硬件情况。Hadoop的分布式特性让他们有足够带宽,完成快速数据恢复。

不久,他们会把非实时数据分析放到这些Hadoop集群中。这可以降低数据库中非关键读的次数,让Facebook网站的响应速度更快。

措施3:长期存储

每周,他们会从Hadoop备份移动到另一个地区的分散存储中。这些系统是最新而且安全的存储系统,在他们的日常数据管理工具流程之外。

监控

除常用的系统监控外,他们还会捕捉很多特定的统计数据,比如binlog集合延迟、系统容量等等。

为备份失败打分,是他们最有价值的工具。因为Facebook的数据库和同时运行的维护任务量级,错过某些备份也不奇怪。广泛的失败和多日没有成功的单个备份,这都是他们要注意的重点。因此,某个错过备份的得分会随着时间呈指数级增长,这些得分的不同聚合,让团队能对备份的整体健康度有一个有效而快速的了解。

比如,在一天内,某个数据错失一次备份,得1分,一天错失50次备份,就是50分。但在三天内的一次数据库错失,就是27分(3的3次幂),三天内50次,这是很严重的问题,得分就是1350(50乘以3的3次幂)。这会在他们的监控图上出现一个巨大的波峰,团队会马上对其采取行动。

恢复

在系统管理员中有句老话:“如果你没有测试过你的备份,就等于没有备份。”

因此,Facebook团队构建了一个测试系统,会持续地从措施2开始,将数据恢复到测试服务器上。恢复完成后,他们会执行多次数据完整性检查。如果有任何反复出现的问题,系统就会报警,提醒相关人员关注、审核。该系统可以发现所有问题,包括MySQL的bug,到备份过程中的纰漏,并可以让他们更灵活地应对备份环境中的变化。

他们构建了一个名为ORC(ORC恢复协调器的递归缩写)的系统,工程师如何需要恢复他们所用工具的数据库的过去版本,就可以以自服务方式使用该系统恢复数据。对于快速开发来说还是挺方便的。

在结尾,Eric Barrett说道:

备份不是最迷人的工程工作。它们即是技术活,又是重复性的,如果一切正常,没人会注意。它们也是跨学科和团队的,需要懂得系统、网络和软件等多方面的专业知识。但是,确保你的记忆和联系安全无误,这是无比重要的事情,而且到最后,也是充满回报的事情。

有网友问到

在不运行mysqld的RBU上,你们如何完成二进制日志的流传送?什么是模拟从进程?

Facebook的MySQL性能工程师Harrison Fisk给出了答案:

我们使用mysqlbinlog的–never–选项,并有一个用python开发的小包装程序,会监控并保证mysqlbinlog运行成功。

原文链接:http://www.infoq.com/cn/news/2013/02/facebook-mysql-backup

今天又想折腾了,于是着手试了一遍为服务器开启两步验证增强安全性。话不多说,实战开始。

  • 安装依赖包
1
yum install pam-devel gcc-c++ make -y

 

  • 下载Google-authentication源码,并安装

墙内:百度盘

墙外:谷歌地址

解压

1
tar xjf libpam-google-authenticator-1.0-source.tar.bz2

进入源码目录并安装

1
2
cd libpam-google-authenticator-1.0
make && make install

 

  • 生成验证密钥

运行google-authenticator,你可以根据实际情况输入y或者n

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
google-authenticator

Do you want authentication tokens to be time-based (y/n) y
#你是否要生成基于时间的认证口令?

https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/root@AY140528171537Z%3Fsecret%3D2YA3XXXXXXXRCEIQ

Your new secret key is: 2YA3XXXXXXXRCEIQ
Your verification code is 17XXX4
Your emergency scratch codes are:
51XXXX25
93XXXX45
87XXXX39
98XXXX31
15XXXX83
#这五个是紧急状态使用的验证码,谨当无法获取验证码时使用,注意这些紧急验证码用一次就少一个,所以这几个紧急验证码一定要保存好

Do you want me to update your "/root/.google_authenticator" file (y/n) y
#你希望我更新你的“~/.google_authenticator”文件吗(y/n)?

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y
#你希望禁止多次使用同一个验证令牌吗?这限制你每次登录的时间大约是30秒,但是这加大了发现或甚至防止中间人攻击的可能性(y/n)?y

By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) y
#默认情况下,令牌保持30秒有效;为了补偿客户机与服务器之间可能存在的时滞,我们允许在当前时间前后有一个额外令牌。如果你在时间同步方面遇到了问题,可以将窗口从默认大小即1分30秒加大到约4分。你希望这么做吗(y/n)?

If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y
#如果你登录的那台计算机没有加固,以防范暴力登录,可以对验证模块启用尝试次数限制。默认情况下,这限制攻击者每30秒试图登录的次数只有3次。你希望启用尝试次数限制吗(y/n)?

 

  • 配置ssh使用两步验证模块

1.编辑/etc/pam.d/sshd,将下面的内容添加进去

1
2
vim /etc/pam.d/sshd
auth required pam_google_authenticator.so

2.编辑/etc/ssh/sshd_config,将ChallengeResponseAuthentication no改为ChallengeResponseAuthentication yes,并重启sshd服务
 

  • 安装、配置谷歌身份验证器

Android:墙内:http://shouji.baidu.com/soft/item?docid=3825924 墙外:https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2

iOS:https://itunes.apple.com/gb/app/google-authenticator/id388497605

Windows Phone:http://www.windowsphone.com/en-gb/store/app/authenticator/e7994dbc-2336-4950-91ba-ca22d653759b

Chrome GAuth Authenticator插件:https://chrome.google.com/webstore/detail/gauth-authenticator/jcmgkikfgdbehjdajjdnebnnmmknfblm

Firefox GAuth Authenticator插件:https://marketplace.firefox.com/app/gauth-authenticator/

验证器的配置,这里以Android的APP为例:

打开身份验证器,点击开始设置。在此我们可以“输入提供的密钥”,其中名称可以随意定义,重要的密钥处需要输入上面我们运行google-authenticator时生成的secret key。若当初没有保存,可以查看根目录下的.google_authenticator文件。添加完成之后该软件就会每隔30秒刷新一次验证码。
 

  • 登陆服务器验证

打开putty,输入IP和端口,打开该会话。成功登陆会显示如下输入顺序

即先提示输入身份验证器APP的Verification code验证码,然后再输入Linux的密码。

若显示Using keyboard-interactive authentication却只有Password提示

说明SELinux为开启状态。因为SELinux会阻止sshd向用户根目录的~/.google_authenticator文件进行任何操作,偷懒的解决方式就是关闭SELinux。

 

注:SSH登陆时的验证步骤为密钥/公钥验证→验证码验证→密码验证,所以在本机有密钥时,会直接登陆服务器,不会触发验证码验证。