Geekwolf's Blog

Quick notes


  • 首页

  • 分类

  • 关于

  • tips

  • 归档

  • 标签

  • 站点地图

  • 搜索

Django模板无法使用perms变量问题

发表于 2017-09-06 | 分类于 Python | 阅读次数
阅读时长 2

首先,在使用Django内置权限管理系统时,settings.py文件要添加

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
INSTALLED_APPS添加:
'django.contrib.auth',
MIDDLEWARE添加:
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.context_processors.auth',
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
],
},
},
]

如何在模板进行权限检查呢?
根据官网说明 https://docs.djangoproject.com/en/1.11/topics/auth/default/#permissions ,已登录用户权限保存在模板变量中,是权限模板代理django.contrib.auth.context_processors.PermWrapper的一个实例,
具体可以查看django/contrib/auth/context_processors.py源码

测试用例:

测试过程中,发现变量压根不存在,没有任何输出;好吧,只能取Debug Django的源码了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def auth(request):
"""
Returns context variables required by apps that use Django's authentication
system.
If there is no 'user' attribute in the request, uses AnonymousUser (from
django.contrib.auth).
"""
if hasattr(request, 'user'):
user = request.user
else:
from django.contrib.auth.models import AnonymousUser
user = AnonymousUser()
print(user, PermWrapper(user), '-----------------------')
return {
'user': user,
'perms': PermWrapper(user),
}

测试访问接口,发现有的接口有打印权限信息,有的没有,似乎恍然醒悟

1
2
3
4
可以打印权限信息的接口返回:
return render(request, 'fms/fms_add.html', {'request': request, 'form': form, 'error': error})
不能打印权限新的接口返回:
return render_to_response( 'fms/fms.html', data)

render和render_to_response区别
render是比render_to_reponse更便捷渲染模板的方法,会自动使用RequestContext,而后者需要手动添加:

1
return render_to_response(request, 'fms/fms_add.html', {'request': request, 'form': form, 'error': error},context_instance=RequestContext(request))

其中RequestContext是django.template.Context的子类.接受request和context_processors,从而将上下文填充渲染到模板
问题已经很明确,由于使用了render_to_response方法,没有手动添加context_instance=RequestContext(request)导致模板不能使用变量

企业级Docker私有仓库部署(https)

发表于 2017-08-05 | 分类于 docker | 阅读次数
阅读时长 1

部署环境

  • Centos7.3 x64
  • docker-ce-17.06.0
  • docker-compose-1.15.0
  • Python-2.7.5(系统默认)

部署目标

  • 使用HTTPS协议
  • 支持Clair(在Harbor1.2版本会支持)
支持HTTPS

生产环境最好由权威CA机构签发证书(免费的推荐StartSSL,可参考https://www.wosign.com/Support/Nginx.html),这里为了测试方便使用自签发的证书

  • 创建CA证书

    1
    openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 365 -out ca.crt
  • 生成CSR公钥

    1
    openssl req -newkey rsa:4096 -nodes -sha256 -keyout hub.wow.key -out hub.wow.csr
  • 颁发证书

    1
    openssl x509 -req -days 365 -in hub.wow.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out hub.wow.crt
  • 部署证书

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    cp hub.wow.crt hub.wow.key /data/harbor/keys/
    vim /data/harbor/harbor.cfg
    hostname = hub.wow
    ui_url_protocol = https
    ssl_cert = /data/harbor/keys/hub.wow.crt
    ssl_cert_key = /data/harbor/keys/hub.wow.key
    cd /data/harbor
    ./prepare 重新生成配置文件
    docker-compose down
    docker-compose up
  • 通过HTTPS访问私有仓库

    1
    2
    3
    4
    5
    WebUI: https://how.wow
    Docker Client:
    [root@hub ~]# docker login -u admin -p Harbor12345 hub.wow
    Login Succeeded

问题

docker login时提示x509: certificate signed by unknown authority
解决方法: 自签名的证书不被系统信任,需要cp ca.crt /etc/docker/certs.d/hub.wow/, 无需重启docker

企业级Docker私有仓库之Harbor部署(http)

发表于 2017-08-04 | 分类于 docker | 阅读次数
阅读时长 2

部署环境

  • Centos7.3 x64
  • docker-ce-17.06.0
  • docker-compose-1.15.0
  • Python-2.7.5(系统默认)

Docker及Docker-compose安装

1
2
3
4
5
6
7
8
9
10
11
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
yum-config-manager --enable docker-ce-edge
yum makecache fast
systemctl start docker
systemctl enable docker
curl -L https://github.com/docker/compose/releases/download/1.15.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

Habor部署配置

1
2
3
4
5
6
7
8
9
10
wget https://github.com/vmware/harbor/releases/download/v1.1.2/harbor-offline-installer-v1.1.2.tgz
tar xf harbor-offline-installer-v1.1.2.tgz
cd harbor/
vim harbor.cfg
hostname = hub.wow
其他默认(http协议)
./install.sh
安装成功后,可以通过http://hub.wow/访问

Docker客户端使用

由于Harbor默认使用的http协议,故需要在Docker client上的Dockerd服务增加–insecure-registry hub.wow
Centos7修改方式为:

1
2
3
4
5
vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --insecure-registry hub.wow
systemctl daemon-reload
systemctl reload docker

1
2
3
4
5
6
7
8
9
10
[root@localhost harbor]# docker login -u admin -p Harbor12345 hub.wow
官方仓库下载busybox镜像
[root@localhost harbor]# docker pull busybox
[root@localhost harbor]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest efe10ee6727f 2 weeks ago 1.13MB
本地基于busybox:latest创建标记hub.wow/busybox:latest
[root@localhost harbor]# docker tag busybox:latest hub.wow/project_name/busybox:latest
推送本地镜像busybox:latest 到hub.wow私有仓库
[root@localhost harbor]# docker push hub.wow/project_name/busybox:latest

Harbor服务管理

1
2
cd harbor/
docker-compose -f ./docker-compose.yml [ up|down|ps|stop|start ]

使用Zabbix LLD实现进程数监控

发表于 2017-04-19 | 分类于 系统监控 | 阅读次数
阅读时长 4

目的

  • 针对特定进程数量做监控报警

思路

  1. 通过Zabbix LLD自动发现:每台机器都跑了什么服务、每个服务应该跑多少进程
  2. Zabbix Agent 30s将当前机器跑了哪些服务、每个服务进程数上报Zabbix Server
  3. 开发给定配置文件proccessInfo.txt: IP 服务名称 进程数量,此配置作为监控依据
  4. proccessInfo.txt配置文件需在每次变更配置时,自动生成最新

配置流程

  1. LLD自动发现脚本
  2. 数据采集脚本
  3. Agent添加Key
  4. Zabbix Server添加模板组
  5. 创建自动发现规则(监控项、报警触发器)
  6. 添加当前进程数监控项(通过Zabbix Trapper方式,由Agent端)
  7. 定义报警内容

具体步骤

LLD自动发现脚本

LLD自动发现,将进程名称及进程总数上报Zabbix Server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/usr/bin/python services.py services_list
{
"data": [
{
"{#SERVICENAME}": "192.168.1.2-p_q1_server",
"{#TRIGGER_VALUE}": 3
},
{
"{#SERVICENAME}": "192.168.1.2-p_world_d2_server",
"{#TRIGGER_VALUE}": 1
},
{
"{#SERVICENAME}": "192.168.1.2-p_gate_server",
"{#TRIGGER_VALUE}": 2
},
{
"{#SERVICENAME}": "192.168.1.2-p_world_d1_server",
"{#TRIGGER_VALUE}": 1
}
]
}
数据采集上报: /usr/bin/python services.py {HOST.HOST}

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# -*- coding: utf-8 -*-
import json
import commands
import subprocess
import re
import sys
class services_monitor:
def __init__(self):
self.zabbix_server_ip = '192.168.1.1'
self.info_path = '/home/proccessInfo.txt'
self.data_path = '/tmp/.process_number_monitor.log'
def ip(self):
ipstr = '([0-9]{1,3}\.){3}[0-9]{1,3}'
ipconfig_process = subprocess.Popen("ifconfig", stdout=subprocess.PIPE)
output = ipconfig_process.stdout.read()
ip_pattern = re.compile('(inet addr:%s)' % ipstr)
pattern = re.compile(ipstr)
iplist = []
for ipaddr in re.finditer(ip_pattern, str(output)):
ip = pattern.search(ipaddr.group())
if ip.group() != "127.0.0.1":
iplist.append(ip.group())
ip = '|'.join(iplist)
return ip
def check_proc(self,proc_name):
cmd = 'ps -ef |grep %s|grep -v grep|wc -l' % proc_name
proccess_info = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
# list=proccess_info.stdout.read().strip().split('\n')
procss_num = proccess_info.communicate()[0]
return procss_num
def get_info(self,ip):
service = []
status, result = commands.getstatusoutput("grep -E '%s' %s" % (str(ip),self.info_path))
result = result.split('\n')
for i in result:
i = list(i.split(' '))
service.append({"{#SERVICENAME}": i[0].strip() + "-" + i[1].strip(), "{#TRIGGER_VALUE}":int(i[2].strip())})
data = json.dumps({'data': service}, sort_keys=True, indent=4)
return data
def collect_data(self,data):
data = json.loads(data)["data"]
commands.getstatusoutput('cat /dev/null >%s' % self.data_path)
f = open(self.data_path,'a')
for i in data:
name = i['{#SERVICENAME}'].split('-')
ip = name[0]
proc_name = name[1]
f.write('%s\tproc_num[%s]\t%s' %(ip,i['{#SERVICENAME}'],self.check_proc(proc_name)))
f.close()
def send_data(self,data_path):
status,output = commands.getstatusoutput('/bin/bash -c "zabbix_sender -z %s -i %s &>/dev/null"' % (self.zabbix_server_ip,self.data_path))
print status,output
if __name__ == '__main__':
services = services_monitor()
ip = services.ip()
data = services.get_info(ip)
try:
argv = sys.argv[1]
if argv == "services_list":
print data
else:
services.collect_data(data)
services.send_data(services.data_path)
except IndexError:
print data

Agent添加Key

1
2
3
vim /usr/local/etc/zabbix_agentd.conf
UserParameter=dzpt.service.process.discovery,/usr/bin/python /home/opt/scripts/services.py services_list
UserParameter=dzpt.service.process.exec[*],/usr/bin/python /home/opt/scripts/services.py $1

创建自动发现规则

(监控项Trapper方式、报警触发器)

添加当前进程数监控项

定义报警内容

Action中定义(此处略)

将定义好的模板链接到主机或者其他模板即可

最后

使用Zabbix LLD之后,可以设定多久更新一次监控项及监控阀值;当配置文件变更时,无需人为调整阀值和监控项

架构学习之路-高可用高并发系统设计原则

发表于 2017-04-13 | 分类于 架构之路 | 阅读次数
阅读时长 5

本系列博客主要是学习开涛《亿级流量网站架构核心技术》一书学习笔记及自己的感悟:

架构设计三大定律

墨菲定律

  • 任何事没有表面看起来那么简单
  • 所有的事都会比预计的时间长
  • 可能出错的事情总会出错
  • 担心某种事情发生,那么它就更有可能发生

    康威定律

  • 系统架构师公司组织架构的反映
  • 按照业务闭环进行系统拆分/组织架构划分,实现闭环、高内聚、低耦合,减少沟通成本
  • 如果沟通出现问题,应该考虑进行系统和组织架构的调整
  • 适合时机进行系统拆分,不要一开始就吧系统、服务拆分拆的非常细,虽然闭环,但是每个人维护的系统多,维护成本高
  • 微服务架构的理论基础 - 康威定律 https://yq.aliyun.com/articles/8611
  • 每个架构师都应该研究下康威定律 http://36kr.com/p/5042735.html

二八定律

  • 80%的结果取决于20%的原因

系统设计遵循的原则

1. 高并发原则

无状态

  • 无状态应用,便于水平扩展
  • 有状态配置可通过配置中心实现无状态
  • 实践: Disconf、Yaconf、Zookpeer、Consul、Confd、Diamond、Xdiamond等

拆分

  • 系统维度:按照系统功能、业务拆分,如购物车,结算,订单等
  • 功能维度:对系统功能在做细粒度拆分
  • 读写维度:根据读写比例特征拆分;读多,可考虑多级缓存;写多,可考虑分库分表
  • AOP维度: 根据访问特征,按照AOP进行拆分,比如商品详情页可分为CDN、页面渲染系统,CDN就是一个AOP系统
  • 模块维度:对整体代码结构划分Web、Service、DAO

服务化

  • 服务化演进: 进程内服务-单机远程服务-集群手动注册服务-自动注册和发现服务-服务的分组、隔离、路由-服务治理
  • 考虑服务分组、隔离、限流、黑白名单、超时、重试机制、路由、故障补偿等
  • 实践:利用Nginx、HaProxy、LVS等实现负载均衡,ZooKeeper、Consul等实现自动注册和发现服

消息队列

  • 目的: 服务解耦(一对多消费)、异步处理、流量削峰缓冲等
  • 大流量缓冲: 牺牲强一致性,保证最终一致性(案例:库存扣减,现在Redis中做扣减,记录扣减日志,通过后台进程将扣减日志应用到DB)
  • 数据校对: 解决异步消息机制下消息丢失问题

数据异构

  • 数据异构: 通过消息队列机制接收数据变更,原子化存储
  • 数据闭环: 屏蔽多从数据来源,将数据异构存储,形成闭环

缓存银弹

  • 用户层:

    • DNS缓存
    • 浏览器DNS缓存
    • 操作系统DNS缓存
    • 本地DNS服务商缓存
    • DNS服务器缓存
    • 客户端缓存
    • 浏览器缓存(Expires、Cache-Control、Last-Modified、Etag)* App客户缓存(js/css/image…)
  • 代理层:

    • CDN缓存(一般基于ATS、Varnish、Nginx、Squid等构建,边缘节点-二级节点-中心节点-源站)
  • 接入层:

    • Nginx为例:

    • Proxy_cache: 代理缓存,可以存储到/dev/shm或者SSD

    • FastCGI Cache
    • Nginx+Lua+Redis: 业务数据缓存
    • PHP为例:
      • Opcache: 缓存PHP的Opcodes
  • 应用层:

    • 页面静态化
    • 业务数据缓存(Redis/Memcached/本地文件等)
    • 消息队列
  • 数据层:

    • NoSQL: Redis、Memcache、SSDB等
    • MySQL: Innodb/MyISAM等Query Cache、Key Cache、Innodb Buffer Size等
  • 系统层:

    • CPU : L1/L2/L3 Cache/NUMA
    • 内存
    • 磁盘:磁盘本身缓存、dirty_ratio/dirty_background_ratio、阵列卡本身缓存

并发化

2. 高可用原则

降级

  • 降级开关集中化管理:将开关配置信息推送到各个应用
  • 可降级的多级读服务:如服务调用降级为只读本地缓存
  • 开关前置化:如Nginx+lua(OpenResty)配置降级策略,引流流量;可基于此做灰度策略
  • 业务降级:高并发下,保证核心功能,次要功能可由同步改为异步策略或屏蔽功能

限流

  • 目的: 防止恶意请求攻击或超出系统峰值
  • 实践:

    • 恶意请求流量只访问到Cache
    • 穿透后端应用的流量使用Nginx的limit处理
    • 恶意IP使用Nginx Deny策略或者iptables拒绝

切流量

  • 目的:屏蔽故障机器
  • 实践:

    • DNS: 更改域名解析入口,如DNSPOD可以添加备用IP,正常IP故障时,会自主切换到备用地址;生效实践较慢
    • HttpDNS: 为了绕过运营商LocalDNS实现的精准流量调度
    • LVS/HaProxy/Nginx: 摘除故障节点

可回滚

  • 发布版本失败时可随时快速回退到上一个稳定版本
3. 业务设计原则
  • 防重设计
  • 幂等设计
  • 流程定义
  • 状态与状态机
  • 后台系统操作可反馈
  • 后台系统审批化
  • 文档注释
  • 备份
4. 总结

先行规划和设计时有必要的,要对现有问题有方案,对未来有预案;欠下的技术债,迟早都是要还的。

CPU工作模式及调频

发表于 2017-03-24 | 分类于 Linux运维 | 阅读次数
阅读时长 2

安装i7z及cpufrequtils

1
apt-get install i7z cpufrequtils

常见的CPU工作模式

调速器 描述
ondemand 按需快速动态调整CPU频率, 一有cpu计算量的任务,就会立即达到最大频率运行,等执行完毕就立即回到最低频率(阙值为 95%
performance 运行于最大频率
conservative 按需快速动态调整CPU频率, 一有cpu计算量的任务,就会立即达到最大频率运行,等执行完毕就立即回到最低频率(阙值为 75%)
powersave 运行于最小频率
userspace 运行于用户指定的频率

查看当前CPU工作模式

1
2
3
4
5
查看CPU当前的工作模式
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
查看支持的CPU工作模式
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors

由于在Debian 8下默认使用intel_pstate驱动,只支持performance和powersave模式,不同频率驱动程序支持的模式不同
具体可以参考:CPU frequency scaling http://t.cn/R6cQXvp

调整最高性能模式

1
echo 'performance' |tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

CPU调频

1
2
3
4
5
6
7
8
9
10
Usage: cpufreq-set [options] Options:
-c CPU, --cpu CPU #指定CPU核心号,请注意上图的analyzing CPU数字。
-d FREQ, --min FREQ #手工指定最小主频速度。(在userspace策略)
-u FREQ, --max FREQ #手工指定最大主频速度。(在userspace策略)
-g GOV, --governor GOV #设置工作策略
-f FREQ, --freq FREQ #设定特定的工作频率(CPU默认档次)
#请参考上图的available frequency steps
-h, --help #输出这个帮助信息
cpufreq-set -d 2.4Ghz -u 2.4Ghz

实时查看频率

通过i7z命令可实时查看当前CPU的工作频率

Nginx/Haproxy作为反向代理或负载均衡时如何获取客户真实IP?

发表于 2017-03-01 | 分类于 Linux运维 | 阅读次数
阅读时长 1

Nginx代理配置

增加如下配置:

1
2
3
4
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X_FORWARDED_PROTO https;
proxy_set_header Host $host;

Haproxy配置

1
option forwardfor

后端Nginx配置

1
2
3
set_real_ip_from 1.1.1.1; 前端Nginx代理或者负载均衡的IP(在后端Nginx日志中显示的)
real_ip_header X-Forwarded-For;
real_ip_recursive on;

后端Nginx访问控制

1
2
3
4
5
6
7
8
9
10
location ~ /test/api/ {
set $allow false;
if ($http_x_forwarded_for ~ "2.2.2.2") {
set $allow false;
}
if ($allow = false) { return 403;}
proxy_pass http://web;
}
}

参考

  • http://www.wkii.org/nginx-cdn-get-user-real-ip.html

网卡软中断过高问题优化总结

发表于 2017-02-28 | 分类于 Linux运维 | 阅读次数
阅读时长 26

问题背景

游戏网关高峰期时出网络丢包,CPU0软中断%sys高达90%

预备知识

什么是中断?

由于接收来自外围硬件(相对于CPU和内存)的异步信号或者来自软件的同步信号,而进行相应的硬件、软件处理;发出这样的信号称为进行中断请求(interrupt request, IRQ)

硬中断与软中断?
  • 硬中断:外围硬件发给CPU或者内存的异步信号就称之为硬中断
  • 软中断:由软件系统本身发给操作系统内核的中断信号,称之为软中断。通常是由硬中断处理程序或进程调度程序对操作系统内核的中断,也就是我们常说的系统调用(System Call)
硬中断与软中断之区别与联系?
  1. 硬中断是有外设硬件发出的,需要有中断控制器之参与。其过程是外设侦测到变化,告知中断控制器,中断控制器通过CPU或内存的中断脚通知CPU,然后硬件进行程序计数器及堆栈寄存器之现场保存工作(引发上下文切换),并根据中断向量调用硬中断处理程序进行中断处理
  2. 软中断则通常是由硬中断处理程序或者进程调度程序等软件程序发出的中断信号,无需中断控制器之参与,直接以一个CPU指令之形式指示CPU进行程序计数器及堆栈寄存器之现场保存工作(亦会引发上下文切换),并调用相应的软中断处理程序进行中断处理(即我们通常所言之系统调用)
  3. 硬中断直接以硬件的方式引发,处理速度快。软中断以软件指令之方式适合于对响应速度要求不是特别严格的场景
  4. 硬中断通过设置CPU的屏蔽位可进行屏蔽,软中断则由于是指令之方式给出,不能屏蔽
  5. 硬中断发生后,通常会在硬中断处理程序中调用一个软中断来进行后续工作的处理
  6. 硬中断和软中断均会引起上下文切换(进程/线程之切换),进程切换的过程是差不多的

查看中断情况

查看中断分布情况即CPU都在哪些设备上干活,干了多少(也可以使用itop工具实时查看)?

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
root@geekwolf:~# cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 CPU8 CPU9 CPU10 CPU11 CPU12 CPU13 CPU14 CPU15 CPU16 CPU17 CPU18 CPU19 CPU20 CPU21 CPU22 CPU23 CPU24 CPU25 CPU26 CPU27 CPU28 CPU29 CPU30 CPU31
0: 620 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-edge timer
8: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-edge rtc0
9: 20774 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi acpi
16: 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi ehci_hcd:usb1
23: 243 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC-fasteoi ehci_hcd:usb2
88: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DMAR_MSI-edge dmar0
89: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 DMAR_MSI-edge dmar1
90: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
91: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
92: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
93: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
94: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
95: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
96: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
97: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
98: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
99: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
100: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge PCIe PME
101: 169988 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge mpt2sas0-msix0
134: 1900138 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth2-q0
150: 4262209 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge eth3-q0
166: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
167: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
168: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
169: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
170: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
171: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
172: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
173: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
174: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
175: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
176: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
177: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
178: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
179: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
180: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
181: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge ioat-msix
NMI: 710 280 658 235 114 91 76 74 208 123 176 128 106 93 102 95 30 360 790 46 28 17 10 8 10 129 1166 22 18 16 11 7 Non-maskable interrupts
LOC: 4230314 2640664 2427443 1337890 1091372 892129 819153 816781 2695809 1563153 1368637 1608410 1241692 1166692 1205270 1124865 120831 1966946 328048 816162 163492 222276 129805 121126 111906 599782 1247371 194215 162828 145678 118762 114295 Local timer interrupts
SPU: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Spurious interrupts
PMI: 710 280 658 235 114 91 76 74 208 123 176 128 106 93 102 95 30 360 790 46 28 17 10 8 10 129 1166 22 18 16 11 7 Performance monitoring interrupts
IWI: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IRQ work interrupts
RES: 679921 1369165 1013002 573776 543083 540027 593345 588120 842115 846190 874862 890102 873810 860080 867322 848916 3879 63916 10863 12850 7463 6350 10889 16041 2065 13207 6870 6817 4030 4700 5190 7430 Rescheduling interrupts
CAL: 46507 67439 67569 67567 67565 67566 67566 67568 154689 67553 67511 67538 67568 67557 67534 67519 67520 26471 67470 67470 67476 67525 67518 67525 67545 64065 67210 67506 67485 67492 67526 67521 Function call interrupts
TLB: 6547 3416 1798 1015 361 637 271 447 822 113 1079 222 259 198 265 844 157 1470 3468 767 499 262 338 230 41 1457 4023 290 105 93 46 177 TLB shootdowns
TRM: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Thermal event interrupts
THR: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Threshold APIC interrupts
MCE: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Machine check exceptions
MCP: 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 569 Machine check polls
ERR: 0
MIS: 0

从上面的数据可以看出网卡eth2、eth3软中断都落在CPU0可以通过cat /proc/softirqs查看具体的软中断情况,总的中断次数可以通过vmstat或者dstat查看,其中vmstat中的in表示每秒的中断次数;
通过mpstat -P ALL 2,每隔两秒查看下所有核状态信息,其中%irq为硬中断,%soft为软中断

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
root@geekwolf:~# mpstat -P ALL 2
08:42:04 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
08:42:05 AM all 4.31 0.00 0.70 0.00 0.00 0.06 0.00 0.00 94.93
08:42:05 AM 0 5.26 0.00 1.05 0.00 0.00 60.05 0.00 0.00 92.63
08:42:05 AM 1 7.07 0.00 1.01 0.00 0.00 0.00 0.00 0.00 91.92
08:42:05 AM 2 8.91 0.00 0.99 0.00 0.00 0.00 0.00 0.00 90.10
08:42:05 AM 3 8.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 91.00
08:42:05 AM 4 8.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 91.00
08:42:05 AM 5 7.00 0.00 2.00 0.00 0.00 0.00 0.00 0.00 91.00
08:42:05 AM 6 7.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 92.00
08:42:05 AM 7 4.12 0.00 1.03 0.00 0.00 0.00 0.00 0.00 94.85
08:42:05 AM 8 4.17 0.00 1.04 0.00 0.00 0.00 0.00 0.00 94.79
08:42:05 AM 9 8.91 0.00 0.99 0.00 0.00 0.00 0.00 0.00 90.10
08:42:05 AM 10 4.17 0.00 2.08 0.00 0.00 0.00 0.00 0.00 93.75
08:42:05 AM 11 6.12 0.00 1.02 0.00 0.00 0.00 0.00 0.00 92.86
08:42:05 AM 12 6.00 0.00 2.00 0.00 0.00 0.00 0.00 0.00 92.00
08:42:05 AM 13 3.16 0.00 1.05 0.00 0.00 0.00 0.00 0.00 95.79
08:42:05 AM 14 8.16 0.00 1.02 0.00 0.00 0.00 0.00 0.00 90.82
08:42:05 AM 15 6.06 0.00 1.01 0.00 0.00 1.01 0.00 0.00 91.92
08:42:05 AM 16 3.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 96.00
08:42:05 AM 17 2.02 0.00 1.01 0.00 0.00 0.00 0.00 0.00 96.97
08:42:05 AM 18 2.04 0.00 1.02 0.00 0.00 0.00 0.00 0.00 96.94
08:42:05 AM 19 2.97 0.00 0.99 0.00 0.00 0.00 0.00 0.00 96.04
08:42:05 AM 20 2.04 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.96
08:42:05 AM 21 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00
08:42:05 AM 22 3.03 0.00 0.00 0.00 0.00 0.00 0.00 0.00 96.97
08:42:05 AM 23 2.04 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.96
08:42:05 AM 24 4.95 0.00 0.00 0.00 0.00 0.00 0.00 0.00 95.05
08:42:05 AM 25 2.02 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.98
08:42:05 AM 26 3.03 0.00 0.00 0.00 0.00 0.00 0.00 0.00 96.97
08:42:05 AM 27 2.04 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.96
08:42:05 AM 28 1.01 0.00 1.01 0.00 0.00 0.00 0.00 0.00 97.98
08:42:05 AM 29 1.02 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.98
08:42:05 AM 30 1.01 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.99
08:42:05 AM 31 1.02 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.98

何优化软中断CPU0过高问题

RSS(Receive Side Scaling,需网卡支持多队列)
查看网卡是否支持队列
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
root@geekwolf:~# lscpi -vvv
06:00.0 Ethernet controller: Broadcom Corporation BCM57840 NetXtreme II 10/20-Gigabit Ethernet (rev 11)
Subsystem: Hewlett-Packard Company Device 22fa
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+ Stepping- SERR+ FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <tabort - <MAbort- >SERR- <perr - INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 32
Region 0: Memory at 93800000 (64-bit, prefetchable) [size=8M]
Region 2: Memory at 93000000 (64-bit, prefetchable) [size=8M]
Region 4: Memory at 95000000 (64-bit, prefetchable) [size=64K]
[virtual] Expansion ROM at 95080000 [disabled] [size=512K]
Capabilities: [48] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=1 PME-
Capabilities: [50] Vital Product Data
Product Name: HP FlexFabric 10Gb 2-port 536FLB Adapter
Read-only fields:
[PN] Part number: 766488-001
[EC] Engineering changes: A-5444
[MN] Manufacture ID: 31 30 33 43
[V0] Vendor specific: 12W PCIeGen3
[V1] Vendor specific: 7.10.55
[V3] Vendor specific: 7.10.72
[V5] Vendor specific: 0A
[V6] Vendor specific: 7.10.72
[V7] Vendor specific: 536FLB
[SN] Serial number: 7C444703LG
[V2] Vendor specific: 5447
[V4] Vendor specific: 8CDCD419D870
[RV] Reserved: checksum good, 186 byte(s) reserved
End
Capabilities: [a0] MSI-X: Enable+ Count=32 Masked-

找到Ethernet controller项,如果有MSI-X,Enable+ 并且Count>1,表示该网卡支持多队列

查看网卡支持多少个队列
1
2
3
4
5
6
7
8
9
10
root@geekwolf:~# grep eth0 /proc/interrupts |awk '{print $NF}'
eth0
eth0-fp-0
eth0-fp-1
eth0-fp-2
eth0-fp-3
eth0-fp-4
eth0-fp-5
eth0-fp-6
eth0-fp-7
配置SMP IRQ affinity

(即绑定队列到不同CPU,Kernel>2.4)

方法1:开启系统irqbalance服务

1
2
apt-get -y install irqbalance
service irqbalance start

方法2: 手动绑定

1
2
3
4
5
6
7
8
9
/proc/irq/:该目录下存放的是以IRQ号命名的目录,如/proc/irq/40/,表示中断号为40的相关信息
/proc/irq/[irq_num]/smp_affinity:该文件存放的是CPU位掩码(十六进制)。修改该文件中的值可以改变CPU和某中断的亲和性
/proc/irq/[irq_num]/smp_affinity_list:该文件存放的是CPU列表(十进制)。注意,CPU核心个数用表示编号从0开始,如cpu0,cpu1等,
smp_affinity和smp_affinity_list修改其一即可,下面修改smp_affinity:
echo $bitmask > /proc/irq/IRQ#/smp_affinity
示例(把140号中断绑定到前4个CPU[cpu0-3]上面):
echo f >/proc/irq/140/smp_affinity
CPU位掩码计算

一个十六进制f转换成二进制为1111,每一位表示一个CPU核,最靠右值是最低位即CPU0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Binary Hex
CPU 0 0001 1
CPU 1 0010 2
CPU 2 0100 4
CPU 3 1000 8
其中十六进制2就表示CPU1,十六进制8就表示CPU3
Binary Hex
CPU 0 0001 1
+ CPU 2 0100 4
-----------------------
both 0101 5
其中得出的十六进制和5表示CPU0 和CPU2
Binary Hex
CPU 0 0001 1
CPU 1 0010 2
CPU 2 0100 4
+ CPU 3 1000 8
-----------------------
both 1111 f
4个CPU参与中断,即可设置为f,8个CPU参与中断可设置为ff,以此类推
配置RSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
过滤eth0中断号,绑定到0-7号CPU核上(eth0-fp命名可能有所不同):
root@geekwolf:~# grep eth0-fp /proc/interrupts |awk '{print $1, $NF}'
147: eth0-fp-0
148: eth0-fp-1
149: eth0-fp-2
150: eth0-fp-3
151: eth0-fp-4
152: eth0-fp-5
153: eth0-fp-6
154: eth0-fp-7
echo 1 >/proc/irq/147/smp_affinity
echo 2 >/proc/irq/148/smp_affinity
echo 4 >/proc/irq/149/smp_affinity
echo 8 >/proc/irq/150/smp_affinity
echo 10 >/proc/irq/151/smp_affinity
echo 20 >/proc/irq/152/smp_affinity
echo 40 >/proc/irq/153/smp_affinity
echo 80 >/proc/irq/154/smp_affinity
可以通过top命令查看%si是否均衡分摊到0-7核CPU
注意事项
  1. 启动irqbalance后,手动绑定将失效
  2. 当CPU工作在最高性能模式时,irqbalance会均匀分配中断到其他CPU,节能模式时中断会集中分配到CPU0
  3. 以上设置均以网卡支持多队列为前提,建议手动绑定SMP IRQ affinity
  4. 网卡多队列需tg3,bnx2,bnx2x,b44等驱动的支持,Broadcom的网卡驱动已经内置在内核中向后兼容大部分的2.6内核及大于2.4.24的2.4内核
  5. 笔者实际测试过程中遇到BladeCenter HS23刀片服务器Emulex Corporation OneConnect 10Gb NIC (be3)本身支持多队列,在连接到千兆网环境下无法使用多队列问题,万兆网络下可以使用,只好通过下面RPS/RFS方式实现

RPS/RFS

Receive Packet Steering/Receive Flow Streering,软件方式实现CPU均衡,接收包中断的优化
RPS: 网卡驱动对每一个数据库包根据四元组(SIP,SPORT,DIP,DPORT)生成HASH值,通过HASH值将每个连接和CPU 绑定
RFS: 由于RPS只是单纯的把数据包均衡到不同的CPU上,此时如果应用程序所在CPU和中断处理的CPU不在同一个核,将会对CPU Cache影响很大,RFS的作用就是将应用程序和软中断处理分配到同一个CPU
配置步骤:

根据上述说明一个十六进制f表示四个CPU核,那么均衡到32核即ffffffff

配置RPS
1
2
3
4
5
6
rps_cpus='ffffffffff'
for rxdir in /sys/class/net/eth0/queues/rx-*
do
echo $rps_cpus >$rxdir/rps_cpus
done
配置RFS

RFS扩展了RPS的性能以增加CPU缓存命中率,减少网络延迟,默认是禁用的
/proc/sys/net/core/rps_sock_flow_entries
设置此文件至同时活跃连接数的最大预期值。对于中等服务器负载,推荐值为 32768 。所有输入的值四舍五入至最接近的2的幂
/sys/class/net/device/queues/rx-queue/rps_flow_cnt
将 device 改为想要配置的网络设备名称(例如,eth0),将 rx-queue 改为想要配置的接收队列名称(例如,rx-0)。
将此文件的值设为 rps_sock_flow_entries 除以 N,其中 N 是设备中接收队列的数量。例如,如果 rps_flow_entries 设为 32768,并且有 16 个配置接收队列,那么 rps_flow_cnt 就应设为 2048。对于单一队列的设备,rps_flow_cnt 的值和 rps_sock_flow_entries 的值是一样的`

1
2
3
4
5
6
7
8
9
10
11
ls /sys/class/net/eth0/queues/rx-*|grep queues|wc -l
8
rps_flow_cnt=32768/8=4096
echo 32768 >/proc/sys/net/core/rps_sock_flow_entries
for rxdir in /sys/class/net/eth0/queues/rx-*
do
echo $rps_cpus >$rxdir/rps_cpus
echo $rps_flow_cnt >$rxdir/rps_flow_cnt
done
echo 32768 >/proc/sys/net/core/rps_sock_flow_entries

优化脚本可参考: https://github.com/geekwolf/sa-scripts/blob/master/ops-scripts/performance_tuning/set_rps.sh

网卡常规优化方案


关于发包的优化XPS 还未做测试,有时间在做补充!

参考

  • TCP/UDP压测工具netperf https://sanwen8.cn/p/P8bHgn.html
  • 多队列网卡及网卡中断绑定阐述 http://www.ywnds.com/?p=4380
  • Netperf压测数据分析 http://www.docin.com/p-1654134152.html
  • RHEL7.0 Performance_Tuning_Guide https://access.redhat.com/documentation/zh-CN/Red_Hat_Enterprise_Linux/7/html/Performance_Tuning_Guide/
  • RPS/RFS/RSS 性能测试 http://www.cnblogs.com/Bozh/archive/2013/03/21/2973769.html

Centos6.5部署Zabbix3.2(备忘)

发表于 2016-12-17 | 分类于 系统监控 | 阅读次数
阅读时长 4

配置yum源

1
2
3
4
wget --no-check-certificate http://lug.ustc.edu.cn/wiki/_export/code/mirrors/help/epel?codeblock=0 -O epel.repo
wget --no-check-certificate http://lug.ustc.edu.cn/wiki/_export/code/mirrors/help/epel?codeblock=1 -O epel-testing.repo
yum install -y http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm
rpm -Uvh http://mirror.webtatic.com/yum/el6/latest.rpm

安装LNMP环境及依赖包

1
yum -y install nginx Percona-Server-server-57 Percona-Server-client-57 Percona-Server-devel-57 Percona-Server-tokudb-57 php56w php56w-fpm php56w-mysql gcc-c++ libxml2-devel net-snmp-devel libcurl-devel fping php56w-bcmath php56w-mbstring php56w-gd php56w-xmlwriter php56w-xmlreader

数据库初始化,支持TokuDB

1
2
3
4
5
6
7
8
数据库初始化
mysqld --initialize-insecure --user=mysql --datadir=/data/mysql/data/
启用TokuDB
ps_tokudb_admin --enable -uroot -pgeekwolf
若无法加载tokudb引擎,请查看huge pages是否关闭:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

安装Zabbix

1
2
3
4
5
6
7
wget https://nchc.dl.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Stable/3.2.2/zabbix-3.2.2.tar.gz
groupadd zabbix
useradd -g zabbix -s /sbin/nologin
tar xf zabbix-3.2.2.tar.gz
./configure --enable-server --enable-agent --with-mysql --enable-ipv6 --with-net-snmp --with-libcurl --with-libxml2
make -j8
make install

配置zabbix_agent

1
2
3
4
5
6
7
8
vim /usr/local/etc/zabbix_agentd.conf
PidFile=/tmp/zabbix_agentd.pid
LogFile=/tmp/zabbix_agentd.log
LogFileSize=0
Server=192.168.1.1
ServerActive=192.168.1.1
Hostname=192.168.1.2
UnsafeUserParameters=1

配置zabbix_server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vim /usr/local/etc/zabbix_server.conf
DBHost=192.168.1.1
DBName=zabbix
DBUser=zabbix
DBPassword=zabbix
DebugLevel=3
StartPollers=80
CacheSize=32M
TrendCacheSize=32M
HistoryCacheSize=32M
LogFile=/tmp/zabbix_server.log
AlertScriptsPath=/usr/local/etc/scripts
FpingLocation=/usr/bin/fping
StartPingers=20
HousekeepingFrequency=1
MaxHousekeeperDelete=10000
Timeout=10

部署Zabbix FrontEnd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cd zabbix-3.2.2/
cp frontends/php/* /usr/share/zabbix/
chown apache.apache /usr/share/zabbix -R
mysql>create database zabbix;
mysql>source database/mysql/schema.sql;
mysql>source database/mysql/images.sql;
mysql>source database/mysql/data.sql;
拷贝启动脚本:
cp misc/init.d/fedora/core5/* /etc/rc.d/init.d/
配置Nginx:
vim /etc/nginx/conf.d/zabbix.conf
server {
listen 80;
server_name zbx.simlinux.com;
index index.html index.php;
root /usr/share/zabbix;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

启动agent和server服务

1
2
3
service zabbix_agentd start
service zabbix_server start
service nginx reload

修改php.ini配置:

1
2
3
4
5
6
always_populate_raw_post_data = -1
max_execution_time = 300
max_input_time = 300
data.timezone = PRC
post_max_size=16M
service php-fpm reload

修改数据表引擎和创建分区表

1
2
3
4
5
alter table history engines='tokudb';
alter table history_log engines='tokudb';
alter table history_str engines='tokudb';
alter table history_text engines='tokudb';
alter table trends engines='tokudb';

分区表可参考http://blog.simlinux.com/archives/1776.html

安装Zabbix Web

访问http://192.168.1.1 进行安装,默认账号密码: admin zabbix

遇到的问题

A. Zabbix设置中文显示时,图形部分字体显示方框

解决方法:
Zabbix默认使用DejaVuSan.ttf字体,不支持中文
拷贝本地C:\Windows\Fonts下的微软雅黑字体上传到Zabbix Web目录fonts下,即msyh.ttf
sed -i ‘s/DejaVuSans/msyh/g’ ./include/defines.inc.php

B. Zabbix_server日志提示20434:20161217:105010.997 fping failed: fping6: Address family for hostname not supported
解决方法:
zabbix_server.conf中指定fping和fping6路径
FpingLocation=/usr/sbin/fping
Fping6Location=/usr/sbin/fping6

Zabbix数据库优化总结

发表于 2016-12-10 | 分类于 系统监控 | 阅读次数
阅读时长 9

目的: 快速清理历史数据,并减少数据存储容量
方法: 历史表使用分区表(删除分区表速度快),使用Tokudb引擎(适合大量insert少量update和select等日志表)

环境说明

Zabbix版本: 2.4
涉及表项:
存储不同类型item的历史数据,最终1小时或者1天等段时间的绘图数据从其中获取
history、history_log、history_str、history_text、history_uint
存储不同类型item的历史趋势数据,每隔一小时从历史数据中统计一次,并计算统计区间的平均值,最大值,最小值trends、trends_uint

操作步骤

关闭zabbix的housekeeper功能

备份原有历史数据表
1
2
3
4
5
6
7
rename table history to history_bak;
rename table history_log to history_log_bak;
rename table history_str to history_str_bak;
rename table history_text to history_text_bak;
rename table history_unit to history_unit_bak;
rename table trends to trends_bak;
rename table trends_unit to trends_unit_bak;
创建新表(使用tokudb引擎)
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
`CREATE TABLE `history` (
`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`value` double(16,4) NOT NULL DEFAULT '0.0000',
`ns` int(11) NOT NULL DEFAULT '0',
KEY `history_1` (`itemid`,`clock`)
) ENGINE=Tokudb DEFAULT CHARSET=utf8;
CREATE TABLE `history_log` (
`id` bigint(20) unsigned NOT NULL,
`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`timestamp` int(11) NOT NULL DEFAULT '0',
`source` varchar(64) NOT NULL DEFAULT '',
`severity` int(11) NOT NULL DEFAULT '0',
`value` text NOT NULL,
`logeventid` int(11) NOT NULL DEFAULT '0',
`ns` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `history_log_2` (`itemid`,`id`),
KEY `history_log_1` (`itemid`,`clock`)
) ENGINE=Tokudb DEFAULT CHARSET=utf8;
CREATE TABLE `history_str` (
`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`value` varchar(255) NOT NULL DEFAULT '',
`ns` int(11) NOT NULL DEFAULT '0',
KEY `history_str_1` (`itemid`,`clock`)
) ENGINE=Tokudb DEFAULT CHARSET=utf8;
CREATE TABLE `history_text` (
`id` bigint(20) unsigned NOT NULL,
`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`value` text NOT NULL,
`ns` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `history_text_2` (`itemid`,`id`),
KEY `history_text_1` (`itemid`,`clock`)
) ENGINE=Tokudb DEFAULT CHARSET=utf8;
CREATE TABLE `history_uint` (
`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`value` bigint(20) unsigned NOT NULL DEFAULT '0',
`ns` int(11) NOT NULL DEFAULT '0',
KEY `history_uint_1` (`itemid`,`clock`)
) ENGINE=Tokudb DEFAULT CHARSET=utf8;
CREATE TABLE `trends` (
`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`num` int(11) NOT NULL DEFAULT '0',
`value_min` double(16,4) NOT NULL DEFAULT '0.0000',
`value_avg` double(16,4) NOT NULL DEFAULT '0.0000',
`value_max` double(16,4) NOT NULL DEFAULT '0.0000',
PRIMARY KEY (`itemid`,`clock`)
) ENGINE=Tokudb DEFAULT CHARSET=utf8;
CREATE TABLE `trends_uint` (
`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`num` int(11) NOT NULL DEFAULT '0',
`value_min` bigint(20) unsigned NOT NULL DEFAULT '0',
`value_avg` bigint(20) unsigned NOT NULL DEFAULT '0',
`value_max` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`itemid`,`clock`)
) ENGINE=Tokudb DEFAULT CHARSET=utf8;
更改索引结构(新版本无需更改)
1
2
3
4
5
6
7
8
ALTER TABLE history_text DROP PRIMARY KEY,
ADD INDEX (id),
DROP INDEX history_text_2,
ADD INDEX history_text_2 (itemid, id);
ALTER TABLE history_log DROP PRIMARY KEY,
ADD INDEX (id),
DROP INDEX history_log_2,
ADD INDEX history_log_2 (itemid, id);
创建存储过程

partition_create 增加分区存储过程
partition_drop 删除分区存储过程
partition_maintenance 分区维护(创建删除逻辑)存储过程
partition_maintenance_all 分区维护(调用partition_maintenance )
partition_verify 检查分区、创建第一个分区的存储过程

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
**************************************partition_create**************************************
DELIMITER $$
CREATE PROCEDURE `partition_create`(SCHEMANAME varchar(64), TABLENAME varchar(64), PARTITIONNAME varchar(64), CLOCK int)
BEGIN
/*
SCHEMANAME = The DB schema in which to make changes
TABLENAME = The table with partitions to potentially delete
PARTITIONNAME = The name of the partition to create
*/
/*
Verify that the partition does not already exist
*/
DECLARE RETROWS INT;
SELECT COUNT(1) INTO RETROWS
FROM information_schema.partitions
WHERE table_schema = SCHEMANAME AND table_name = TABLENAME AND partition_description &gt;= CLOCK;
IF RETROWS = 0 THEN
/*
1\. Print a message indicating that a partition was created.
2\. Create the SQL to create the partition.
3\. Execute the SQL from #2.
*/
SELECT CONCAT( "partition_create(", SCHEMANAME, ",", TABLENAME, ",", PARTITIONNAME, ",", CLOCK, ")" ) AS msg;
SET @sql = CONCAT( 'ALTER TABLE ', SCHEMANAME, '.', TABLENAME, ' ADD PARTITION (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', CLOCK, '));' );
PREPARE STMT FROM @sql;
EXECUTE STMT;
DEALLOCATE PREPARE STMT;
END IF;
END$$
DELIMITER ;
**************************************partition_drop**************************************
DELIMITER $$
CREATE PROCEDURE `partition_drop`(SCHEMANAME VARCHAR(64), TABLENAME VARCHAR(64), DELETE_BELOW_PARTITION_DATE BIGINT)
BEGIN
/*
SCHEMANAME = The DB schema in which to make changes
TABLENAME = The table with partitions to potentially delete
DELETE_BELOW_PARTITION_DATE = Delete any partitions with names that are dates older than this one (yyyy-mm-dd)
*/
DECLARE done INT DEFAULT FALSE;
DECLARE drop_part_name VARCHAR(16);
/*
Get a list of all the partitions that are older than the date
in DELETE_BELOW_PARTITION_DATE. All partitions are prefixed with
a "p", so use SUBSTRING TO get rid of that character.
*/
DECLARE myCursor CURSOR FOR
SELECT partition_name
FROM information_schema.partitions
WHERE table_schema = SCHEMANAME AND table_name = TABLENAME AND CAST(SUBSTRING(partition_name FROM 2) AS UNSIGNED) &lt; DELETE_BELOW_PARTITION_DATE;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
/*
Create the basics for when we need to drop the partition. Also, create
@drop_partitions to hold a comma-delimited list of all partitions that
should be deleted.
*/
SET @alter_header = CONCAT("ALTER TABLE ", SCHEMANAME, ".", TABLENAME, " DROP PARTITION ");
SET @drop_partitions = "";
/*
Start looping through all the partitions that are too old.
*/
OPEN myCursor;
read_loop: LOOP
FETCH myCursor INTO drop_part_name;
IF done THEN
LEAVE read_loop;
END IF;
SET @drop_partitions = IF(@drop_partitions = "", drop_part_name, CONCAT(@drop_partitions, ",", drop_part_name));
END LOOP;
IF @drop_partitions != "" THEN
/*
1\. Build the SQL to drop all the necessary partitions.
2\. Run the SQL to drop the partitions.
3\. Print out the table partitions that were deleted.
*/
SET @full_sql = CONCAT(@alter_header, @drop_partitions, ";");
PREPARE STMT FROM @full_sql;
EXECUTE STMT;
DEALLOCATE PREPARE STMT;
SELECT CONCAT(SCHEMANAME, ".", TABLENAME) AS `table`, @drop_partitions AS `partitions_deleted`;
ELSE
/*
No partitions are being deleted, so print out "N/A" (Not applicable) to indicate
that no changes were made.
*/
SELECT CONCAT(SCHEMANAME, ".", TABLENAME) AS `table`, "N/A" AS `partitions_deleted`;
END IF;
END$$
DELIMITER ;
**************************************partition_verify**************************************
DELIMITER $$
CREATE PROCEDURE `partition_verify`(SCHEMANAME VARCHAR(64), TABLENAME VARCHAR(64), HOURLYINTERVAL INT(11))
BEGIN
DECLARE PARTITION_NAME VARCHAR(16);
DECLARE RETROWS INT(11);
DECLARE FUTURE_TIMESTAMP TIMESTAMP;
/*
* Check if any partitions exist for the given SCHEMANAME.TABLENAME.
*/
SELECT COUNT(1) INTO RETROWS
FROM information_schema.partitions
WHERE table_schema = SCHEMANAME AND table_name = TABLENAME AND partition_name IS NULL;
/*
* If partitions do not exist, go ahead and partition the table
*/
IF RETROWS = 1 THEN
/*
* Take the current date at 00:00:00 and add HOURLYINTERVAL to it. This is the timestamp below which we will store values.
* We begin partitioning based on the beginning of a day. This is because we don't want to generate a random partition
* that won't necessarily fall in line with the desired partition naming (ie: if the hour interval is 24 hours, we could
* end up creating a partition now named "p201403270600" when all other partitions will be like "p201403280000").
*/
SET FUTURE_TIMESTAMP = TIMESTAMPADD(HOUR, HOURLYINTERVAL, CONCAT(CURDATE(), " ", '00:00:00'));
SET PARTITION_NAME = DATE_FORMAT(CURDATE(), 'p%Y%m%d%H00');
-- Create the partitioning query
SET @__PARTITION_SQL = CONCAT("ALTER TABLE ", SCHEMANAME, ".", TABLENAME, " PARTITION BY RANGE(`clock`)");
SET @__PARTITION_SQL = CONCAT(@__PARTITION_SQL, "(PARTITION ", PARTITION_NAME, " VALUES LESS THAN (", UNIX_TIMESTAMP(FUTURE_TIMESTAMP), "));");
-- Run the partitioning query
PREPARE STMT FROM @__PARTITION_SQL;
EXECUTE STMT;
DEALLOCATE PREPARE STMT;
END IF;
END$$
DELIMITER ;
**************************************partition_maintenance**************************************
DELIMITER $$
CREATE PROCEDURE `partition_maintenance`(SCHEMA_NAME VARCHAR(32), TABLE_NAME VARCHAR(32), KEEP_DATA_DAYS INT, HOURLY_INTERVAL INT, CREATE_NEXT_INTERVALS INT)
BEGIN
DECLARE OLDER_THAN_PARTITION_DATE VARCHAR(16);
DECLARE PARTITION_NAME VARCHAR(16);
DECLARE OLD_PARTITION_NAME VARCHAR(16);
DECLARE LESS_THAN_TIMESTAMP INT;
DECLARE CUR_TIME INT;
CALL partition_verify(SCHEMA_NAME, TABLE_NAME, HOURLY_INTERVAL);
SET CUR_TIME = UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-%d 00:00:00'));
SET @__interval = 1;
create_loop: LOOP
IF @__interval &gt; CREATE_NEXT_INTERVALS THEN
LEAVE create_loop;
END IF;
SET LESS_THAN_TIMESTAMP = CUR_TIME + (HOURLY_INTERVAL * @__interval * 3600);
SET PARTITION_NAME = FROM_UNIXTIME(CUR_TIME + HOURLY_INTERVAL * (@__interval - 1) * 3600, 'p%Y%m%d%H00');
IF(PARTITION_NAME != OLD_PARTITION_NAME) THEN
CALL partition_create(SCHEMA_NAME, TABLE_NAME, PARTITION_NAME, LESS_THAN_TIMESTAMP);
END IF;
SET @__interval=@__interval+1;
SET OLD_PARTITION_NAME = PARTITION_NAME;
END LOOP;
SET OLDER_THAN_PARTITION_DATE=DATE_FORMAT(DATE_SUB(NOW(), INTERVAL KEEP_DATA_DAYS DAY), '%Y%m%d0000');
CALL partition_drop(SCHEMA_NAME, TABLE_NAME, OLDER_THAN_PARTITION_DATE);
END$$
DELIMITER ;
**************************************partition_maintenance_all**************************************
DELIMITER $$
CREATE PROCEDURE `partition_maintenance_all`(SCHEMA_NAME VARCHAR(32))
BEGIN
CALL partition_maintenance(SCHEMA_NAME, 'history', 90, 24, 30);
#针对zabbix数据库(调用时传入zabbix数据库的库名)的history表创建分区,数据保留90天,分区时间间隔为24小时,每次创建30个分区
CALL partition_maintenance(SCHEMA_NAME, 'history_log', 90, 24, 30);
CALL partition_maintenance(SCHEMA_NAME, 'history_str', 90, 24, 30);
CALL partition_maintenance(SCHEMA_NAME, 'history_text', 90, 24, 30);
CALL partition_maintenance(SCHEMA_NAME, 'history_uint', 90, 24, 30);
CALL partition_maintenance(SCHEMA_NAME, 'trends', 730, 24, 15);
CALL partition_maintenance(SCHEMA_NAME, 'trends_uint', 730, 24, 30);
END$$
DELIMITER ;
设置分区表维护Event Scheduler
1
2
3
4
5
6
7
8
9
10
11
开启数据库Event Scheduler功能
set GLOBAL event_scheduler=ON;
创建事件zbx_partition_maintenance 每月1号1点执行partition_maintenance_all:
DELIMITER $$
CREATE EVENT `zbx_partition_maintenance`
ON SCHEDULE every 1 month starts date_add(date_add(date_sub(curdate(),interval day(curdate())-1 day),interval 1 month),interval 1 HOUR)
ON COMPLETION PRESERVE DO
BEGIN
CALL partition_maintenance_all('zabbix') ;
END$$
DELIMITER ;
123…9
Geekwolf

Geekwolf

DevOps | Docker | Python | k8s

89 日志
12 分类
68 标签
RSS
GitHub Weibo
友情链接
  • 旧版博客
  • nolinux
  • 峰云就她了
  • 懒懒的天空
  • 普拉多VX
  • 枯木磊
© 2012 - 2018 Geekwolf

Hosted by Coding Pages