├── README.md ├── MongoDB ├── mongodb.conf ├── mongodb.yaml ├── mongodb_rep.yaml └── mongodb_install.sh ├── Zabbix ├── Zabbix触发器和监控项设置时间范围.md ├── Zabbix设置自定义监控项之——监控tcp连接状态.md ├── tcp-status.sh ├── Zabbix 设置自动添加主机两种方法(自动注册、自动发现).md ├── Zabbix监控图标中文乱码(包含Docker安装乱码).md ├── Zabbix邮件预警-这个坑我跳了不止一次.md ├── Zabbix-proxy和Zabbix-agent源码安装.md ├── Zabbix集成Cloud Alert(睿象云)实现电话短信预警.md ├── Zabbix-Grafana数据可视化.md ├── Zabbix监控ActiveMQ.md └── zabbix-tcp-connection.xml ├── Shell └── tcp-status.sh ├── AWS └── AWS云创建EC2与使用注意事项-踩坑记录.md ├── 运维常用应用的日志分割.md ├── jvm优化 └── java应用cpu过高,内存占用较多分析.md └── Docker └── docker日志.md /README.md: -------------------------------------------------------------------------------- 1 | # LinuxGuide 2 | -------------------------------------------------------------------------------- /MongoDB/mongodb.conf: -------------------------------------------------------------------------------- 1 | bind_ip=0.0.0.0 2 | port=27037 3 | unixSocketPrefix=/opt/mongodb 4 | dbpath=/opt/mongodb/data/ 5 | logpath=/opt/mongodb/logs/mongodb.log 6 | pidfilepath=/opt/mongodb/logs/mongod.pid 7 | logRotate=reopen 8 | logappend=true 9 | listenBacklog=128 10 | maxConns=500 11 | directoryperdb=true 12 | auth=true 13 | fork=true 14 | journal=true 15 | profile=2 16 | slowms=200 17 | -------------------------------------------------------------------------------- /MongoDB/mongodb.yaml: -------------------------------------------------------------------------------- 1 | systemLog: 2 | destination: file 3 | path: "/opt/mongodb/logs/mongodb.log" 4 | logAppend: true 5 | timeStampFormat: "iso8601-local" 6 | processManagement: 7 | fork: true 8 | pidFilePath: "/opt/mongodb/logs/mongod.pid" 9 | net: 10 | bindIp: "0.0.0.0" 11 | port: 27017 12 | maxIncomingConnections: 500 13 | wireObjectCheck: true 14 | unixDomainSocket: 15 | enabled: true 16 | pathPrefix: /opt/mongodb/ 17 | filePermissions: 0700 18 | storage: 19 | dbPath: "/opt/mongodb/data/" 20 | indexBuildRetry: true 21 | journal: 22 | enabled: true 23 | commitIntervalMs: 100 24 | directoryPerDB: true 25 | syncPeriodSecs: 60 26 | engine: "wiredTiger" 27 | wiredTiger: 28 | engineConfig: 29 | journalCompressor: "snappy" 30 | collectionConfig: 31 | blockCompressor: "snappy" 32 | indexConfig: 33 | prefixCompression: true 34 | security: 35 | authorization: "enabled" 36 | operationProfiling: 37 | mode: "all" 38 | slowOpThresholdMs: 200 39 | slowOpSampleRate: 1.0 40 | 41 | -------------------------------------------------------------------------------- /MongoDB/mongodb_rep.yaml: -------------------------------------------------------------------------------- 1 | systemLog: 2 | destination: file 3 | path: "/opt/mongodb/logs/mongodb.log" 4 | logAppend: true 5 | timeStampFormat: "iso8601-local" 6 | processManagement: 7 | fork: true 8 | pidFilePath: "/opt/mongodb/logs/mongod.pid" 9 | net: 10 | bindIp: "0.0.0.0" 11 | port: 27017 12 | maxIncomingConnections: 500 13 | wireObjectCheck: true 14 | storage: 15 | dbPath: "/opt/mongodb/data/" 16 | #indexBuildRetry: true 17 | journal: 18 | enabled: true 19 | commitIntervalMs: 100 20 | directoryPerDB: true 21 | syncPeriodSecs: 60 22 | engine: "wiredTiger" 23 | wiredTiger: 24 | engineConfig: 25 | journalCompressor: "snappy" 26 | collectionConfig: 27 | blockCompressor: "snappy" 28 | indexConfig: 29 | prefixCompression: true 30 | security: 31 | authorization: "disabled" # 配置好后需要开启验证 32 | # keyFile: 33 | # clusterAuthMode: "keyFile" 34 | operationProfiling: 35 | mode: "all" 36 | slowOpThresholdMs: 200 37 | slowOpSampleRate: 1.0 38 | replication: 39 | oplogSizeMB: 2048 40 | replSetName: "fymongodb" 41 | enableMajorityReadConcern: true -------------------------------------------------------------------------------- /Zabbix/Zabbix触发器和监控项设置时间范围.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | 3 | 4 | 5 | ## 一、实际业务场景 6 | 7 | ### 业务问题 8 | 9 | 最近在监控 `ActiveMQ` 的阻塞消息时,发现每天0点都有预警,然后进行排查,0 点确实是有阻塞消息,这个阻塞消息的存在,是因为 0点系统进行结算,会产生大量的消息,并且有一些结算任务,导致消息会有阻塞。但是这个阻塞是正常的,我不想进行预警,那么有以下方法可以禁止这个预警: 10 | 11 | - 设置监控时间 12 | 13 | 就是在某个时间段不去获取该监控项的数据,这个方法好像是可以,但是隐隐感觉有些不妥。 14 | 15 | - 设置触发器时间(推荐方法) 16 | 17 | 就是监控的数据我获取,但是在某个时间段该触发器无效。这个好像还不错。 18 | 19 | - 设置用户报警媒介启用时间 20 | 21 | 就是设置该用户在某个时间段可以收到报警,某个时间段不接受报警。这个设置得背锅哦。 22 | 23 | 24 | 25 | ### 解决办法 26 | 27 | 经过上面的对比,我觉得还是 设置触发器时间比较适合该需求。所以我们设置触发器监控时间。设置为 0 点0分到 0点 10分,该监控项不预警。 28 | 29 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E8%A7%A6%E5%8F%91%E5%99%A8_%E7%9B%91%E6%8E%A7%E6%97%B6%E9%97%B4_activemq.png) 30 | 31 | 使用到触发器设置范围,也觉得该对 zabbix 设置时间范围配置做个总的记录。 32 | 33 | ## 二、Zabbix触发器和监控项与用户预警设置时间范围配置流程 34 | 35 | ### 一、触发器设置时间范围 36 | 37 | 触发器设置时间范围需要将触发器条件和 触发器时间范围相结合,比如我们有一个需求,**就是我们需要在 时间点 1点到 23点,检查agent 是否活跃,当在这个时间段如果 agent 不活跃的话就进行预警**。 38 | 39 | 首先我们需要创建一个触发器,选择监控项为 `agent.ping`,创建当 `agent.ping=0`时候的表达式。 40 | 41 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E8%AE%BE%E7%BD%AE%E8%A7%A6%E5%8F%91%E5%99%A8%E6%97%B6%E9%97%B4%E8%8C%83%E5%9B%B4.png) 42 | 43 | 然后我们选择表达式构建构造器。选择上面一样的监控项,功能选择 `time() 当前时间` 设置时间范围, 44 | 45 | 注意时间范围的格式是 :HHMMSS,也就是6位数字。 46 | 47 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E8%A7%A6%E5%8F%91%E5%99%A8%E6%97%B6%E9%97%B4%E8%8C%83%E5%9B%B4_%E8%A1%A8%E8%BE%BE%E5%BC%8F.png) 48 | 49 | 这样就ok了。 50 | 51 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E8%A7%A6%E5%8F%91%E5%99%A8%E8%AE%BE%E7%BD%AE%E6%97%B6%E9%97%B4%E8%8C%83%E5%9B%B4_example.png) 52 | 53 | 54 | 55 | ### 二、监控项设置时间范围 56 | 57 | 在创建监控项里面的,自定义时间间隔,可以设置监控范围。 58 | 59 | 示例: 我想在星期一到星期五,全天监控,间隔是 30s, 周六到 周日,全天监控,间隔是 60s. 60 | 61 | | 间隔 | 周期 | 62 | | :--- | :-------------- | 63 | | 30 | 1-5,00:00-24:00 | 64 | | 60 | 6-7,00:00-24:00 | 65 | 66 | 示例2:我想周一到周日全天监控,间隔30s,但是在每天的 0点到 0点10不监控。 67 | 68 | | 间隔 | 周期 | 69 | | :--- | :-------------- | 70 | | 30 | 1-7,00:10-24:00 | 71 | | 0 | 6-7,00:00-00:10 | 72 | 73 | 如果灵活间隔设置为“0”,则在灵活间隔期间不轮询监控项,并在周期结束后根据默认更新间隔恢复轮询。 74 | 75 | 详细监控项自定义间隔见 [官方文档](https://www.zabbix.com/documentation/4.0/zh/manual/config/items/item/custom_intervals) 76 | 77 | ### 三、用户报警设置启用时间 78 | 79 | 该设置在用户基本资料的报警媒介里面。 80 | 81 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%20%E7%94%A8%E6%88%B7%E6%8A%A5%E8%AD%A6%E8%AE%BE%E7%BD%AE%E5%90%AF%E7%94%A8%E6%97%B6%E9%97%B4.png) 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Zabbix/Zabbix设置自定义监控项之——监控tcp连接状态.md: -------------------------------------------------------------------------------- 1 | 在实际监控中,除了官方自带的一些监控项,我们很多时候有一些定制化监控,比如特定的服务、TCP 连接状态等等,这时候就需要自定义监控项。自定义监控项的就是要通过用户自定义的参数来执行监控获取数据。本文将讲讲用户自定义参数和一个用户自定义参数的示例(监控 TCP 连接状态)。 2 | 3 | ### 一、用户自定义参数 4 | 5 | [官方文档](https://www.zabbix.com/documentation/4.0/zh/manual/config/items/userparameters) 6 | 7 | 用户定义参数可以用来帮助用户实现通过 `Zabbix agent` 执行非 `Zabbix` 原生的 `agent check`。 8 | 9 | 在 agent 的配置文件中配置参数设置 `UserParameter` 。 10 | 11 | 一条用户自定义参数配置应当使用以下语法: 12 | 13 | ``` 14 | UserParameter=, 15 | ``` 16 | 17 | key 是对应监控项键值的值,command 是获取 监控项的值的命令,可以是脚本。 18 | 19 | key 可以传递参数,形如 key[*],表示接受监控项传来的所有参数,在 command 可以使用 $@,$1, $2 等获取传入的参数。 20 | 21 | `Zabbix agent` 执行的命令最多可以返回 512KB 的数据给 `zabbix server`。但是,请注意,最终可以存储在数据库中的文本值,在 `MySQL` 上的限制为 64KB 。 22 | 23 | #### 用户自定义参数示例 24 | 25 | ``` 26 | UserParameter=ping,echo 1 27 | ``` 28 | 29 | 代理将始终使用'ping'键为一个监控项返回'1'。 30 | 31 | 一个更复杂的例子: 32 | 33 | ``` 34 | UserParameter=mysql.ping,mysqladmin -uroot ping | grep -c alive 35 | ``` 36 | 37 | 如果MySQL服务器是活动状态,代理将返回'1',否则为0。 38 | 39 | ``` 40 | UserParameter=tcp.status[*],/bin/bash /opt/scripts/tcp_status.sh $1 41 | ``` 42 | 43 | 44 | 45 | ### 二、配置 监控 TCP 连接状态 46 | 47 | #### 配置 `zabbix agent` 48 | 49 | 更改 `zabbix agent` 配置文件 50 | 51 | ```bash 52 | sudo echo "UserParameter=tcp.status[*],/bin/bash /opt/scripts/tcp_status.sh \$1 " >>/etc/zabbix/zabbix_agentd.conf 53 | ``` 54 | 55 | 下载监控脚本 56 | 57 | ```bash 58 | # 创建目录 59 | sudo mkdir /opt/scripts/ 60 | # 下载脚本,该链接有时间期限,github地址:https://github.com/tobewithyou1996/LinuxGuide/tree/master/Shell 61 | sudo wget 'https://djxlsp.oss-cn-shenzhen.aliyuncs.com/shell/tcp-status.sh?OSSAccessKeyId=LTAI8hlsoWKOIPS8&Expires=1561404848&Signature=Si3RT4GdkEVKHrIgR7UaayPYcdU%3D' -O /opt/scripts/tcp_status.sh 62 | # 更改脚本的所有者和所属组 63 | sudo chown zabbix:zabbix /opt/scripts/tcp_status.sh 64 | # 更改脚本的权限 65 | sudo chmod 744 /opt/scripts/tcp_status.sh 66 | ### 重启zabbix agent 67 | # centos6 68 | sudo service zabbix-agent restart 69 | # centos7 70 | sudo systemctl restart zabbix-agent 71 | ``` 72 | 73 | #### 导入监控模板 74 | 75 | `xml` 文件: https://github.com/tobewithyou1996/LinuxGuide/blob/master/Zabbix/zabbix-tcp-connection.xml 76 | 77 | 选择导入该模板,该模板包含 一个应用集、11个监控项、1个触发器、一个图形。 78 | 79 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_tcp_%E7%9B%91%E6%8E%A7_%E6%A8%A1%E6%9D%BF.png) 80 | 81 | 然后将该模板链接到主机,这样就可以监控对应的tcp连接状态数据。 82 | 83 | **监控数据** 84 | 85 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_mointer_tcp_data.png) 86 | 87 | **监控图表** 88 | 89 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_mointer_tcp_pic.png) 90 | 91 | -------------------------------------------------------------------------------- /Shell/tcp-status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #this script is used to get tcp and udp connetion status 3 | #tcp status 4 | metric=$1 5 | tmp_file=/tmp/tcp_status.txt 6 | /bin/netstat -an|awk '/^tcp/{++S[$NF]}END{for(a in S) print a,S[a]}' > $tmp_file 7 | 8 | case $metric in 9 | closed) 10 | output=$(awk '/CLOSED/{print $2}' $tmp_file) 11 | if [ "$output" == "" ];then 12 | echo 0 13 | else 14 | echo $output 15 | fi 16 | ;; 17 | listen) 18 | output=$(awk '/LISTEN/{print $2}' $tmp_file) 19 | if [ "$output" == "" ];then 20 | echo 0 21 | else 22 | echo $output 23 | fi 24 | ;; 25 | synrecv) 26 | output=$(awk '/SYN_RECV/{print $2}' $tmp_file) 27 | if [ "$output" == "" ];then 28 | echo 0 29 | else 30 | echo $output 31 | fi 32 | ;; 33 | synsent) 34 | output=$(awk '/SYN_SENT/{print $2}' $tmp_file) 35 | if [ "$output" == "" ];then 36 | echo 0 37 | else 38 | echo $output 39 | fi 40 | ;; 41 | established) 42 | output=$(awk '/ESTABLISHED/{print $2}' $tmp_file) 43 | if [ "$output" == "" ];then 44 | echo 0 45 | else 46 | echo $output 47 | fi 48 | ;; 49 | timewait) 50 | output=$(awk '/TIME_WAIT/{print $2}' $tmp_file) 51 | if [ "$output" == "" ];then 52 | echo 0 53 | else 54 | echo $output 55 | fi 56 | ;; 57 | closing) 58 | output=$(awk '/CLOSING/{print $2}' $tmp_file) 59 | if [ "$output" == "" ];then 60 | echo 0 61 | else 62 | echo $output 63 | fi 64 | ;; 65 | closewait) 66 | output=$(awk '/CLOSE_WAIT/{print $2}' $tmp_file) 67 | if [ "$output" == "" ];then 68 | echo 0 69 | else 70 | echo $output 71 | fi 72 | ;; 73 | lastack) 74 | output=$(awk '/LAST_ACK/{print $2}' $tmp_file) 75 | if [ "$output" == "" ];then 76 | echo 0 77 | else 78 | echo $output 79 | fi 80 | ;; 81 | finwait1) 82 | output=$(awk '/FIN_WAIT1/{print $2}' $tmp_file) 83 | if [ "$output" == "" ];then 84 | echo 0 85 | else 86 | echo $output 87 | fi 88 | ;; 89 | finwait2) 90 | output=$(awk '/FIN_WAIT2/{print $2}' $tmp_file) 91 | if [ "$output" == "" ];then 92 | echo 0 93 | else 94 | echo $output 95 | fi 96 | ;; 97 | *) 98 | echo -e "\e[033mUsage: sh $0 [closed|closing|closewait|synrecv|synsent|finwait1|finwait2|listen|established|lastack|timewait]\e[0m" 99 | 100 | esac -------------------------------------------------------------------------------- /Zabbix/tcp-status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #this script is used to get tcp and udp connetion status 3 | #tcp status 4 | metric=$1 5 | tmp_file=/tmp/tcp_status.txt 6 | /bin/netstat -an|awk '/^tcp/{++S[$NF]}END{for(a in S) print a,S[a]}' > $tmp_file 7 | 8 | case $metric in 9 | closed) 10 | output=$(awk '/CLOSED/{print $2}' $tmp_file) 11 | if [ "$output" == "" ];then 12 | echo 0 13 | else 14 | echo $output 15 | fi 16 | ;; 17 | listen) 18 | output=$(awk '/LISTEN/{print $2}' $tmp_file) 19 | if [ "$output" == "" ];then 20 | echo 0 21 | else 22 | echo $output 23 | fi 24 | ;; 25 | synrecv) 26 | output=$(awk '/SYN_RECV/{print $2}' $tmp_file) 27 | if [ "$output" == "" ];then 28 | echo 0 29 | else 30 | echo $output 31 | fi 32 | ;; 33 | synsent) 34 | output=$(awk '/SYN_SENT/{print $2}' $tmp_file) 35 | if [ "$output" == "" ];then 36 | echo 0 37 | else 38 | echo $output 39 | fi 40 | ;; 41 | established) 42 | output=$(awk '/ESTABLISHED/{print $2}' $tmp_file) 43 | if [ "$output" == "" ];then 44 | echo 0 45 | else 46 | echo $output 47 | fi 48 | ;; 49 | timewait) 50 | output=$(awk '/TIME_WAIT/{print $2}' $tmp_file) 51 | if [ "$output" == "" ];then 52 | echo 0 53 | else 54 | echo $output 55 | fi 56 | ;; 57 | closing) 58 | output=$(awk '/CLOSING/{print $2}' $tmp_file) 59 | if [ "$output" == "" ];then 60 | echo 0 61 | else 62 | echo $output 63 | fi 64 | ;; 65 | closewait) 66 | output=$(awk '/CLOSE_WAIT/{print $2}' $tmp_file) 67 | if [ "$output" == "" ];then 68 | echo 0 69 | else 70 | echo $output 71 | fi 72 | ;; 73 | lastack) 74 | output=$(awk '/LAST_ACK/{print $2}' $tmp_file) 75 | if [ "$output" == "" ];then 76 | echo 0 77 | else 78 | echo $output 79 | fi 80 | ;; 81 | finwait1) 82 | output=$(awk '/FIN_WAIT1/{print $2}' $tmp_file) 83 | if [ "$output" == "" ];then 84 | echo 0 85 | else 86 | echo $output 87 | fi 88 | ;; 89 | finwait2) 90 | output=$(awk '/FIN_WAIT2/{print $2}' $tmp_file) 91 | if [ "$output" == "" ];then 92 | echo 0 93 | else 94 | echo $output 95 | fi 96 | ;; 97 | *) 98 | echo -e "\e[033mUsage: sh $0 [closed|closing|closewait|synrecv|synsent|finwait1|finwait2|listen|established|lastack|timewait]\e[0m" 99 | 100 | esac -------------------------------------------------------------------------------- /Zabbix/Zabbix 设置自动添加主机两种方法(自动注册、自动发现).md: -------------------------------------------------------------------------------- 1 | 在实际生产环境中,我们可能需要将很多台主机添加到 Zabbix Server 里,我们进行手动添加的话,会比较麻烦、费时,而且还容易出错。所以一般我们会设置主机自动注册。这样就比较方便。 2 | 3 | 官方文档链接 : [点我](https://www.zabbix.com/documentation/4.0/zh/manual/discovery/auto_registration) 4 | 5 | #### 针对zabbix agent 设置参数做下特别说明 6 | 7 | - `Server` 8 | 9 | 指定可以连接本 agent 的 `Zabbix Server` 或者 `Zabbix Proxy` 的 IP 。 10 | 11 | - `ServerActive` 12 | 13 | 参数是用于在 自动注册和 主动监控(监控项)用的参数,设置为 `zabbix server` 或者是 `zabbix proxy` 的 IP。 14 | 15 | - `Hostname` 16 | 17 | 我们需要设置 Hostname ,因为我们将在 动作中的触发条件中使用,如果你没有在`zabbix_agentd.conf`中特别定义*Hostname*, 则服务器将使用agent的系统主机名命名主机。Linux中的系统主机名可以通过运行`hostname`命令获取。最后成功添加的主机名称也是该选项设置的值。 18 | 19 | 20 | 21 | ### 一、 通过 agent 自动注册到 zabbix server (官方) 22 | 23 | **划重点:发起点就是: zabbix-agent** 24 | 25 | **涉及配置:配置---》动作--》自动注册** 26 | 27 | 28 | 29 | 主机自动注册配置涉及两块: 30 | 31 | - agent 配置 32 | - 动作-自动注册 33 | 34 | #### 一、 agent 配置 35 | 36 | 需要配置的参数 37 | 38 | - `Server` : 配置为 `Zabbix Server` 或者 `Zabbix Proxy` 的 IP。 39 | 40 | - `ServerActive` :配置为 `Zabbix Server` 或者 `Zabbix Proxy` 的 IP。如果端口改变了,需要在后面加上端口。 41 | 42 | - `Hostname`:设置主机的名称。 43 | 44 | 我们也可以使用其它参数值进行设置然后在触发条件中,例如 `HostMetadata` 和 `HostMetadataItem` 45 | 46 | #### 二、动作-自动注册 47 | 48 | 配置 ---》 动作 ----》 自动注册 ---》 创建动作。 49 | 50 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E5%8A%A8%E4%BD%9C_%E8%87%AA%E5%8A%A8%E6%B3%A8%E5%86%8C.png) 51 | 52 | 53 | 54 | 动作需要设置触发条件,我们可能只需要将自动发现的符合某个条件主机添加到某个主机群组。所以我们这里需要设置触发条件。可以通过 主机名称、主机元数据、`zabbix proxy` 来设置触发条件。 55 | 56 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E5%8A%A8%E4%BD%9C_%E8%A7%A6%E5%8F%91%E6%9D%A1%E4%BB%B6.png) 57 | 58 | **操作:**也就是自动发现的主机符合前面设置条件后需要设置的操作,比如添加到某个群组,链接到某个模板等等。 59 | 60 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E5%8A%A8%E4%BD%9C_%E8%87%AA%E5%8A%A8%E6%B3%A8%E5%86%8C.png) 61 | 62 | 63 | 64 | #### 注意事项 65 | 66 | - 如果我们设置好了,上面的配置后,但是发现没有主机注册,我们可以看看是不是我们 `zabbix server` 或者 `zabbix proxy `的监听的端口在防火墙(或者是安全组)有没有开放。默认监听端口是 10051。 67 | 68 | - 如果我们可以看到主机注册成功了,但是 agent 的状态一直不是活跃的,那么我们可以看看我们 `zabbix agent` 的监听的端口在防火墙(或者是安全组)没有开放。默认监听端口是 10050。 69 | 70 | 71 | 72 | 73 | 74 | ### 二、通过 zabbix server 自动发现来添加主机 75 | 76 | **划重点:发起点就是: zabbix server** 77 | 78 | **涉及配置:配置---》动作--》自动发现,配置---》自动发现 ** 79 | 80 | #### zabbix agent 配置 81 | 82 | 由于发起点是 `zabbix server`,所以我们在配置参数时,只需要配置 `Server`和 `Hostname`,然后将 `ServerActive`参数注释。如果我们没有注释该参数,则又会进行自动注册了。如果我们没有设置自动注册项的话,该参数不注释也可以的。 83 | 84 | #### Zabbix server 配置 85 | 86 | 设置自动发现规则 87 | 88 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E8%87%AA%E5%8A%A8%E5%8F%91%E7%8E%B0_%E6%B7%BB%E5%8A%A0%E4%B8%BB%E6%9C%BA.png) 89 | 90 | 设置动作-自动发现-创建动作 91 | 92 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E5%8A%A8%E4%BD%9C_%E8%87%AA%E5%8A%A8%E5%8F%91%E7%8E%B0_%E5%88%9B%E5%BB%BA%E5%8A%A8%E4%BD%9C.png) 93 | 94 | 设置动作的触发条件,就是匹配我们自动发现出来的主机,当自动发现的主机符合触发条件,就添加到 指定的主机组和链接到指定的模板。 95 | 96 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E5%8A%A8%E4%BD%9C_%E8%87%AA%E5%8A%A8%E5%8F%91%E7%8E%B0_%E5%8A%A8%E4%BD%9C_%E8%A7%A6%E5%8F%91%E5%99%A8.png) 97 | 98 | 设置操作,链接模板,添加到主机群组。 99 | 100 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_%E5%8A%A8%E4%BD%9C_%E8%87%AA%E5%8A%A8%E5%8F%91%E7%8E%B0_%E5%88%9B%E5%BB%BA%E6%93%8D%E4%BD%9C.png) 101 | 102 | > 我们可以在 `监测---》自动发现`查看到我们自动发现到的主机。 103 | 104 | ### 三 脑洞大开 105 | 106 | #### 脑洞大开一 107 | 108 | 在思考这个场景的过程中,我想过当 `zabbix agent` 没有固定ip(公司内部服务器),我们该如何监控,我想可以通过让该主机自动注册到 `zabbix server`,然后使用 主动发送模式,也就是由 `zabbix-agent` 自动发送监控数据到 `zabbix server`,记住我们这里需要设置所有的监控项类型为 `zabbix agent(主动式)`。 问题点在于: **当客户端IP 变了,zabbix server 是重新添加一个新的 host,还是会自动识别 **,经过测试,发现 zabbix server 不会添加新的主机,也不会更改 之前主机的IP,但是数据是正常采集的,zabbix agent 是会有一个报错。 109 | 110 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_agent_error.png) 111 | 112 | 113 | 114 | #### 脑洞大开二 115 | 116 | 当把 `zabbix server` 放置在内网,没有固定ip,那么是否可以实现监控呢?我思考了下,是发现不可以的,原因有一点,就是 既然 zabbix server 没有固定ip,所以采用的模式是被动,那么在 zabbix -agent 要设置一个 `Server` 参数,这个参数的意义是允许哪个 ip 连接我的 agent 的。但是我们的 zabbix server 有没有固定 IP。所以方法是行不通的。 117 | 118 | -------------------------------------------------------------------------------- /Zabbix/Zabbix监控图标中文乱码(包含Docker安装乱码).md: -------------------------------------------------------------------------------- 1 | 最近在看 `Zabbix 4.0` 版本的官方文档,搭建后图表使用中文发现还是有乱码。之前在 3.0 版本的时候也遇到过,之前有记录。现在针对2个版本的乱码问题的解决做下记录。 2 | 3 | ### Zabbix 4.0 版本 4 | 5 | 乱码之前的图表中文显示: 6 | 7 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_4.0_%E4%B8%AD%E6%96%87%E4%B9%B1%E7%A0%81.png) 8 | 9 | 10 | 11 | 解决办法就是上传中文字体库到 `Zabbix server` 。替换原来图表使用的字体。 12 | 13 | #### 解决思路 14 | 15 | 先找到图表使用的字体,我们在 ` /usr/share/zabbix/assets/fonts`(yum 安装) 可以看到字体文件 `graphfont.ttf` ,这个文件就是图表使用的字体。(如果在该路径找不到此字体,请检查版本或者使用 Find 查找)。 16 | 17 | ```bash 18 | [root@localhost fonts]# ls -l /usr/share/zabbix/assets/fonts 19 | total 0 20 | lrwxrwxrwx 1 root root 33 Jun 10 15:17 graphfont.ttf -> /etc/alternatives/zabbix-web-font 21 | 22 | ``` 23 | 24 | 25 | 26 | 我们可以看到该字体是链接到 `/etc/alternatives/zabbix-web-font`,我们进行查看 `/etc/alternatives/zabbix-web-font`。发现它链接到了 `/usr/share/fonts/dejavu/DejaVuSans.ttf` 27 | 28 | ```bash 29 | [root@localhost fonts]# ll -h /etc/alternatives/zabbix-web-font 30 | lrwxrwxrwx 1 root root 38 Jun 13 14:58 /etc/alternatives/zabbix-web-font -> /usr/share/fonts/dejavu/DejaVuSans.ttf 31 | [root@localhost fonts]# ls -l /usr/share/fonts/dejavu/DejaVuSans.ttf 32 | -rw-r--r-- 1 root root 720012 Feb 27 2011 /usr/share/fonts/dejavu/DejaVuSans.ttf 33 | ``` 34 | 35 | 也就是我们的图表使用的字体`graphfont.ttf` 最终是指向 `/usr/share/fonts/dejavu/DejaVuSans.ttf`。 36 | 37 | 理清楚了这个,我们就可以去找一个中文字体,然后上传到 `/usr/share/fonts/dejavu/`,然后让 `/etc/alternatives/zabbix-web-font` 链接到 `/usr/share/fonts/dejavu/` 里我们上传的新的中文字体。 38 | 39 | #### 解决操作 40 | 41 | - 找中文字体 42 | 43 | 我们直接从我们的windows 系统里面找中文字体。默认路径为 `C:\Windows\Fonts`。我们使用的是楷体。上传到我们 `Zabbix server 服务器` 的 `/usr/share/fonts/dejavu/` 44 | 45 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_4.0%E4%B8%AD%E6%96%87%E5%AD%97%E4%BD%93.png) 46 | 47 | ``` 48 | [root@localhost fonts]# ls -l /usr/share/fonts/dejavu/ 49 | total 16800 50 | -rw-r--r-- 1 root root 611212 Feb 27 2011 DejaVuSans-BoldOblique.ttf 51 | -rw-r--r-- 1 root root 672300 Feb 27 2011 DejaVuSans-Bold.ttf 52 | -rw-r--r-- 1 root root 580168 Feb 27 2011 DejaVuSansCondensed-BoldOblique.ttf 53 | -rw-r--r-- 1 root root 631992 Feb 27 2011 DejaVuSansCondensed-Bold.ttf 54 | -rw-r--r-- 1 root root 576004 Feb 27 2011 DejaVuSansCondensed-Oblique.ttf 55 | -rw-r--r-- 1 root root 643852 Feb 27 2011 DejaVuSansCondensed.ttf 56 | -rw-r--r-- 1 root root 345204 Feb 27 2011 DejaVuSans-ExtraLight.ttf 57 | -rw-r--r-- 1 root root 611556 Feb 27 2011 DejaVuSans-Oblique.ttf 58 | -rw-r--r-- 1 root root 720012 Feb 27 2011 DejaVuSans.ttf 59 | -rw-r--r-- 1 root root 11787328 Aug 9 2018 simkai.ttf 60 | ``` 61 | 62 | 楷体也就是 `simkai.ttf` 63 | 64 | - 替换字体为 `simkai.ttf` 65 | 66 | ```bash 67 | [root@localhost fonts]# rm -f /etc/alternatives/zabbix-web-font 68 | [root@localhost fonts]# ln -s /usr/share/fonts/dejavu/simkai.ttf /etc/alternatives/zabbix-web-font 69 | ``` 70 | 71 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_4.0_%E8%A7%A3%E5%86%B3%E4%B9%B1%E7%A0%81.png) 72 | 73 | ### Zabbix 3.0 版本 74 | 75 | 图表乱码 76 | 77 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_3.0_%E5%9B%BE%E8%A1%A8%E4%B8%AD%E6%96%87%E4%B9%B1%E7%A0%81.png) 78 | 79 | 解决办法和上面大同小异,也是替换字体。 80 | 81 | 这里说下不同之处。就是 上面的 4.0 版本的 `graphfont.ttf` 字体路径是在 `/usr/share/zabbix/assets/fonts`,而 3.0 版本的字体路径是在 `/usr/share/zabbix/fonts` 。 其他的操作是一致的。 82 | 83 | 84 | 85 | 86 | 87 | #### Zabbix 4.0 Docker 版本 图表乱码问题解决 88 | 89 | 字体文件存放于镜像 `zabbix-web-nginx-mysql` 的 `/usr/share/zabbix/assets/fonts/`目录下。 90 | 91 | ```bash 92 | docker cp /tmp/SIMKAI.TTF c9e36aa249a3:/usr/share/zabbix/assets/fonts/ 93 | ``` 94 | 95 | 然后我们登录到容器里面 96 | 97 | ```bash 98 | # 将后缀名 TTF 改为 ttf 99 | [root@c9e36aa249a3 fonts]# mv /usr/share/zabbix/assets/fonts/SIMKAI.TTF /usr/share/zabbix/assets/fonts/SIMKAI.ttf 100 | # 编辑文件 /usr/share/zabbix/include/defines.inc.php,大约在69行。将 DejaVuSans 更改为 SIMKAI 101 | [root@c9e36aa249a3 fonts]# vi /usr/share/zabbix/include/defines.inc.php 102 | # 更改前 103 | define('ZBX_GRAPH_FONT_NAME', 'DejaVuSans'); // font file name 104 | # 更改后 105 | define('ZBX_GRAPH_FONT_NAME', 'SIMKAI'); // font file name 106 | ``` 107 | 108 | 然后刷新界面,就可以正常显示了。 109 | 110 | 如果是使用的 镜像 `zabbix-web-apache-mysql` ,和 镜像 `zabbix-web-nginx-mysql` 的操作一致。 111 | 112 | -------------------------------------------------------------------------------- /Zabbix/Zabbix邮件预警-这个坑我跳了不止一次.md: -------------------------------------------------------------------------------- 1 | 每每碰到 `Zabbix`,我发现配置邮件预警这个坑,我必须要跳进去,跟它是有八辈子的仇哦,哎,接下来数数这些坑。看看你遇到过类似的吗? 2 | 3 | #### Zabbix 预警配置流程 4 | 5 | 6 | 7 | 监控项---》触发器---》动作---》报警媒介类型---》用户报警媒介。 8 | 9 | 10 | 11 | ### 第一坑 云服务器厂商封25端口之坑 12 | 13 | 阿里云、腾讯云这些服务器厂商都限制使用 TCP 25 端口连接外部地址。如果我们一直使用 25 端口进行连接的话,你是永远发送不出邮件的,虽然说是可以解封,但是 99.9% 是解封不成功的,如果你解封成功了,可能是老天实在是看不下去了,让阿里工作人员犯晕给你解封了。 14 | 15 | **跳坑:** 坑是自己掉进去的,爬也要爬出来,使用 465 端口,前提是你的邮件服务器开启了绑定 465 端口。 16 | 17 | 那么如果我们使用的不知名的服务器厂商,我不知道 25 端口是否被封了,我们可以使用 `telnet`,测试下。 18 | 19 | 示例: 20 | 21 | ```bash 22 | [root@iZwz9cdow8llyjlb9lglu4Z ~]# telnet smtp.qq.com 25 23 | Trying 14.18.245.164... 24 | telnet: connect to address 14.18.245.164: Connection timed out 25 | [root@iZwz9cdow8llyjlb9lglu4Z ~]# telnet smtp.163.com 25 26 | Trying 220.181.12.13... 27 | telnet: connect to address 220.181.12.13: Connection timed out 28 | [root@iZwz9cdow8llyjlb9lglu4Z ~]# telnet smtp.qq.com 465 29 | Trying 14.17.57.241... 30 | Connected to smtp.qq.com. 31 | Escape character is '^]'. 32 | [root@iZwz9cdow8llyjlb9lglu4Z ~]# telnet smtp.163.com 465 33 | Trying 220.181.12.13... 34 | Connected to smtp.163.com. 35 | Escape character is '^]'. 36 | ``` 37 | 38 | 阿里云有些比较早创建的 `ECS` 是没有限制25端口的,我们是可以使用25端口的。 39 | 40 | 41 | 42 | ### 第二坑 报警媒介配置之坑 43 | 44 | 有的时候我们常常忘记配置报警媒介类型,然后我们就进行预警,但是我们这里并不是讲你是否配置了报警媒介,而是讲邮件配置。 45 | 46 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_email.png) 47 | 48 | 我们这里将示例的是两个配置。 49 | 50 | #### **一、QQ 邮箱** 51 | 52 | 打开 `QQ` 邮箱,点击账户,选择**POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务**。 开启 `POP3/SMTP` 服务,并生成授权码。我们这获取到的授权码是 `fixleucazfkrbadf`。 53 | 54 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/QQ_SMTP.png) 55 | 56 | 然后我们在 `Zabbix` 报警媒介类型,配置Email。 57 | 58 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/QQ_email.png) 59 | 60 | | 名称 | 解释 | 值 | 61 | | --------------- | ------------------------------------------------------------ | ----------------------------------------- | 62 | | SMTP服务器 | 设置SMTP服务器来处理传出的消息.一般组成是 smtp + 域名 | smtp.qq.com | 63 | | SMTP服务器端口 | 设置SMTP服务器端口来处理传出的消息.Zabbix 3.0版本之后*支持此选项。如果我们是可以使用25的话,我们尽量使用25,因为我在使用465的时候,是报错了的 `failed to send email: Timeout was reached: Operation timed out after 40001 milliseconds with 0 out of 0 bytes received`,可能是发送比较多导致连接超时。用不了25的服务器不要又跳坑了。 | 25,465 | 64 | | SMTP HELO | 设置正确的SMTP helo值,通常是域名. | qq.com | 65 | | SMTP电邮 | 发送邮件的邮件地址 | `1120336774@qq.com` | 66 | | 安全链接 | 如果需要SSL 认证就勾选,不需要则选择 无。 | 无 | 67 | | 认证 | 用户和密码 | 用户和密码 | 68 | | 用户名称 和密码 | 用户名,不要只填个`1120336774` 啊,我前面就是填了这个,好久才跳出来。要填`1120336774@qq.com` ,密码填入我们获取的授权码。 | 用户名:`1120336774@qq.com` 密码 12456789 | 69 | 70 | 71 | 72 | #### **二、自己的邮件服务器** 73 | 74 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_uou.png) 75 | 76 | 77 | 78 | 注意事项: 79 | 80 | > 当我们使用 QQ 邮件服务器或者163邮件服务器等,我们如果向同一邮箱发送了比较多的邮件,邮件是很容易被放到垃圾邮箱的。而且当我们使用的是自己的邮件服务器,我们发送比较多的邮件到 QQ 邮件服务器时,我们的邮件服务器会比较容易被 QQ 邮箱标记为 垃圾邮件服务器并加入黑名单。 81 | 82 | [发件邮箱配置官方文档](https://www.zabbix.com/documentation/4.0/zh/manual/config/notifications/media/email) 83 | 84 | ### 第三坑 动作和用户报警媒介之坑 85 | 86 | 一般我们都会创建好,监控项和触发器,但是我们一般会忘记配置动作和用户报警媒介。 87 | 88 | #### **动作:** 89 | 90 | 一个动作由操作(例如发出通知)和条件(*什么时间*进行操作)组成,动作包含 触发动作的条件、触发动作后的操作、恢复操作、更新操作。 91 | 92 | 我们一般通过触发器警示度来配置动作,当触发器警示度大于等于警告就发邮件。 93 | 94 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_action.png) 95 | 96 | 97 | 98 | > 具体的动作日志,我们可以在*报表(Reports) → 动作日志(Action log)*中查看。 99 | 100 | #### 用户报警媒介 101 | 102 | 当我们需要将不同的严重性的邮件发送给不同的人,我们需要给每个用户配置报警媒介,当我们配置的预警方式是邮件的时候,我们需要为用户配置报警媒介。 103 | 104 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_baojingmedia.png) 105 | 106 | 如果我们使用的是邮件预警的话,我们就使用的类型是 `Email` 然后在收件人里面填入收件邮箱。 107 | 108 | 109 | 110 | ### 第四坑 预警用户对生成事件的主机没有权限 111 | 112 | 当我们创建了一个用户,并且配置好了,报警媒介,在发生预警的时候,我们的配置的报警媒介的邮箱没有收到邮件,也排除了上面的问题,最终我们检查发现该用户没有对该主机没有权限。我们需要确认你创建的用户对生成事件的主机至少拥有读(read)权限,这样在预警时才能发送到对应用户的报警媒介。 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /Zabbix/Zabbix-proxy和Zabbix-agent源码安装.md: -------------------------------------------------------------------------------- 1 | ## 一 、Zabbix Proxy 2 | 3 | #### 概述 4 | 5 | Zabbix proxy 是一个可以从一个或多个受监控设备采集监控数据并将信息发送到 Zabbix server 的进程,主要是代表 Zabbix server 工作。 所有收集的数据都在本地缓存,然后传输到 proxy 所属的 Zabbix server。 6 | 7 | 部署Zabbix proxy 是可选的,但可能非常有利于分担单个 Zabbix server 的负载。 如果只有代理采集数据,则 Zabbix server 上会减少 CPU 和磁盘 I/O 的开销。 8 | 9 | Zabbix proxy 是无需本地管理员即可集中监控远程位置、分支机构和网络的理想解决方案。 10 | 11 | Zabbix proxy 需要使用独立的数据库。 12 | 13 | ### Zabbix proxy安装 14 | 15 | #### 下载编译 16 | 17 | 下载 18 | 19 | ```bash 20 | cd /tmp && wget https://jaist.dl.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Stable/4.0.9/zabbix-4.0.9.tar.gz 21 | ``` 22 | 23 | 解压 24 | 25 | ``` 26 | tar -xzf zabbix-4.0.9.tar.gz 27 | ``` 28 | 29 | 创建用户和组并创建安装目录 30 | 31 | ```bash 32 | sudo groupadd zabbix 33 | sudo useradd -g zabbix zabbix 34 | sudo mkdir /opt/zabbix-proxy 35 | sudo chown zabbix:zabbix /opt/zabbix-proxy 36 | ``` 37 | 38 | 安装依赖包 39 | 40 | ```bash 41 | yum install -y mysql-devel net-snmp net-snmp-devel libssh2-devel 42 | ``` 43 | 44 | 编译安装 45 | 46 | ```bash 47 | cd zabbix-4.0.9 48 | # 如果想使用其它参数和数据库,使用 ./configure --help 查看选项和参数,使用mysql 作为 proxy 的数据库 49 | ./configure --prefix=/opt/zabbix-proxy --enable-proxy --with-net-snmp --with-mysql --with-ssh2 50 | make install 51 | ``` 52 | 53 | #### 创建Zabbix proxy数据库并导入数据 54 | 55 | Zabbix proxy 是将数据储存在本地,然后传输到 Zabbix Server 的。所以我们需要创建 Zabbix proxy 的数据库。 56 | 57 | ``` 58 | # 创建数据库 59 | create database zabbix_proxy character set utf8 collate utf8_bin; 60 | # 创建用户 61 | grant all privileges on zabbix_proxy.* to zabbix_fy@localhost identified by 'password'; 62 | ``` 63 | 64 | 导入数据,zabbix proxy 不需要将所有的数据库数据都导入,只需要导入 `schema.sql` 65 | 66 | ``` 67 | mysql -u zabbix_fy -p --database zabbix_proxy 注:1、在安装过程中根据安装提示,输入zabbix管理地址、管理员用户名、密码。 46 | > 47 | > ​ 2、zabbix管理地址正确示例:http://zabbix.server.com/zabbix 48 | 49 | 4. 当提示"安装成功"时表示安装成功! 50 | 5. 在 `zabbix server` 管理界面查看是否添加成功。 51 | 52 | ![1561622519970](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_cloud_alert_web.png) 53 | 54 | 出现该脚本就意味着成功了。 55 | 56 | ### 三 、创建分派策略和通知策略 57 | 58 | 这里要严重的注意一点,就是 `CloudAlert` 的 预警级别只有三种,它和 `zabbix` 的级别对应见下表.我们在设置通知策略和分派策略需要注意. 59 | 60 | | zabbix 级别状态 | 参数值 | OneAlert 级别状态 | 61 | | :---------------------- | :----- | :---------------- | 62 | | information (信息) | 1 | 提醒 | 63 | | not_classified (未分类) | 1 | 提醒 | 64 | | warning (警告) | 2 | 警告 | 65 | | average (一般严重) | 2 | 警告 | 66 | | high (严重) | 3 | 严重 | 67 | | disaster (灾难) | 3 | 严重 | 68 | 69 | #### 分派策略 70 | 71 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_Cloud_Alert%E5%88%9B%E5%BB%BA%E5%88%86%E6%B4%BE%E7%AD%96%E7%95%A5.png) 72 | 73 | 74 | 75 | #### 通知策略 76 | 77 | 我们这里只使用到 `CloudAlert` 的通知策略的通知方式中的电话和短信,因为我们 微信已经对接了我们的企业微信预警,邮箱也使用了企业邮箱(进垃圾邮箱的概率更低一些).所以我们这里只设置 通知方式为 电话和短信. 并且只有在严重预警的时候才会触发. 78 | 79 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_CloudAlert_%E9%80%9A%E7%9F%A5%E7%AD%96%E7%95%A5.png) 80 | 81 | 82 | 83 | ### 四 、设置动作 84 | 85 | 在执行安装脚本的时候,默认已经帮我们添加好了动作 `cloudalert action`。但是没有设置触发条件,我们可以设置一下触发条件,触发器示警度 大于等于 **严重** 的时候,进行触发该动作. 86 | 87 | 88 | 89 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_cloudalert_action.png) 90 | 91 | 92 | 93 | ### 五 、生成预警 94 | 95 | 当我们的预警达到阈值,就会触发报警. 96 | 97 | 短信预警内容: 98 | 99 | ``` 100 | 【睿象云】16:48:53,发生严重级别告警:Zabbix agent on Test-186 is unreachable for 5 minutesTest-186 Agent ping:Up (1)Zabbix agent on Test-186 is unreachable for 5 minutes,告警对象:Test-186,告警编号:585679 101 | ``` 102 | 103 | 104 | 105 | ### 六 、卸载Cloud Alert 106 | 107 | #### Web 设置卸载 108 | 109 | - 删除报警媒介 `cloudalert media`。 110 | 111 | - 删除用户群组 `cloudalert group`。 112 | 113 | - 删除用户 `cloudalert`。 114 | 115 | - 删除动作 `cloudalert action`。 116 | 117 | > 有人会说我们没有添加上面的东西,为什么会存在上面这些内容,我们在 执行 `install.sh` 脚本的时候就会添加这些. 118 | 119 | #### 脚本文件卸载 120 | 121 | ​ 删除脚本 删除 `/usr/local/zabbix-server/share/zabbix/alertscripts ` 的`cloudalert`文件夹。 122 | 123 | 124 | 125 | ### 七、注意事项 126 | 127 | #### 错误内容 128 | 129 | 我安装的 `zabbix server ` 是使用的 docker 安装的, 脚本目录是使用的数据卷(我们可以用 `docker inspect container_id ` 查看到)。我们将脚本放置在该数据卷后,安装,也提示成功了,但是在预警的时候,有报错。 130 | 131 | 报错内容如下: 132 | 133 | ```bash 134 | /usr/lib/zabbix/alertscripts/cloudalert/bin 135 | /usr/lib/zabbix/alertscripts/cloudalert/bin/log.sh: line 11: /var/lib/docker/volumes/bb221b74a7d8ad528194867830db0c1ac8fdc31f2ab0ee4456ffce61646fd83a/_data/cloudalert/logs/cloudalert.log: No such file or directory 136 | cp: cannot stat '/var/lib/docker/volumes/bb221b74a7d8ad528194867830db0c1ac8fdc31f2ab0ee4456ffce61646fd83a/_data/cloudalert/logs/cloudalert.log': No such file or directory 137 | /usr/lib/zabbix/alertscripts/cloudalert/bin/log.sh: line 16: /var/lib/docker/volumes/bb221b74a7d8ad528194867830db0c1ac8fdc31f2ab0ee4456ffce61646fd83a/_data/cloudalert/logs/cloudalert.log: No such file or directory 138 | % Total % Received % Xferd Average Speed Time Time Time Current 139 | Dload Upload Total Spent Left Speed 140 | 141 | 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 142 | 100 623 0 89 100 534 1141 6850 --:--:-- --:--:-- --:--:-- 6935 143 | /usr/lib/zabbix/alertscripts/cloudalert/bin/log.sh: line 11: /var/lib/docker/volumes/bb221b74a7d8ad528194867830db0c1ac8fdc31f2ab0ee4456ffce61646fd83a/_data/cloudalert/logs/cloudalert.log: No such file or directory 144 | cp: cannot stat '/var/lib/docker/volumes/bb221b74a7d8ad528194867830db0c1ac8fdc31f2ab0ee4456ffce61646fd83a/_data/cloudalert/logs/cloudalert.log': No such file or directory 145 | /usr/lib/zabbix/alertscripts/cloudalert/bin/log.sh: line 16: /var/lib/docker/volumes/bb221b74a7d8ad528194867830db0c1ac8fdc31f2ab0ee4456ffce61646fd83a/_data/cloudalert/logs/cloudalert.log: No such file or directory 146 | ``` 147 | 148 | #### 解析过程与解决问题 149 | 150 | 从上面我们可以看到是脚本 `log.sh` 执行的过程中报错了,提示没有该文件,它写入的文件是 `/var/lib/docker/volumes/bb221b74a7d8ad528194867830db0c1ac8fdc31f2ab0ee4456ffce61646fd83a/_data/cloudalert/logs/cloudalert.log` ,这个文件路径是 docker 宿主机的日志文件路径,程序在 docker 里面运行,这个路径肯定是获取不到的。我们通过查看 `log.sh` 脚本发现, 151 | 152 | ```bash 153 | #!/bin/bash 154 | if [ -z "$DIR" ]; then 155 | DIR="$( cd "$( dirname "$0" )" && pwd )" 156 | fi 157 | 158 | source $DIR/cloudalert.conf 159 | function log(){ 160 | path=$base_path 161 | log=$path/logs/cloudalert.log 162 | time=`date +%Y-%m-%d\ %H:%M:%S` 163 | echo $time $1 [$2]: "$3" >> $log 164 | bak_log=$path/logs/cloudalert.log_`date +%Y-%m` 165 | if [ ! -f $bak_log ]; 166 | then 167 | cp $log $bak_log 168 | > $log 169 | fi 170 | } 171 | ``` 172 | 173 | 日志路径引用了 `base_path`,这个值是在 `cloudalert.conf` 里定义的. 我们可以在配置文件中看到, `base_path` 值获取的是 宿主机 `cloudalert` 所在的路径. 而不是实际在 docker 容器里的路径。 174 | 175 | ``` 176 | 177 | current_path=/var/lib/docker/volumes/bb221b74a7d8ad528194867830db0c1ac8fdc31f2ab0ee4456ffce61646fd83a/_data/cloudalert/bin 178 | base_path=/var/lib/docker/volumes/bb221b74a7d8ad528194867830db0c1ac8fdc31f2ab0ee4456ffce61646fd83a/_data/cloudalert 179 | agentVersion=1130 180 | AppKey=1233444555666 181 | zabbix_host=http://127.0.0.1 182 | zabbix_url=http://127.0.0.1/api_jsonrpc.php 183 | user=Admin 184 | password=admin 185 | ``` 186 | 187 | 188 | 189 | 我们将 `base_path` 的值更改为 在docker 容器里面的值 `/usr/lib/zabbix/alertscripts/cloudalert` . 190 | 191 | 然后就没有报错了. 192 | 193 | #### 反思 194 | 195 | 这个问题的引起,是我在 宿主机下将执行的该脚本,导致的脚本执行的时候获取的是宿主机的目录,而不是 docker 主机里面的目录路径,在 docker 容器里面执行脚本,即可避免该问题。 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /Zabbix/Zabbix-Grafana数据可视化.md: -------------------------------------------------------------------------------- 1 | 本文转载自: [Grafana数据可视化](https://www.cnblogs.com/clsn/p/9715636.html) 2 | 3 | ## 1.1 Grafana简介 4 | 5 | ### 1.1.1 Grafana是什么? 6 | 7 | 一个类似Kibana的东西,也是对后端的数据进行实时展示,那么Grafana和Kibana有什么区别?在我看来区别不大,不过在大家的日常使用中Kibana是跟着Logstash、ElasticSearch等组件一起使用做日志展示、索引、分析的,造成了一种假象就是Kibana就只有这种用法了,Kibana也可以接入其他数据源的,不过大家最长用的还是展示日志。 8 | 9 | 那么Grafana到底是什么呢?Grafana其实就是一个可视化面板(Dashboard),有着非常漂亮的图表和布局展示,功能齐全的度量仪表盘和图形编辑器,支持Graphite、zabbix、InfluxDB、Prometheus和OpenTSDB作为数据源。随着版本的迭代,支持接入的数据源将会更多。 10 | 11 | 下面看看官方是怎么解释Grafana的: 12 | 13 | > grafana是用于可视化大型测量数据的开源程序,他提供了强大和优雅的方式去创建、共享、浏览数据。dashboard中显示了你不同metric数据源中的数据。 14 | > 15 | > grafana最常用于因特网基础设施和应用分析,但在其他领域也有机会用到,比如:工业传感器、家庭自动化、过程控制等等。 16 | > 17 | > grafana有热插拔控制面板和可扩展的数据源,目前已经支持Graphite、InfluxDB、OpenTSDB、Elasticsearch。 18 | 19 | Grafana官方网站:*https://grafana.com/* 20 | 21 | ### 1.1.2 如何获取Grafana 22 | 23 | 访问Grafana下载页面*https://grafana.com/grafana/download*在这里可获取该软件的全版本。 24 | 25 | 可以按照使用需求,进行下载相应版本。 26 | 27 | ![img](https://img2018.cnblogs.com/blog/1190037/201809/1190037-20180927211249757-1859644340.png) 28 | 29 | ## 1.2 安装Grafana 30 | 31 | ### 1.2.1 系统环境说明 32 | 33 | ``` 34 | [root@monitor.clsn.io /root] 35 | #cat /etc/redhat-release 36 | CentOS Linux release 7.5.1804 (Core) 37 | 38 | [root@monitor.clsn.io /root] 39 | #uname -r 40 | 3.10.0-862.el7.x86_64 41 | 42 | [root@monitor.clsn.io /root] 43 | #systemctl status firewalld.service 44 | ● firewalld.service - firewalld - dynamic firewall daemon 45 | Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled) 46 | Active: inactive (dead) 47 | Docs: man:firewalld(1) 48 | 49 | [root@monitor.clsn.io /root] 50 | #sestatus 51 | SELinux status: disabled 52 | ``` 53 | 54 | ### 1.2.2 安装Grafana 55 | 56 | 在这次安装中,我们使用的是grafana-5.2.4版本。不同版本之间功能存在着一定的差距。 57 | 58 | ``` 59 | [root@monitor.clsn.io /root] 60 | #wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.2.4-1.x86_64.rpm 61 | 62 | [root@monitor.clsn.io /root] 63 | #ls 64 | grafana-5.2.4-1.x86_64.rpm 65 | 66 | [root@monitor.clsn.io /root] 67 | #sudo yum localinstall grafana-5.2.4-1.x86_64.rpm 68 | ``` 69 | 70 | ### 1.2.3 启动Grafana 71 | 72 | ``` 73 | [root@monitor.clsn.io /root] 74 | #systemctl start grafana-server.service 75 | 76 | [root@monitor.clsn.io /root] 77 | #systemctl enable grafana-server.service 78 | ``` 79 | 80 | ### 1.2.4 检查监听端口 81 | 82 | Grafana默认监听端口为3000,可以通过修改配置文件(/etc/grafana/grafana.ini)对其做定制化配置。 83 | 84 | ``` 85 | [root@monitor.clsn.io /root] 86 | #netstat -lntup |grep grafana 87 | tcp6 0 0 :::3000 :::* LISTEN 1333/grafana-server 88 | ``` 89 | 90 | ## 1.3 Grafana的使用 91 | 92 | ### 1.3.1 访问界面 93 | 94 | 通过流量器访问 [http://ip:3000](http://ip:3000/) 即可访问grafana页面,初始用户名与密码均为admin,可在登陆是修改默认密码。 95 | 96 | ![img](https://img2018.cnblogs.com/blog/1190037/201809/1190037-20180927210840252-2134711658.png) 97 | 98 | 登陆成功之后可以先进行创建第一个数据源,以及第一个展示面板。 99 | 100 | ![img](https://img2018.cnblogs.com/blog/1190037/201809/1190037-20180927210851135-1730640629.png) 101 | 102 | ### 1.3.2 Grafana For Zabbix 103 | 104 | 使用Zabbix收集数据,Grafana展示图形,许多的公司都是这么做的。Grafana默认没有zabbix作为数据源,我们需要手动给zabbix安装一个插件,然后再添加进Grafana即可。 105 | 106 | 关于zabbix的安装可以参照以下文章进行配置。 107 | 108 | 惨绿少年博客:*https://www.cnblogs.com/clsn/p/7885990.html* 109 | 110 | zabbix官方文档:*https://www.zabbix.com/documentation/3.4/zh/manual* 111 | 112 | 注:本次使用zabbix版本为3.4.14。 113 | 114 | ``` 115 | [root@monitor.clsn.io /root] 116 | #zabbix_server -V 117 | zabbix_server (Zabbix) 3.4.14 118 | Revision 84877 14 September 2018, compilation time: Sep 14 2018 08:09:35 119 | 120 | Copyright (C) 2018 Zabbix SIA 121 | License GPLv2+: GNU GPL version 2 or later . 122 | This is free software: you are free to change and redistribute it according to 123 | the license. There is NO WARRANTY, to the extent permitted by law. 124 | ``` 125 | 126 | ### 1.3.3 获取grafana for zabbix 插件 127 | 128 | 通过grafana-cli plugins list-remote命令 可以获取到grafana的插件列表。 129 | 130 | ``` 131 | [root@monitor.clsn.io /root] 132 | #grafana-cli plugins list-remote |grep zabbix 133 | id: alexanderzobnin-zabbix-app version: 3.9.1 134 | ``` 135 | 136 | 从上可以查询到插件版本为3.9.1 137 | 138 | **安装插件** 139 | 140 | ``` 141 | [root@monitor.clsn.io /root] 142 | #grafana-cli plugins install alexanderzobnin-zabbix-app 143 | installing alexanderzobnin-zabbix-app @ 3.9.1 144 | from url: https://grafana.com/api/plugins/alexanderzobnin-zabbix-app/versions/3.9.1/download 145 | into: /var/lib/grafana/plugins 146 | 147 | ✔ Installed alexanderzobnin-zabbix-app successfully 148 | Restart grafana after installing plugins . 149 | ``` 150 | 151 | 出现√即为安装成功。在安装完成后无比重启grafana使其生效。 152 | 153 | ``` 154 | [root@monitor.clsn.io /root] 155 | #systemctl restart grafana-server.service 156 | ``` 157 | 158 | ### 1.3.4 配置zabbix源 159 | 160 | 登陆grafana页面,开启zabbix插件。 161 | 162 | ![img](https://img2018.cnblogs.com/blog/1190037/201809/1190037-20180927210954623-1846544813.png) 163 | 164 | 点击enable开启插件。 165 | 166 | ![img](https://img2018.cnblogs.com/blog/1190037/201809/1190037-20180927211000886-1183080310.png) 167 | 168 | 添加zabbix数据源 169 | 170 | ![img](https://img2018.cnblogs.com/blog/1190037/201809/1190037-20180927211017749-353752415.png) 171 | 172 | **相关配置项目说明:** 173 | 174 | | **配置项目** | **说明** | 175 | | ------------ | ------------------------------------------------------------ | 176 | | **Name** | 给数据源起一个名字。 | 177 | | **Default** | 选择默认,意味着数据源将预先选定为新的面板。 | 178 | | **Type** | 选择数据源的类型。 | 179 | | **Url** | 这里的Url是http协议,地址和端口是zabbix-web提供的接口。或为zabbix的api地址。 | 180 | | **Access** | 访问代理,这里选择了proxy表示Grfana通过后端访问,还有direct值表示从浏览器直接访问目录。 | 181 | | **Username** | 输入zabbix的用户名,需要进行认证,一般使用管理员。 | 182 | | **Password** | 输入zabbix用户的密码。 | 183 | 184 | 代理(proxy)访问意味着的Grafana后端将从浏览器代理所有请求,并将它们发送到数据源。这样是有用的,因为它可以消除CORS(交叉来源站点资源)的问题,如消除需要传播到数据源到浏览器的身份验证详细信息。但还支持直接(direct)访问,因为在某些情况下可能用来访问直接根据用例和拓扑结构的Grafana、 用户和数据源的数据源。 185 | 186 | 以上信息都填写完成之后点击Save & Test,一般只要看见Success就表示成功了,下面就可以去利用zabbix中数据添加图形了。 187 | 188 | 下面先引入zabbix自带的dashboard,点击import。 189 | 190 | ![img](https://img2018.cnblogs.com/blog/1190037/201809/1190037-20180927211028461-918380907.png) 191 | 192 | ### 1.3.5 查看zabbix dashboard页面 193 | 194 | ![img](https://img2018.cnblogs.com/blog/1190037/201809/1190037-20180927211035195-369295502.png) 195 | 196 | 使用grafana的好处是对图形的自定义更加简便,通过变更不同的json文件,即可在数据源中查找到想要的结果,然后绘制出图。 197 | 198 | ![img](https://img2018.cnblogs.com/blog/1190037/201809/1190037-20180927211040955-437270551.png) 199 | 200 | ## 1.4 附录 201 | 202 | ### 1.4.1 grafana-cli命令 203 | 204 | 安装插件最简单的方法是使用与grafana捆绑在一起的CLI工具grafana-cli。在修改插件之后发生任何修改之前,grafana服务器需要重新启动。 205 | 206 | **Grafana****插件安装目录** 207 | 208 | 在Linux系统上,grafana-cli会假定grafana插件目录是/var/lib/grafana/plugins。通过指定-pluginsDir标志可以覆盖grafana-cli将要运行的目录。在Windows系统中,必须为每个呼叫指定此参数 209 | 210 | **Grafana-cli****命令说明** 211 | 212 | ```bash 213 | 列出可用的插件 214 | #grafana-cli plugins list-remote 215 | 216 | 安装最新版本的插件 217 | #grafana-cli plugins install 218 | 219 | 安装特定版本的插件 220 | #grafana-cli plugins install 221 | 222 | 列出安装的插件 223 | #grafana-cli plugins ls 224 | 225 | 更新所有安装的插件 226 | #grafana-cli plugins update-all 227 | 228 | 更新一个插件 229 | #grafana-cli plugins update 230 | 231 | 删除一个插件 232 | #grafana-cli plugins remove 233 | ``` 234 | 235 | -------------------------------------------------------------------------------- /MongoDB/mongodb_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ########################## 3 | #Function="install mongodb" 4 | #Date="2019-04-18" 5 | #Auther="djx" 6 | ########################## 7 | [ $(id -u) != "0" ] && echo "Error: You must be root to run this script" && exit 1 8 | logfile="/var/log/mongod_install.log" 9 | softdir="/software" 10 | installdir="/usr/local" 11 | sys_version=$(rpm -q centos-release|cut -d- -f3) 12 | clear 13 | echo "##########################################" 14 | echo "# Auto Install mongodb for centos6/7.x ##" 15 | echo "# Press Ctrl + C to cancel ##" 16 | echo "# Any key to continue ##" 17 | echo "##########################################" 18 | echo "(1) Install Mongodb-3.2" 19 | echo "(2) Install Mongodb-3.4" 20 | echo "(3) Install Mongodb-3.6" 21 | echo "(4) EXIT" 22 | read -p "Please input your choice:" NUM 23 | if [ ${sys_version} == "6" ];then 24 | case $NUM in 25 | 1) 26 | mongodb_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.2.20.tgz" 27 | software_version="mongodb-3.2" 28 | ;; 29 | 2) 30 | mongodb_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.4.10.tgz" 31 | software_version="mongodb-3.4" 32 | ;; 33 | 3) 34 | mongodb_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.6.5.tgz" 35 | software_version="mongodb-3.6" 36 | ;; 37 | 4) 38 | echo -e "\033[41;37m You choice channel! \033[0m" && exit 0 39 | ;; 40 | *) 41 | echo -e "\033[41;37m Input Error! Place input{1|2|3|4} \033[0m" && exit 1 42 | ;; 43 | esac 44 | elif [ ${sys_version} == "7" ];then 45 | case $NUM in 46 | 1) 47 | mongodb_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.2.20.tgz" 48 | software_version="mongodb-3.2" 49 | ;; 50 | 2) 51 | mongodb_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.4.10.tgz" 52 | software_version="mongodb-3.4" 53 | ;; 54 | 3) 55 | mongodb_url="https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.6.5.tgz" 56 | software_version="mongodb-3.6" 57 | ;; 58 | 4) 59 | echo -e "\033[41;37m You choice channel! \033[0m" && exit 0 60 | ;; 61 | *) 62 | echo -e "\033[41;37m Input Error! Place input{1|2|3|4} \033[0m" && exit 1 63 | ;; 64 | esac 65 | else 66 | echo "system must user centos6/7.x." >>${logfile} 2>&1 67 | fi 68 | 69 | sys_init() { 70 | clear 71 | echo -e "\033[42;5m initialization system... \033[0m" 72 | sleep 2 73 | sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config 74 | if [ ${sys_version} == "6" ];then 75 | /etc/init.d/iptables status >/dev/null 76 | [ $? -eq 0 ] && iptables -I INPUT -p tcp --dport 27017 -j ACCEPT 77 | [ $? -eq 0 ] && /etc/init.d/iptables save >${logfile} 2>&1 78 | elif [ ${sys_version} == "7" ];then 79 | systemctl stop firewalld && systemctl disable firewalld 80 | else 81 | echo "system must user centos6/7.x." >>${logfile} 2>&1 82 | fi 83 | yum -y install wget >/dev/null 84 | setenforce 0 85 | echo "sys_init complate!">> ${logfile} 86 | } 87 | 88 | 89 | download_software() { 90 | clear 91 | echo -e "\033[42;5m download software... \033[0m" 92 | sleep 2 93 | if [ ! -d ${softdir} ];then 94 | mkdir ${softdir} && cd ${softdir} 95 | else 96 | cd ${softdir} 97 | fi 98 | for software_url in ${mongodb_url} 99 | do 100 | wget -c ${software_url} --tries=5 101 | if [ $? -eq 0 ];then 102 | for software in `ls` 103 | do 104 | tar zxf $software -C $installdir 105 | done 106 | else 107 | echo "download software error!" >> ${logfile} 2>&1 && exit 1 108 | fi 109 | done 110 | echo "download_software" >>${logfile} 111 | } 112 | 113 | install_software() { 114 | clear 115 | echo -e "\033[42;5m install server... \033[0m" 116 | sleep 2 117 | mongodbdir=$(ls ${installdir}|grep "mongodb-linux-x86_64") 118 | ln -s ${installdir}/${mongodbdir} ${installdir}/mongodb 119 | mkdir ${installdir}/mongodb/{conf,mongoData,mongoLog} 120 | touch ${installdir}/mongodb/mongoLog/mongodb.log 121 | echo "export PATH=\$PATH:${installdir}/mongodb/bin">/etc/profile.d/mongodb.sh 122 | source /etc/profile.d/mongodb.sh 123 | cat >${installdir}/mongodb/conf/mongodb.conf <>${logfile} 138 | } 139 | 140 | start_server() { 141 | clear 142 | echo -e "\033[42;5m configuration server... \033[0m" 143 | if [ ${sys_version} == "6" ];then 144 | cat >/etc/init.d/mongodb-server</dev/null 164 | RETVAL=$? 165 | [ \$RETVAL = 0 ] && touch \${lockfile} 166 | return \$RETVAL 167 | } 168 | stop() { 169 | if test "x\${getpid}" != x; then 170 | action $"Stopping \$prog " /bin/true 171 | killall mongod 172 | fi 173 | RETVAL=\$? 174 | [ \$RETVAL = 0 ] && rm -rf \${lockfile} \${pidfile} 175 | return \$RETVAL 176 | } 177 | case "\$1" in 178 | start) 179 | start 180 | ;; 181 | stop) 182 | stop 183 | ;; 184 | status) 185 | status -p \${pidfile} \${mongod} 186 | RETVAL=\$? 187 | ;; 188 | restart) 189 | stop 190 | start 191 | ;; 192 | *) 193 | echo $"Usage: \$0 {start|status|stop|restart}" 194 | exit 1 195 | esac 196 | exit \${RETVAL} 197 | EOF 198 | cd / 199 | chmod +x /etc/init.d/mongodb-server 200 | chkconfig mongodb-server on 201 | service mongodb-server start 202 | elif [ ${sys_version} == "7" ];then 203 | cat >/usr/lib/systemd/system/mongod.service<>${logfile} 2>&1 216 | else 217 | echo "install occer error,please see ${logfile}" && exit 1 218 | fi 219 | } 220 | 221 | 222 | check_server() { 223 | clear 224 | echo -e "\033[42;5m check server status... \033[0m" 225 | server_port=$(netstat -lntup|grep mongod|wc -l) 226 | server_proc=$(ps -ef |grep mongodb.conf|grep -v grep|wc -l) 227 | if [ ${server_port} -gt 0 -a ${server_port} -gt 0 ];then 228 | echo -e "\033[42;37m mongodb-server install successful! \033[0m" 229 | echo -e "\033[42;37m version:${software_version} \033[0m" 230 | echo -e "\033[42;37m bashpath:${installdir}/mongodb \033[0m" 231 | else 232 | echo "install occer error,please see ${logfile}" && exit 1 233 | fi 234 | } 235 | 236 | main() { 237 | sys_init 238 | download_software 239 | install_software 240 | start_server 241 | check_server 242 | } 243 | 244 | main -------------------------------------------------------------------------------- /AWS/AWS云创建EC2与使用注意事项-踩坑记录.md: -------------------------------------------------------------------------------- 1 | ## AWS 2 | 3 | [TOC] 4 | 5 | 6 | 7 | #### AWS云服务器价格计算器 8 | 9 | AWS WEB 价格计算器网址 10 | 11 | ### 一 创建 EC2(云服务器) 12 | 13 | #### 创建步骤一: 进入 控制台,选择系统镜像 14 | 15 | ![GIFade](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/AWS/EC2_create.gif) 16 | 17 | #### 创建步骤二:设置示例类型,配置实例,选择存储,配置安全组,创建实例 18 | 19 | ![GIF-234](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/AWS/EC2-set.gif) 20 | 21 | #### 创建步骤三 :分配弹性IP,并绑定到主机上。 22 | 23 | ![image](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/AWS/aws-bind-elastic-ip.gif) 24 | 25 | #### 注意事项 26 | 27 | > 1. 数据卷选择需要根据需求选择,选择错了会导致费用比较高,具体比较见下文 28 | > 2. 一定要绑定弹性 IP,如果我们没有绑定弹性 IP,默认在实例重启后,公网 IP 是会变化的,如果我们依赖于公网 IP 提供服务的话,这是会很糟糕的,所以我们需要绑定 弹性IP,默认内网IP是不会发生改变的。 29 | > 3. 默认的登录用户 是 `centos` ,是通过秘钥登录的(我们创建的时候指定了秘钥)。 30 | 31 | #### EC2 数据卷选择 32 | 33 | EBS 各个卷的配置与性能 34 | 35 | | | 固态硬盘 (SSD) | 硬盘驱动器 (HDD) | | | 36 | | :-------------------- | :----------------------------------------------------------: | :----------------------------------------------------------: | ------------------------------------------------------------ | ------------------------------------------------------------ | 37 | | **卷类型** | 通用型 SSD (`gp2`)* | 预配置 IOPS SSD (`io1`) | 吞吐优化 HDD (`st1`) | Cold HDD (`sc1`) | 38 | | **描述** | 平衡价格和性能的通用 SSD 卷,可用于多种工作负载 | 最高性能 SSD 卷,可用于任务关键型低延迟或高吞吐量工作负载 | 为频繁访问的吞吐量密集型工作负载设计的低成本 HDD 卷 | 为不常访问的工作负载设计的最低成本 HDD 卷 | 39 | | **使用案例** | 建议用于大多数工作负载系统启动卷虚拟桌面低延迟交互式应用程序开发和测试环境 | 需要持续 IOPS 性能或每卷高于 16,000 IOPS 或 250 MiB/s 吞吐量的关键业务应用程序大型数据库工作负载,如:MongoDBCassandraMicrosoft SQL ServerMySQLPostgreSQLOracle | 以低成本流式处理需要一致、快速的吞吐量的工作负载大数据数据仓库日志处理不能是启动卷 | 适合大量不常访问的数据、面向吞吐量的存储最低存储成本至关重要的情形不能是启动卷 | 40 | | **API 名称** | `gp2` | `io1` | `st1` | `sc1` | 41 | | **卷大小** | 1 GiB - 16 TiB | 4 GiB - 16 TiB | 500 GiB - 16 TiB | 500 GiB - 16 TiB | 42 | | **最大IOPS\**/卷** | 16,000*** | 64,000**** | 500 | 250 | 43 | | **最大吞吐量/卷** | 250 MiB/s*** | 1,000 MiB/s† | 500 MiB/s | 250 MiB/s | 44 | | **最大IOPS/实例**†† | 80,000 | 80,000 | 80,000 | 80,000 | 45 | | **最大吞吐量/实例**†† | 1,750 MiB/s | 1,750 MiB/s | 1,750 MiB/s | 1,750 MiB/s | 46 | | **管理性能属性** | IOPS | IOPS | MiB/s | MiB/s | 47 | 48 | **新加坡可用区**价格表(时间:2019-05-30) 49 | 50 | | 数据卷类型 | 容量 | IOPS | 最大吞吐量 | | 51 | | -------------------- | ----------- | ---- | ---------------- | ----------- | 52 | | gp2 | 50GB | 150 | 128 MBs/sec | $6/month | 53 | | IOPS SSD (`io1`) | 50GB | 150 | 37.5 MBs/sec | $17.7/month | 54 | | 吞吐优化 HDD (`st1`) | 500GB(最小) | — | 19.53125 MBs/sec | $27/month | 55 | 56 | 根据上面的对比,建议选择`gp2` (性价比高)。`AWS` 云服务器的硬盘的 `IOPS` 是跟硬盘有关的。但是 EBS 卷支持生产期间的实时配置更改。您可以在不中断服务的情况下修改卷类型、卷大小和 IOPS 容量。EC2 默认创建的卷的类型是 `gp2`。 57 | 58 | #### EC2 创建快照计划任务 59 | 60 | 在实际生产环境中,定时创建一个快照也是一个对数据备份的好办法,所以接下来我们来讲讲创建快照计划任务。 61 | 62 | 方法一: 生命周期管理器 官方文档: 63 | 64 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/AWS/EC2-create-snapshot.gif) 65 | 66 | 67 | 68 | 方法二: 通过`cloudwatch` 创建 规则(rules) 69 | 70 | 通过这种方式创建的快照,是不会自动删除的,就是会将创建的快照一直保存。 71 | 72 | ![1559206665634](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/AWS/1559206665634.png) 73 | 74 | #### 设置 root 用户密码 75 | 76 | AWS EC2 默认创建的用户是 `centos`,是使用秘钥进行登录的,我们考虑到我们需要`root`用户,虽然我们不常用到,但是为了以备后期使用,是服务器的安全,我们这里会配置 `root` 用户密码,但不允许 root 用户远程登录。 77 | 78 | 具体操作 79 | 80 | ```bash 81 | [centos@ip-172-31-21-255 ~]$ sudo passwd root 82 | Changing password for user root. 83 | New password: 84 | BAD PASSWORD: The password is shorter than 8 characters 85 | Retype new password: 86 | passwd: all authentication tokens updated successfully. 87 | [centos@ip-172-31-21-255 ~]$ su root 88 | Password: 89 | [root@ip-172-31-21-255 centos]# id 90 | uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 91 | [root@ip-172-31-21-255 centos]# 92 | ``` 93 | 94 | 如果我们需要通过 root 来进行远程登陆的话,可以选择远程登陆使用 密码登陆 95 | 96 | ```bash 97 | # 将 sshd配置文件/etc/ssh/sshd_config 参数 PasswordAuthentication no 更改为 yes 98 | sed -i '/^PasswordAuthentication/s/no/yes/' /etc/ssh/sshd_config 99 | systemctl restart sshd 100 | # 更改之后,我们只能通过密码进行登陆了,而不能通过密钥登陆了。这时我们需要给 centos 设置密码,然后通过密码登陆 101 | ``` 102 | 103 | 如果我们想要通过 root 通过密钥进行远程登陆的话,我们需要先在 xshell 生成密钥,并将公钥存放在 root 用户的 `/root/.ssh/authorized_keys` 里,然后进行登陆。 104 | 105 | 生成密钥,并获取公钥(要记住设置的密码,后面要使用) 106 | 107 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/AWS/ssh-pub-login.gif) 108 | 109 | 110 | 111 | 112 | 113 | ### 二、AWS 注意事项 114 | 115 | #### 弹性IP限制 116 | 117 | 注意在每个地域,每个账户的默认可以申请的弹性IP是 5个。如果我们的计划需要使用的弹性IP超过了5个,我们需要提前进行申请,将限制提高。 118 | 119 | #### 付费类型 120 | 121 | 一种是RI,另外一种是OnDemand 122 | 123 | RI预付费 124 | 125 | OnDemand后付费 126 | 127 | #### EC2实例有两种根设备类型 128 | 129 | 1、实例存储(本地),系统和磁盘再同一主机上 130 | 131 | ​ Instances storage,当删除了实例,数据卷也释放了 132 | 133 | 2、EBS存储(网盘),EBS可能与云主机不在一台物理机上,可能在其他物理机上。 134 | 135 | ​ Elastic Block Storage,当删除了实例,EBS 卷可以单独保存。 136 | 137 | #### EC2 实例数量限制 138 | 139 | EC2实例在申请超过20台后,会有数量限制。 140 | 141 | #### AWS 使用RDS注意时区参数 142 | 143 | 使用 AWS 的 RDS ,记住需要创建一个参数组,默认的参数组是不可以修改的,我们新建的参数组是可以修改的。 144 | 145 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/AWS/aws-rds-time-zone.png) 146 | 147 | #### AWS ELB 148 | 149 | ELB 是不可以设置黑名单的,也是不可以开启 gzip 的。 150 | 151 | ### 三、AWS 申请 SSL 证书 152 | 153 | 我们的域名是在阿里云上面购买的,我们可以在 阿里云上面进行证书申请,当我们在阿里云上面申请后,我们需要,从阿里云导出来后再导入 AWS,这样会比较麻烦,而且后期续订证书也比较麻烦。所以我们就计划直接在 AWS 上面申请 SSL 证书,AWS 是支持的, 154 | 155 | 在证书管理界面点击 ---》请求证书,然后选择请求公有证书,然后填入我们的要获取证书的域名。要想在 AWS 获取证书,可以通过两种方式验证域名的所有者, 156 | 157 | - 第一是通过 `DNS` 解析设置指定记录值 158 | 159 | `AWS` 会给我们一个 名称和记录值,我们需要在 解析里面添加 `CNAME` 记录,名称值填入到 主机记录,记录值填入到解析的记录值。 160 | 161 | - 第二是通过 邮件验证。 162 | 163 | 邮件验证的话,是会发送到该域名的以下邮件里进行确认 164 | 165 | - administrator@*your_domain_name* 166 | - hostmaster@*your_domain_name* 167 | - postmaster@*your_domain_name* 168 | - webmaster@*your_domain_name* 169 | - admin@*your_domain_name* 170 | 171 | 自动续订策略 172 | 173 | - 只要证书在使用中且 `CNAME` 记录保持不变,**ACM 便会自动续订证书**。 174 | - 电子邮件验证的证书仅可在其原始验证日期的 825 天后续订。825 天之后,域拥有者或授权代表必须请求新的证书,而 DNS 验证的证书将无限期续订。 175 | 176 | > 如果 ACM 无法在生成 CNAME 值后的 72 小时内验证域名,ACM 会将证书状态更改为**验证超时**。导致此结果的最可能原因是您未使用 ACM 生成的值更新 DNS 配置。要解决此问题,您必须请求新的证书。 177 | 178 | 有关AWS 的一些其他文章可查看 [博客园-宋某人](https://www.cnblogs.com/syaving/) 179 | 180 | -------------------------------------------------------------------------------- /运维常用应用的日志分割.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | 3 | ## 一 、Nginx-Tomcat 等常用服务日志分析 4 | 5 | 在实际生产中,我们知道哪些应用的日志会自动分割吗?哪些应用日志需要我们通过服务进行定时分割?接下来我们来看看。 6 | 7 | #### 对比的标准 8 | 9 | - 是否会自动切割 ? 10 | - 重启是否会自动分割 ? 11 | 12 | ### Nginx 日志 13 | 14 | 15 | 16 | | 日志名称 | 日志描述 | 是否自动切割 | 是否需要定时切割 | 17 | | ---------- | -------------- | ------------ | ---------------- | 18 | | access.log | Nginx 访问日志 | 否 | 是 | 19 | | error.log | Nginx 错误日志 | 否 | 是 | 20 | 21 | 如果需要单独配置网站日志的话需要在 server 模块添加`access_log logs/djx.log ;` 22 | 23 | 24 | 25 | 26 | 27 | ### Tomcat日志 28 | 29 | | 日志名称 | 日志描述 | 是否自动切割 | 是否需要定时切割 | 30 | | ----------------------------------- | ------------------------------------------------------------ | ------------ | ---------------- | 31 | | catalina.out | Tomcat 运行时日志和输出到控制台日志(应用) | 否 | 是 | 32 | | catalina.2019-04-28.log | Tomcat本身运行的日志,主要是启动和暂停的。 | 是 | 否 | 33 | | localhost_access_log.2019-04-28.txt | 访问 Tomcat 的日志,请求时间和资源,状态码都有记录 | 是 | 否 | 34 | | localhost.2019-04-28.log | 应用初始化(listener, filter, servlet)未处理的异常最后被 Tomcat 捕获而输出的日志 | 是 | 否 | 35 | | host-manager.2019-04-28.log | 放 Tomcat 的自带的 **Host Manager**项目的日志信息的 | 是 | 否 | 36 | | manager.2019-04-28.log | Tomcat 自带 **Manager**项目专有的日志文件 | 是 | 否 | 37 | 38 | Tomcat 的日志比较特别和有意思,我也是认真看了看才发现其中的奥秘。 39 | 40 | #### 画重点了 41 | 42 | Tomcat 的 `catalina.out` 日志是 不会自动切割的,所以我们需要对它进行定时切割,重启 Tomcat 也是不会自动切割的。 43 | 44 | 其它的日志 Tomcat 是会进行自动切割的,但是会遵循这样的一个规则:日志隔天切割,有日志才切割,重启会切割: 45 | 46 | - 日志隔天切割 :含义是 日志在24.00分才会进行切割,如果 00:00:10 产生了当天的第一条日志,那么就进行切割。 47 | - 有日志才切割 :含义是 如果满足了隔天的要求,但是第二天一直没有产生日志,那么就会直到第二天第一条日志产生时才进行切割。 48 | - 重启切割 : 含义是 如果上面的条件都不满足,就是到了第二天,但是一条日志一直都没有产生,那么在重启Tomcat 时是会进行切割的。 49 | 50 | 上面内容有点绕,我们举几个示例理解下。 51 | 52 | **示例1:** 53 | 54 | ``` 55 | Tomcat 在 2019 年 4 月28号15.30分启动的,有日志文件 catalina.2019-04-28.log 等。2019 年 4月29号的第一条日志在 2019 年 4月29号9.30分。那么日志切割在什么时候? 56 | 57 | ​ 日志切割是在 2019 年 4月29号9.30分。 58 | ``` 59 | 60 | **示例2:** 61 | 62 | ``` 63 | Tomcat 在 2019 年 4 月28号10.30分启动的,有日志文件 catalina.2019-04-28.log 等。在 2019 年 4月29号3.30分重启了 Tomcat ,但是在重启前,Tomcat 在2019 年 4月29号3.30分当天是没有产生日志的,但在 2019 年 4月29号 3.50 产生了日志。问在什么时候切割了日志? 64 | 65 | ​ Tomcat 重启时就进行了切割。 66 | ``` 67 | 68 | 69 | 70 | ### MongoDB 日志 71 | 72 | MongoDB 的日志我们平时是关注的比较少,但是我们这边还是做下记录。 73 | 74 | MongoDB 的日志是否切割取决于 MongoDB 的配置参数。 75 | 76 | ```bash 77 | logRotate= rename/reopen 78 | #3.0.0版中的新功能。可以取值为 rename 或 reopen: 79 | rename 重命名日志文件。每次重启都会重命名日志文件。 80 | reopen 按照典型的 Linux/Unix 日志循环行为关闭并重新打开日志文件。使用 reopen 使用的 Linux/Unix logrotate的工具时,以避免日志的丢失。 81 | 如果指定 reopen,则还必须使用 logappend 82 | logappend= true # 当 MongoDB 实例重新启动时,将新的日志内容添加到现有日志文件的末尾。如果没有此选项,MongoDB 将备份现有日志并创建新文件。 83 | ``` 84 | 85 | 但是,MongoDB 的日志默认是不会进行切割的(如果不重启的话)。 86 | 87 | `MongoDB` 日志切割 见文章 :[MongoDB 日志切割三种方式](https://www.cnblogs.com/operationhome/p/10677099.html) 88 | 89 | ### Redis 日志 90 | 91 | Redis 日志默认也是不切割的, 重启也不切割。 Redis 日志在实际环境中我们也是建议进行切割的,切割频率可以降低。我看到有的 Redis 日志达到 1G,运行了2年,那么我们进行查找日志就比较不方便的,所以建议 Redis 的日志也进行切割。 92 | 93 | ## 二 、日志切割服务 logrotate 94 | 95 | 我们通常会去寻找对应的日志切割服务,但是我们不知道系统默认已经默认带了一个日志的切割服务 `logrotate`。像我们系统的日志 `/var/log/cron` 、`/var/log/maillog`、`/var/log/messages`等等这些都是通过 `logrotate` 来进行切割的,我们可以在文件 ` /etc/logrotate.d/syslog` 看到具体的配置。`logrotate` 可以每天或者每个月按周期对日志进行自动切割和压缩,以及通过邮件发送。`logrotate` 的自动切割是 通过 `crond` 来运行任务的。 96 | 97 | [logrotate 官方链接](https://linux.die.net/man/8/logrotate) 98 | 99 | #### logrotate 命令以及选项 100 | 101 | ```bash 102 | logrotate [OPTION...] 103 | -d, --debug # 仅仅是测试,并不做任何东西。在测试配置文件是否正确的时候可以使用。 104 | -f, --force # 指定配置文件 105 | -m, --mail=command # 指定发送邮件的命令,替代 /bin/mail 106 | -s, --state=statefile # 指定状态文件的路径 ,默认路径是 /var/lib/logrotate.status 。 107 | -v, --verbose # 显示 logrotate 分割信息 108 | -l, --log=STRING # 指定日志文件的路径 109 | --version # 显示版本信息 110 | ``` 111 | 112 | #### logrotate 配置文件路径 113 | 114 | `logrotate` 配置文件的位置 位于`/etc/logrotate.conf` 115 | 116 | `logrotate` 用户配置文件位于 `/etc/logrotate.d/` 117 | 118 | `logrotate` 的执行状态文件`/var/lib/logrotate.status` 119 | 120 | #### logrotate 配置文件的参数: 121 | 122 | ```bash 123 | su djx djx # 指定切割用户和用户组,默认为root。一定要加 用户组 ,否则会报错。 124 | compress # 是否通过gzip压缩转储以后的日志文件,如xxx.log-20131216.gz ;如果不需要压缩,注释掉就行 125 | compresscmd # 指定压缩的命令,默认 gzip 126 | uncompresscmd # 用于解压缩的日志文件的命令 默认是 gunzip 127 | compressext # 启用压缩的扩展名,默认 gzip 的扩展名就是 .gz。 128 | copy # 制作日志文件的副本,与create选项互斥。 129 | copytruncate # 用于还在打开中的日志文件,把当前日志备份并截断;是先拷贝再清空的方式,拷贝和清空之间有一个时间差,可能会丢失部分日志数据。与create选项互斥。 130 | create mode owner group # 在切割后,创建新的日志文件,并指定数据的权限和所有者和所属组。 131 | dateext # 这个参数很重要!就是切割后的日志文件以当前日期YYYYMMDD为格式结尾,如xxx.log-20131216这样,如果注释掉,切割出来是按数字递增,即前面说的 xxx.log-1这种格式 132 | dateformat format_string # 指定日志文件后缀日期格式 133 | ifempty # 表示即使是空文件也要选择,该选项是默认值。与 notifempty 相反 134 | notifempty # 当日志文件为空时,不进行轮转,与 ifempty 相反 135 | mailfirst # 当配置了邮件地址,指定发送最新的文件 136 | maillast # 当配置了邮件地址,指定发送最旧的文件,(默认设置) 137 | rotate count # 日志保留的次数, 如果该参数不写的话,默认就是删除之前所有的文件日志。比如切割了200次,那么只保留最新的180次日志,并删除旧的20次日志。如果配置文件指定的是 daily,那每天切割一次日志,就意味着保留180天日志。 138 | maxage count # 删除早于 count 天的日志,如果配置了 mail 则通过邮件发送。 139 | daily # 每天 切割 140 | weekly # 每周运行一次,通常在每周的第一天。 141 | monthly # 每月运行一次切割,通常会在该月的第一天。 142 | yearly # 如果当前年份与上一次年份不相同,就会进行切割 143 | nocompress # 不进行压缩。 144 | size size # 日志文件达到多大就切割 145 | olddir dir # 切割后存放的目录 146 | start count # 当没有指定日期后缀,将数字作为后缀内容,默认是从 1 开始 。可以指定其他数字开始。 147 | missingok # 如果日志丢失,不报错继续滚动下一个日志 148 | mail 112@163.com # 该参数与 rotate 是有关联的,当超过 rotate 指定次数,文件不是删除,而是通过邮件发送到指定位置。 149 | prerotate # 在logrotate转储之前需要执行的指令 150 | postrotate # 在logrotate转储之后需要执行的指令 151 | 152 | ### 3.85 版本增加每个小时切割 153 | hourly # 每个小时切割 154 | ``` 155 | 156 | 157 | 158 | #### 示例配置 159 | 160 | ```bash 161 | # 文件路径,可以使用通配符。 162 | /opt/tomcat/logs/catalina.out{ 163 | compress 164 | compressext .gz 165 | copytruncate 166 | dateext 167 | notifempty 168 | maillast 169 | rotate 180 170 | daily 171 | size 10M 172 | olddir /opt/logs/tomcat 173 | missingok 174 | mail 888888@qq.com # 如果我们本地没有配置好发送邮件配置的话是发送不了邮件的。 175 | } 176 | ``` 177 | 178 | #### 常用命令 179 | 180 | ```bash 181 | logrotate -d -f /etc/logrotate.d/tomcat # 测试配置文件是否配置正常 182 | logrotate -f /etc/logrotate.d/tomcat # 立刻切割文件,可以将该命令放到定时任务中实现定时切割 183 | ``` 184 | 185 | 186 | 187 | #### 注意事项: 188 | 189 | > - 当我们设置好日志按日进行切割的时候,具体的执行时间是在什么时候呢?我们不要以为是会在 24.00 的时候进行切割的,它进行切割的时间是随机的。这个随机值取决于 `crond` 服务的,最终会取决于文件 `/etc/anacrontab` , 190 | > 191 | > ```bash 192 | > [root@localhost ~]# cat /etc/anacrontab 193 | > # /etc/anacrontab: configuration file for anacron 194 | > 195 | > # See anacron(8) and anacrontab(5) for details. 196 | > 197 | > SHELL=/bin/sh 198 | > PATH=/sbin:/bin:/usr/sbin:/usr/bin 199 | > MAILTO=root 200 | > # the maximal random delay added to the base delay of the jobs # 延迟时间 201 | > RANDOM_DELAY=45 202 | > # the jobs will be started during the following hours only 执行时间段 203 | > START_HOURS_RANGE=3-22 204 | > 205 | > #period in days delay in minutes job-identifier command 206 | > 1 5 cron.daily nice run-parts /etc/cron.daily 207 | > 7 25 cron.weekly nice run-parts /etc/cron.weekly 208 | > @monthly 45 cron.monthly nice run-parts /etc/cron.monthly 209 | > 210 | > ``` 211 | > 212 | > 我们可以发现 定时任务是会在 3-22点的5分-45分里面进行日志切割。 213 | > 214 | > - **生产环境中该如何定时日志分割** 215 | > 216 | > 我们在实际的生产环境中,我们通常会进行按日进行日志分割,也就是我们希望在 24.00 进行前一天的日志分割,我们可以通过 `crond` 服务进行定时切割 (logrotate -f /etc/logrotate.d/tomcat ), 但是我们通常在很多应用中会有定时任务在 24.00进行执行,那个时间段也就会产生大量的日志,如果我们在此时切割,那么我们可能会导致比较多的重要的日志丢失(并且此时任务多,资源消耗多,切割也慢),那么我们建议先咨询开发,24.00 是否有大量定时任务,我们可以在 **24.00之前几分钟或者之后几分钟** 进行切割。这样就避免大量的日志丢失。 217 | 218 | 219 | 220 | ## 三、日志切割示例 221 | 222 | ### Nginx 切一切 223 | 224 | 示例:`Nginx` 日志保存在 `/opt/nginx/logs/`,包含日志 `access.log` 和 `error.log`。 225 | 226 | ```bash 227 | /opt/nginx/logs/* { 228 | compress 229 | compressext .gz 230 | copytruncate 231 | dateext 232 | notifempty 233 | maillast 234 | rotate 180 235 | daily 236 | size 10M 237 | olddir /opt/logs/nginx 238 | missingok 239 | mail 888888@qq.com # 如果我们本地没有配置好发送邮件配置的话是发送不了邮件的。 240 | } 241 | ``` 242 | 243 | 244 | 245 | ### Tomcat 切一切 246 | 247 | 示例:`Tomcat` 日志保存在 `/opt/tomcat/logs/`,包含日志 `catalina.out`,其他日志会自动切割。 248 | 249 | ``` 250 | /opt/tomcat/logs/catalina.out{ 251 | compress 252 | compressext .gz 253 | copytruncate 254 | dateext 255 | notifempty 256 | maillast 257 | rotate 180 258 | daily 259 | size 10M 260 | olddir /opt/logs/tomcat 261 | missingok 262 | mail 888888@qq.com # 如果我们本地没有配置好发送邮件配置的话是发送不了邮件的。 263 | } 264 | ``` 265 | 266 | 267 | 268 | -------------------------------------------------------------------------------- /jvm优化/java应用cpu过高,内存占用较多分析.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | 3 | # java 应用 4 | 5 | ## 1 cpu 负载过高 6 | 7 | ### 1.1 分析问题 8 | 9 | 1. 首先我们通过top 命令进行分析,找出消耗最多cpu的java 进程id 。 10 | 11 | 2. 找出对应的进程id 后,我们可以通过 top -Hp 进程id 命令来找出该进程中占用cpu最多的前几个线程id。 12 | 13 | 3. 我们使用 jstack -l 进程pid > /tmp/java_pid.log 输出java的堆栈日志到文件 /tmp/java_pid.log。 14 | 15 | 4. 我们将刚刚查询到的java进程中占用cpu最多的前几个线程id。进行转化为16进制。 16 | 17 | ```bash 18 | printf "%X" 线程id 19 | ``` 20 | 21 | 5. 我们在java堆栈日志文件中找到上面转化为16进制的线程的pid对应的 日志。 22 | 23 | 24 | 25 | 实际操作步骤流程图: ![image](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/java%20%E5%BA%94%E7%94%A8%E8%B0%83%E4%BC%98/java_cpu.gif) 26 | 27 | 28 | 29 | 补充:有时可能是我们代码创建线程过多导致的问题: 30 | 31 | ```bash 32 | # 查看该进程有多少线程 33 | ps p 9534 -L -o pcpu,pmem,pid,tid,time,tname,cmd|wc -l 34 | ``` 35 | 36 | ### 1.2 解决方案 37 | 38 | 我们把对应的线程id的日志拿给我们的开发,进行定位错误,这里容易定位出的错误是: 39 | 40 | 1. 线程处于WAITING(等待状态) 41 | 2. 线程BLOCKED(阻塞) 42 | 43 | ![img](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/java%20%E5%BA%94%E7%94%A8%E8%B0%83%E4%BC%98/clipboard.png) 44 | 45 | 我可以把定位到代码位置,告诉开发,让开发查看对应的代码是否有问题。 46 | 47 | 48 | 49 | 50 | 51 | ## 2 内存占用过多 52 | 53 | ​ Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。 54 | ![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-3/JVM运行时数据区域.png) 55 | 56 | 这些组成部分一些是线程私有的,其他的则是线程共享的。 57 | 58 | **线程私有的:** 59 | 60 | - 程序计数器 61 | - 虚拟机栈 62 | - 本地方法栈 63 | 64 | **线程共享的:** 65 | 66 | - 堆 67 | - 方法区 68 | - 直接内存 69 | 70 | ### 2.1 从内存回收方面 71 | 72 | ​ Java 堆是垃圾收集器管理的主要区域,因此也被称作**GC堆(Garbage Collected Heap)**.从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以Java堆还可以细分为:新生代和老年代:再细致一点有:Eden空间、From Survivor、To Survivor空间等。**进一步划分的目的是更好地回收内存,或者更快地分配内存。** 73 | 74 | ![img](https://user-gold-cdn.xitu.io/2018/8/25/16570344a29c3433?w=599&h=250&f=png&s=8946&ynotemdtimestamp=1552300476230) 75 | 76 | **在 JDK 1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域(永久代使用的是JVM的堆内存空间,而元空间使用的是物理内存,直接受到本机的物理内存限制)。**关于metaspace的详细讲解看:[JVM源码分析之Metaspace解密](https://mp.weixin.qq.com/s/SsXbRvtvawKDHstFpU4uog) 77 | 78 | ​ java 实际的内存使用是这样的,大多数情况下,对象在新生代中 eden 区分配。当 eden 区没有足够空间进行分配时,虚拟机将发起一次Minor GC(新生代GC).将eden 区的一些存活对象移动到Survivor 区,当Survivor区的大小,不够储存eden 区的存活对象时,那么就会将它移动到老年区(Old Generation ),当老年区满了时候将触发一次 Full GC . 79 | 80 | ​ 在实际工作中,我们可以使用 jmap -heap pid 来查看当前的进程的 java 堆的分布情况。 81 | 82 | ```bash 83 | [root@iz23nb5ujp69 ~]# jmap -heap 11764 84 | Attaching to process ID 11764, please wait... 85 | Debugger attached successfully. 86 | Server compiler detected. 87 | JVM version is 25.73-b02 88 | 89 | using thread-local object allocation. 90 | Parallel GC with 2 thread(s) 91 | 92 | Heap Configuration: 93 | MinHeapFreeRatio = 0 #GC后,如果发现空闲堆内存占到整个预估堆内存的40%,则放大堆内存的预估最大值,但不超过固定最大值。默认该值是40 94 | MaxHeapFreeRatio = 100 #GC后,如果发现空闲堆内存占到整个预估堆内存的100%,则收缩堆内存预估最大值。默认的是70 95 | MaxHeapSize = 2147483648 (2048.0MB) # 最大的堆内存 96 | NewSize = 715653120 (682.5MB) # 新生代初始大小 97 | MaxNewSize = 715653120 (682.5MB) # 新生代最大大小 98 | OldSize = 1431830528 (1365.5MB) #老年代 99 | NewRatio = 2 # 新生代和老年代的 内存比例: 1:2 默认值 100 | SurvivorRatio = 8 # Eden区与Survivor区的大小比值,设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10,Eden区和Survivor区 的实际比例值是会变动的 101 | MetaspaceSize = 21807104 (20.796875MB) # 元空间大小 102 | CompressedClassSpaceSize = 1073741824 (1024.0MB) # 压缩时可用的最大的内存 103 | MaxMetaspaceSize = 17592186044415 MB #元空间可用最大大小 104 | G1HeapRegionSize = 0 (0.0MB) #G1 收集器的内存大小 105 | 106 | Heap Usage: 107 | PS Young Generation # 新生代 108 | Eden Space: # Eden 109 | capacity = 372768768 (355.5MB) 110 | used = 185979712 (177.36407470703125MB) 111 | free = 186789056 (178.13592529296875MB) 112 | 49.89144154909459% used # eden 可用区使用率,该值满了将触发 young gc 113 | From Space: # Survivor1 114 | capacity = 175112192 (167.0MB) 115 | used = 47983120 (45.76026916503906MB) 116 | free = 127129072 (121.23973083496094MB) 117 | 27.401358781460516% used 118 | To Space: # Survivor2 119 | capacity = 167772160 (160.0MB) 120 | used = 0 (0.0MB) 121 | free = 167772160 (160.0MB) 122 | 0.0% used 123 | PS Old Generation # 老年代 124 | capacity = 1431830528 (1365.5MB) 125 | used = 257274632 (245.35620880126953MB) 126 | free = 1174555896 (1120.1437911987305MB) 127 | 17.9682320616089% used # 老年代 可用区使用率,该值满了将触发 full gc 128 | ``` 129 | 130 | 131 | 132 | 适当的young gc 可以让清理一些不存活的对象,但是短时间大量的 young GC 是会导致 Full GC 的,那么Full gc 是尽量不要产生的,当一个应用,产生大量的full GC是不正常的, 过多的GC和Full GC是会占用很多的系统资源(主要是CPU),影响系统的吞吐量。 133 | 134 | ​ young gc: 135 | 136 | ![1552463473610](C:\Users\djx\AppData\Roaming\Typora\typora-user-images\1552463473610.png) 137 | 138 | Metadata GC 139 | 140 | ![image](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/java%20%E5%BA%94%E7%94%A8%E8%B0%83%E4%BC%98/young_gc.png) 141 | 142 | ​ full gc : 143 | 144 | ![image](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/java%20%E5%BA%94%E7%94%A8%E8%B0%83%E4%BC%98/full_gc.png) 145 | 146 | **GC 日志解析** 147 | 148 | 对了,如何在日志中打印GC日志,我们在后面的配置中会讲到。 149 | 150 | ```bash 151 | [GC (Allocation Failure) [DefNew: 279616K->19156K(314560K), 0.0595827 secs] 279616K->19256K(1013632K), 0.0601044 secs] [Times: user=0.03 sys=0.02, real=0.06 secs] 152 | 153 | GC: 154 | 表明进行了一次垃圾回收,前面没有Full修饰,表明这是一次Minor GC。 155 | 156 | Allocation Failure: 157 | 表明本次引起GC的原因是因为在年轻代中没有足够的空间能够存储新的数据了。 158 | 159 | 279616K->19156K(314560K) 260460 160 | 三个参数分别为:GC前该内存区域(这里是年轻代)使用容量,GC后该内存区域使用容量,该内存区域总容量。 161 | 162 | 0.0595827 secs 163 | 表示GC耗时 164 | 165 | 279616K->19256K(1013632K) 166 | 堆区垃圾回收前的大小,堆区垃圾回收后的大小,堆区总大小。 167 | 168 | 0.0071945 secs 169 | Times: user=0.01 sys=0.00, real=0.01 secs 170 | 分别表示用户态耗时,内核态耗时和总耗时 171 | 172 | 173 | 新生代清理的内存:279616 - 19156 = 260460k 174 | 堆区减少的内存:279616 - 19256 = 260360k 175 | 新生代存到老年代的 数据为 260460k - 260360k 176 | 177 | 178 | 179 | 180 | 181 | Meta 日志:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/considerations.html 182 | 183 | used:加载的类的空间量。 184 | capacity: 当前分配块的元数据的空间。 185 | committed: 空间块的数量。 186 | reserved 指的是元空间的总大小 187 | ``` 188 | 189 | 那么如何查询一个应用发生young Gc 和Full GC 的次数和耗时时间。我们可以使用jstat 。 190 | 191 | 192 | 193 | **jstat 查询GC 次数和Full Gc 次数** 194 | 195 | ```bash 196 | jstat -gcutil pid 2000 10 (每隔2秒输出一次结果,输出10次) 197 | [root@iz23nb5ujp69 ~]# jstat -gcutil 3626 2000 10 198 | S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 199 | 56.01 0.00 8.21 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 200 | 56.01 0.00 8.30 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 201 | 56.01 0.00 8.41 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 202 | 56.01 0.00 8.56 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 203 | 56.01 0.00 9.00 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 204 | 56.01 0.00 9.27 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 205 | 56.01 0.00 9.34 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 206 | 56.01 0.00 9.46 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 207 | 56.01 0.00 9.57 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 208 | 56.01 0.00 9.70 88.19 98.44 96.92 27350 353.229 41 32.416 385.645 209 | S0 — Heap上的 Survivor space 0 区已使用空间的百分比 210 | S1 — Heap上的 Survivor space 1 区已使用空间的百分比 211 | E — Heap上的 Eden space 区已使用空间的百分比 212 | O — Heap上的 Old space 区已使用空间的百分比 213 | M - 表示的是Klass Metaspace以及NoKlass Metaspace两者总共的使用率 214 | CSS -表示的是NoKlass Metaspace的使用率 215 | YGC — 从应用程序启动到采样时发生 Young GC 的次数 216 | YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒) 217 | FGC — 从应用程序启动到采样时发生 Full GC 的次数 218 | FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒) 219 | GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒) 220 | FGC Scavenge GC要慢,因此应该尽可能减少Full GC。 221 | ``` 222 | 223 | 导致young Gc 和 full GC 的原因有哪些: 224 | 225 | 1. young 可用区 设置的太小 ,young gc 设置的太小就会导致 ,多次young gc,多次young gc 也就导致 oldGeneration 不断增大,最终导致full gc 226 | 2. Old Generation 设置的太小, 当 Old Generation 太小的话就会导致 经常占满,然后会进行full GC 。 227 | 3. **System.gc()被显示调用** , 垃圾回收不要手动触发,尽量依靠JVM自身的机制。 228 | 4. Meta(元数据)区可用内存设置的太少。 229 | 230 | 231 | 232 | **jvm 默认使用的配置** 233 | 234 | ​ 我们拿我们的tomcat 应用来说,我们如果使用默认的配置,我们使用jmap -heap 线程 查看 235 | 236 | ```bash 237 | [root@www apache-tomcat-8.5.38]# jmap -heap 7568 238 | Attaching to process ID 7568, please wait... 239 | Debugger attached successfully. 240 | Server compiler detected. 241 | JVM version is 25.131-b11 242 | 243 | using thread-local object allocation. 244 | Mark Sweep Compact GC 245 | 246 | Heap Configuration: 247 | MinHeapFreeRatio = 40 # 这个默认值在上面已经说到了,对于heap,我们尽量不要让它自动调整 248 | MaxHeapFreeRatio = 70 # 这个默认值在上面已经说到了,对于heap,我们尽量不要让它自动调整 249 | MaxHeapSize = 480247808 (458.0MB) 250 | NewSize = 10485760 (10.0MB) 251 | MaxNewSize = 160038912 (152.625MB) 252 | OldSize = 20971520 (20.0MB) # 默认的值分配不合理 253 | NewRatio = 2 254 | SurvivorRatio = 8 255 | MetaspaceSize = 21807104 (20.796875MB) 256 | CompressedClassSpaceSize = 1073741824 (1024.0MB) 257 | MaxMetaspaceSize = 17592186044415 MB 258 | G1HeapRegionSize = 0 (0.0MB) 259 | 260 | ``` 261 | 262 | 上面的配置很大一部分是不合理的,对于线上应用来说。 263 | 264 | 265 | 266 | **JVM配置参数(根据自己的项目情况调整)** 267 | 268 | ```bash 269 | -Xms2048m # 堆的最小内存,建议和最大内存设置的一致,以避免每次垃圾回收完成后JVM重新分配内存,提高GC运行的效率。 270 | -Xmx2048m # 堆的最大内存,建议和最小内存设置的一致,以避免每次垃圾回收完成后JVM重新分配内存,提高GC运行的效率。 271 | -XX:MaxHeapFreeRatio=100 #GC后,如果发现空闲堆内存占到整个预估堆内存的100%,则收缩堆内存预估最大值。默认的是70 272 | -XX:MinHeapFreeRatio=0 #GC后,如果发现空闲堆内存占到整个预估堆内存的0%,则放大堆内存的预估最大值,但不超过固定最大值。默认该值是40 273 | -Xmn900m #设置新生代的内存,如果我们设置了Xmx 和Xms为一致的话,那么该值的默认值为Xmx值的1/3。 274 | -XX:MetaspaceSize=64M # 初始化的Metaspace大小,也是最小大小 java 8 后,用Meta代替了永久代,默认该值为20M(因系统而异),如果日志中出现了Meta GC,那么可以提高该值。 275 | -XX:MaxMetaspaceSize= # 这个参数用于限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存,影响到其他程序。 276 | -XX:MinMetaspaceFreeRatio=40 #GC后,如果发现空闲Meta内存占到整个预估Meta内存的40%,则放大Meta内存的预估最大值,但不超过固定最大值。默认该值是40 277 | -XX:MaxMetaspaceFreeRatio=70 #GC后,如果发现空闲Meta内存占到整个预估Meta内存的70%,则收缩Meta内存预估最大值。默认的是70 278 | -XX:MaxNewSize= #设置新生代的最大值,一般默认为整个堆的1/3 279 | -XX:NewRatio=N #设置新生代和老年代的比值,默认为2 表示 新生代占用1/3 280 | -XX:SurvivorRatio=N #设置新生代中的 Eden 和两个Survivor 的比值,默认为8表示,eden占用 8/10,时间中jvm会自动调整Eden 和Survivor 的值的。 281 | -XX:MaxTenuringThreshold=N #新生代的对象的年龄(年龄计数器)达到N值后移动到老年代,默认值为15 282 | -XX:ParallelGCThreads=n #设置垃圾收集器在并行阶段使用的线程数,建议设置为与处理器数目相等 283 | 284 | -XX:+DisableExplicitGC #关闭System.gc() 看你的程序是否需要System.gc(),再来决定 285 | 286 | -XX:MaxDirectMemorySize # 来指定最大的堆外内存 287 | 选用GC 回收器,不同的回收器,对应的延迟和内存不一致 288 | 289 | 290 | ## 针对Meta 细化设置 291 | -XX:CompressedClassSpaceSize #这个参数主要是设置Klass Metaspace的大小,不过这个参数设置了也不一定起作用,前提是能开启压缩指针,假如-Xmx超过了32G,压缩指针是开启不来的。如果有Klass Metaspace,那这块内存是和Heap连着的。 292 | 293 | 294 | ## 垃圾收集器的选择 295 | Parallel Scavenge收集器关注点是吞吐量(高效率的利用CPU)。CMS等垃圾收集器的关注点更多的是用户线程的停顿时间(提高用户体验,减少回收的停顿时间),CMS GC算法主要是针对老生代,持久代。所谓吞吐量就是CPU中用于运行用户代码的时间与CPU总消耗时间的比值。还有G1 收集器是(java1.9的默认收集器)。jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代) 296 | 297 | 298 | 如果要使用CMS收集器的话, 299 | -XX:+UseConcMarkSweepGC # 开启CMS GC 垃圾收集器 300 | -XX:+UseCMSInitiatingOccupancyOnly #只有开启了这个参数,CMSInitiatingOccupancyFraction这个参数才会生效 301 | -XX:CMSInitiatingOccupancyFraction= #触发cms gc的老生代使用率,当老生代使用达到该阈值之后,就将触发GC,该参数必须配合UseCMSInitiatingOccupancyOnly使用才有效 302 | -XX:+CMSClassUnloadingEnabled/-XX:-CMSClassUnloadingEnabled # 在使用CMS时,是否开启类卸载 如果开启 在full gc是会顺带扫描metaSpace/PermGen 303 | -XX:+ParallelRefProcEnabled # 尽量开启并行处理在任何地方 304 | -XX:+CMSScavengeBeforeRemark #开启在cms gc remark之前做一次ygc,减少gc roots扫描的对象数,从而提高remark的效率 305 | ``` 306 | 307 | 其它参数 308 | 309 | ```bash 310 | -Xss256k # 每个线程的堆栈大小,Xss越大,每个线程的大小就越大,占用的内存越多,能容纳的线程就越少 311 | #Xss越小,则递归的深度越小,容易出现栈溢出 java.lang.StackOverflowError,减少局部变量的声明,可以节省栈帧大小,增加调用深度 312 | -XX:+PrintGCDetails # 日志中输入GC详情日志。 313 | -XX:+PrintHeapAtGC # 打印GC前后的详细堆栈信息 314 | -XX:+PrintGCTimeStamps # 打印GC发生的时间戳 315 | -XX:+PrintGCDateStamps # 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800) 316 | 317 | # 指定GC 日志和错误日志,OOM 318 | -XX:ErrorFile=/tmp/gc/hs_err_pid%p.log # 发生错误时错误日志保存的地方 319 | -Xloggc:/tmp/gc/gc.log # gc 日志记录的地方 320 | 321 | -XX:+HeapDumpOnOutOfMemoryError #启用当抛出OutOfMemoryError异常时,将堆转储到文件 322 | -XX:HeapDumpPath=/tmp/gc #当启用 HeapDumpOnOutOfMemoryError 时,储存dump文件的路径 323 | -XX:+PrintGCApplicationStoppedTime # 启用打印应用暂停的时间 324 | 325 | 还有一些参数见文章:https://blog.csdn.net/see__you__again/article/details/51998038 326 | ``` 327 | 328 | 329 | 330 | 希望达成的: young gc 频率适中,如果young gc 次数较少的话,一次young gc 的耗时就会比较长,那么最求的平衡就是: young gc 频率和 young gc 耗时 达到两者的平衡值。Full Gc 尽量不要有。 331 | 332 | 参考配置 333 | 334 | ```bahs 335 | -Xms2048m -Xmx2048m -XX:MaxHeapFreeRatio=100 -XX:MinHeapFreeRatio=0 -Xmn900m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:MinMetaspaceFreeRatio=0 -XX:SurvivorRatio=7 -XX:MaxMetaspaceFreeRatio=100 -XX:MaxTenuringThreshold=14 -XX:ParallelGCThreads=2 -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintGCDetails 336 | ``` 337 | 338 | 调优完之后的效果是 ,20-30分钟发生一次Minor GC(young gc ) 每次的GC 耗时,无Full GC 和Meta 导致的GC。 339 | 340 | 341 | 342 | 案例分析: 343 | 344 | GC 日志 345 | 346 | ``` 347 | [GC (Metadata GC Threshold) [PSYoungGen: 282234K->101389K(523264K)] 589068K->410894K(1921536K), 0.1611903 secs] [Times: user=0.18 sys=0.00, real=0.16 secs] 348 | 349 | [Full GC (Metadata GC Threshold) [PSYoungGen: 101389K->0K(523264K)] [ParOldGen: 309505K->258194K(1398272K)] 410894K->258194K(1921536K), [Metaspace: 268611K->268101K(1294336K)], 1.8562117 secs] [Times: user=1.80 sys=0.08, real=1.86 secs] 350 | ``` 351 | 352 | 我们可以在日志中看到触发了一次普通的GC 和一次 Full GC ,两次GC的原因都是Meta区GC导致的,我们看Full Gc 的日志, young 区的内存没有使用完,old区的内存也没有占用满,只有Meta 区的内存占用满了,那么导致这个问题的就是Meta 区设置的太小。 353 | 354 | #### 355 | 356 | **扩展: ** 357 | 358 | 查看 java 的一些默认配置 359 | 360 | ``` 361 | java -XX:+PrintFlagsInitial 362 | 示例: 查看Meta(元空间的默认大小) 363 | java -XX:+PrintFlagsInitial |grep MetaspaceSize 364 | 365 | ``` 366 | 367 | jvm 参数生成器(寒泉子) 368 | 369 | http://xxfox.perfma.com/jvm/generate 370 | 371 | #### 372 | 373 | ### 1、吞吐量 374 | 375 | > 应用系统的生命周期内,应用程序所花费的时间和系统总运行时间的比值。 376 | > 系统总运行时间=应用程序耗时+GC耗时。 377 | > 如果系统运行了100分钟,GC耗时1分钟,则系统吞吐量=99% 378 | 379 | ### 2、垃圾回收器负载 380 | 381 | > 垃圾回收器负载=GC耗时/系统总运行时间 382 | 383 | ### 3、停顿时间 384 | 385 | > 垃圾回收器运行时,应用程序的暂停时间,缩短由于垃圾收集引起的停顿时间或完全消除垃圾收集所引起的停顿,避免应用程序运行时发生抖动 386 | 387 | ### 4、垃圾回收频率 388 | 389 | > 垃圾回收器多长时间运行一次。一般而言,频率越低越好,通常增大堆空间可以有效降低垃圾回收发生的频率,但是会增加回收时产生的停顿时间。 390 | 391 | ### 5、反应时间 392 | 393 | > 当一个对象成为垃圾后,多长时间内,它所占用的内存空间会被释放掉。 394 | 395 | 396 | 397 | java 垃圾回收系列文章:https://segmentfault.com/a/1190000004638653 398 | 399 | -------------------------------------------------------------------------------- /Zabbix/Zabbix监控ActiveMQ.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 当我们在线上使用了`ActiveMQ` 后,我们需要对一些参数进行监控,比如 消息是否有阻塞,哪个消息队列阻塞了,总的消息数是多少等等。下面我们就通过 `Zabbix` 结合 `Python` 脚本来实现对 `ActiveMQ`的监控。 4 | 5 | 6 | 7 | ### 一、创建 Activemq Python 监控脚本 8 | 9 | 10 | 11 | 因为 `CentOS` 系统默认安装的是 `Python2.7`,为了避免麻烦,我们这里的脚本也是对应的 `Python2` 12 | 13 | Python2 监控脚本 14 | 15 | ```python 16 | # -*- coding: utf-8 -*- 17 | # @Time : 2019/6/25 9:26 18 | # @Author : djx 19 | # @Email : djxlsp@163.com 20 | # @File : mointer_mq_python2.py 21 | # @Software: PyCharm 22 | # @Python_version: python2.7 23 | 24 | import base64 25 | import urllib2 26 | import json 27 | import logging 28 | import sys 29 | 30 | 31 | def activemq_mointer(userinfo_encode): 32 | # 总的消息阻塞数 33 | pending_queue_sum = 0 34 | # 阻塞消息的队列名称 35 | pending_queue_lists = '' 36 | # 总的消息数 37 | mq_sum = 0 38 | headers = { 39 | 'Authorization': 'Basic {}'.format(userinfo_encode), 40 | 'ua': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36' 41 | } 42 | url = 'http://' + ip + ':' + port + \ 43 | '/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost/Queues/' 44 | request = urllib2.Request(url=url, headers=headers) 45 | try: 46 | response = urllib2.urlopen(request) 47 | except Exception as e: 48 | logging.error(e) 49 | return {'pending_queue_sum': 110, 'pending_queue_lists': '110', 'mq_sum': 0} # 当服务不可用时,返回预警数字,用于预警。 50 | activemq_info = response.read() 51 | activemq_info_json = json.loads(activemq_info) 52 | activemq_queues = activemq_info_json['value'] 53 | for i in activemq_queues: 54 | queue_url = 'http://' + ip + ':' + port + \ 55 | '/api/jolokia/read/' + i['objectName'] 56 | queue_request = urllib2.Request(url=queue_url, headers=headers) 57 | try: 58 | queue_response = urllib2.urlopen(queue_request) 59 | except Exception as e: 60 | logging.error(e) 61 | return {'pending_queue_sum': 110, 'pending_queue_lists': '110', 'mq_sum': 0} 62 | queue_info = queue_response.read() 63 | info_dict = json.loads(queue_info) 64 | mq_sum += info_dict['value']['EnqueueCount'] 65 | if int(info_dict['value']['QueueSize'] 66 | ) > 0: # 取值 QueueSize ,就是未消费的消息数量 67 | pending_queue_sum += info_dict['value']['QueueSize'] 68 | pending_queue_lists += info_dict['value']['Name'] 69 | pending_queue_lists += ' and ' 70 | logging.info( 71 | "消息队列--{}--有阻塞消息--{} 条".format( 72 | info_dict['value']['Name'], 73 | info_dict['value']['QueueSize'])) 74 | return {'pending_queue_sum': pending_queue_sum, 'pending_queue_lists': pending_queue_lists, 'mq_sum': mq_sum} 75 | 76 | 77 | if __name__ == '__main__': 78 | # ActiveMQ 服务器信息 79 | username = 'admin' 80 | password = 'admin' 81 | ip = '127.0.0.1' 82 | port = '8161' 83 | userinfo = username + ':' + password 84 | userinfo_encode = base64.b64encode(userinfo.encode('utf8')) 85 | # 日志配置,注意下面日志文件的路径是采用相对路径的。 86 | logging.basicConfig( 87 | filename="/var/log/activemq_mointer.log", 88 | filemode="a", 89 | format="%(asctime)s %(name)s:%(levelname)s:%(message)s", 90 | datefmt="%d-%M-%Y %H:%M:%S", 91 | level=logging.DEBUG) 92 | if len(sys.argv) == 2: 93 | mointer_argv = sys.argv[1] 94 | if mointer_argv in ('pending', 'pending_lists', 'queue_sum'): 95 | mq_re = activemq_mointer(userinfo_encode) 96 | if mointer_argv == 'pending': 97 | print(mq_re['pending_queue_sum']) 98 | elif mointer_argv == 'pending_lists': 99 | print(mq_re['pending_queue_lists']) 100 | else: 101 | print(mq_re['mq_sum']) 102 | else: 103 | # 错误提示 104 | print("Please enter the correct parameters pending|pending_lists|queue_sum") 105 | else: 106 | # 错误提示 107 | print("Please enter the correct parameters pending|pending_lists|queue_sum") 108 | 109 | ``` 110 | 111 | 使用该脚本注意事项: 112 | 113 | 1. 传入参数只能一个 ,而且只能是 `pending`, `pending_lists`, `queue_sum` ,分别代表阻塞消息数、阻塞消息队列名称、总的消息数。 114 | 115 | 2. 脚本有日志记录和异常记录,注意设置 日志文件路径,假设脚本路径位于 `/opt/scripts/`,我们在该目录下进行执行脚本的话,`activemq_mointer.log` 日志文件也就会产生在当前目录下。我们可以在路径中通过绝对路径来指定文件夹 形如 `/var/log/activemq_mointer.log` 116 | 117 | 3. 该脚本是由 `zabbix agent` 进行使用 ,所以我们需要设置该 脚本的权限,以及保证该脚本的用户有创建日志文件的权限(或者我们先前创建好对应权限日志文件) 118 | 119 | ```bash 120 | sudo chown zabbix:zabbix mointer_mq_python2.py 121 | sudo chmod 744 mointer_mq_python2.py 122 | sudo touch /var/log/activemq_mointer.log 123 | sudo chown zabbix:zabbix /var/log/activemq_mointer.log 124 | ``` 125 | 126 | `Python3` 脚本 127 | 128 | ```python 129 | # -*- coding: utf-8 -*- 130 | # @Time : 2019/6/25 9:20 131 | # @Author : djx 132 | # @Email : djxlsp@163.com 133 | # @File : mointer_mq.py.py 134 | # @Software: PyCharm 135 | # @Python_version: python3 136 | 137 | import base64 138 | import requests 139 | import logging 140 | import sys 141 | 142 | def activemq_mointer(userinfo_encode): 143 | # 总的消息阻塞数 144 | pending_queue_sum = 0 145 | # 阻塞消息的队列名称 146 | pending_queue_lists = '' 147 | # 总的消息数 148 | mq_sum = 0 149 | headers = { 150 | 'Authorization': 'Basic {}'.format(str(userinfo_encode,'utf-8')), 151 | 'ua': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36' 152 | } 153 | url = 'http://' + ip + ':' + port + '/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost/Queues/' 154 | try: 155 | response = requests.get(url=url, headers=headers) 156 | except Exception as e: 157 | logging.error(e) 158 | return {'pending_queue_sum': 110, 'pending_queue_lists': '110', 'mq_sum': 0} # 当服务不可用时,返回预警数字,用于预警。 159 | activemq_info = response.json() 160 | activemq_queues = activemq_info['value'] 161 | for i in activemq_queues: 162 | queue_url = 'http://' + ip + ':' + port + '/api/jolokia/read/' + i['objectName'] 163 | try: 164 | queue_info = requests.get(url=queue_url, headers=headers) 165 | except Exception as e: 166 | logging.error(e) 167 | return {'pending_queue_sum': 110, 'pending_queue_lists': '110', 'mq_sum': 0} 168 | info_dict = queue_info.json() 169 | mq_sum += info_dict['value']['EnqueueCount'] 170 | if int(info_dict['value']['QueueSize']) > 0: # 取值 QueueSize ,就是未消费的消息数量 171 | pending_queue_sum += info_dict['value']['QueueSize'] 172 | pending_queue_lists += info_dict['value']['Name'] 173 | pending_queue_lists += ' and ' 174 | logging.info( 175 | "Queues--{}--peding msg --{}".format( 176 | info_dict['value']['Name'], 177 | info_dict['value']['QueueSize'])) 178 | return {'pending_queue_sum': pending_queue_sum, 'pending_queue_lists': pending_queue_lists, 'mq_sum': mq_sum} 179 | 180 | if __name__ == '__main__': 181 | # ActiveMQ 服务器信息 182 | username = 'admin' 183 | password = 'admin' 184 | ip = '127.0.0.1' 185 | port = '8161' 186 | userinfo = username + ':' + password 187 | userinfo_encode = base64.b64encode(userinfo.encode('utf8')) 188 | # 日志配置 189 | logging.basicConfig( 190 | filename="/var/log/activemq_mointer.log", 191 | filemode="a", 192 | format="%(asctime)s %(name)s:%(levelname)s:%(message)s", 193 | datefmt="%Y-%m-%d %H:%M:%S", 194 | level=logging.INFO) 195 | if len(sys.argv) == 2: 196 | mointer_argv = sys.argv[1] 197 | if mointer_argv in ('pending', 'pending_lists', 'queue_sum'): 198 | mq_re = activemq_mointer(userinfo_encode) 199 | if mointer_argv == 'pending': 200 | print(mq_re['pending_queue_sum']) 201 | elif mointer_argv == 'pending_lists': 202 | print(mq_re['pending_queue_lists']) 203 | else: 204 | print(mq_re['mq_sum']) 205 | else: 206 | # 错误提示 207 | print("Please enter the correct parameters pending|pending_lists|queue_sum") 208 | else: 209 | # 错误提示 210 | print("Please enter the correct parameters pending|pending_lists|queue_sum") 211 | 212 | ``` 213 | 214 | 215 | 216 | ### 二 、设置 zabbix agent 217 | 218 | 设置 zabbix agent 219 | 220 | ```bash 221 | # 将监控项配置写入配置文件 222 | sudo echo "UserParameter=activemq.mointer[*],python /opt/scripts/mointer_mq_python2.py \$1 " >> /opt/zabbix-agent/etc/zabbix_agentd.conf 223 | # 重启zabbix agent 224 | sudo systemctl restart zabbix-agent 225 | ``` 226 | 227 | ### 三、导入监控项: 228 | 229 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_activemq_mointer.png) 230 | 231 | 监控模板 xml 文件。(该监控模板包含三个监控项,一个触发器) 232 | 233 | ```xml 234 | 235 | 236 | 4.0 237 | 2019-06-26T03:49:47Z 238 | 239 | 240 | AWS-1688 241 | 242 | 243 | Fy-hbg 244 | 245 | 246 | 247 | 449 | 450 | 451 | 452 | {Template App ActiveMQ:activemq.mointer[pending].avg(10m)}>=5 453 | 1 454 | {Template App ActiveMQ:activemq.mointer[pending].avg(5m)}=0 455 | activemq queue pending on {HOST.NAME} 456 | 0 457 | 458 | 459 | 0 460 | 3 461 | activemq 消息发生阻塞,10分钟内平均阻塞消息数超过5条 462 | 0 463 | 0 464 | 465 | 466 | 467 | 468 | 469 | 470 | ``` 471 | 472 | 将该监控模板链接到对应的主机。 473 | 474 | 我们可以看到我们监控的数据了。 475 | 476 | ![](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/Zabbix/zabbix_activemq_mointer_data.png) 477 | 478 | 至此,ActiveMQ 的监控项都已经配置好了。 -------------------------------------------------------------------------------- /Docker/docker日志.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [TOC] 4 | 5 | **本文所有内容基于:** 6 | 7 | ```txt 8 | Docker-CE 9 | Server Version: 18.09.6 10 | Storage Driver: overlay2 11 | Kernel Version: 3.10.0-862.el7.x86_64 12 | Operating System: CentOS Linux 7 (Core) 13 | ``` 14 | 15 | Docker 日志分为两类: 16 | 17 | - Docker 引擎日志(也就是 dockerd 运行时的日志), 18 | - 容器的日志,容器内的服务产生的日志。 19 | 20 | 21 | 22 | ## 一 、Docker 引擎日志 23 | 24 | Docker 引擎日志一般是交给了 Upstart(Ubuntu 14.04) 或者 systemd (CentOS 7, Ubuntu 16.04)。前者一般位于 /var/log/upstart/docker.log 下,后者我们一般 通过 `journalctl -u docker ` 来进行查看。 25 | 26 | 27 | 28 | | 系统 | 日志位置 | 29 | | ---------------------- | ------------------------------------------------------------ | 30 | | Ubuntu(14.04) | `/var/log/upstart/docker.log` | 31 | | Ubuntu(16.04) | `journalctl -u docker.service` | 32 | | CentOS 7/RHEL 7/Fedora | `journalctl -u docker.service` | 33 | | CoreOS | `journalctl -u docker.service` | 34 | | OpenSuSE | `journalctl -u docker.service` | 35 | | OSX | `~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/log/d‌ocker.log` | 36 | | Debian GNU/Linux 7 | `/var/log/daemon.log` | 37 | | Debian GNU/Linux 8 | `journalctl -u docker.service` | 38 | | Boot2Docker | `/var/log/docker.log` | 39 | 40 | 以上内容来自: 41 | 42 | ## 二、容器日志 43 | 44 | 45 | 46 | ### 2.1、常用查看日志命令——docker logs 47 | 48 | `docker logs CONTAINER` 显示当前运行的容器的日志信息, UNIX 和 Linux 的命令有三种 输入输出,分别是 STDIN(标准输入)、STDOUT(标准输出)、STDERR(标准错误输出),docker logs 显示的内容包含 STOUT 和 STDERR。在生产环境,如果我们的应用输出到我们的日志文件里,所以我们在使用 docker logs 一般收集不到太多重要的日志信息。 49 | 50 | > - nginx 官方镜像,使用了一种方式,让日志输出到 STDOUT,也就是 创建一个符号链接 `/var/log/nginx/access.log` 到 `/dev/stdout`。 51 | > - httpd 使用的是 让其输出到指定文件 ,正常日志输出到 `/proc/self/fd/1` (STDOUT) ,错误日志输出到 `/proc/self/fd/2` (STDERR)。 52 | > - 当日志量比较大的时候,我们使用 docker logs 来查看日志,会对 docker daemon 造成比较大的压力,容器导致容器创建慢等一系列问题。 53 | > - **只有使用了 `local 、json-file、journald` 的日志驱动的容器才可以使用 docker logs 捕获日志,使用其他日志驱动无法使用 `docker logs`** 54 | 55 | 56 | 57 | ### 2.2 、Docker 日志 驱动 58 | 59 | Docker 提供了两种模式用于将消息从容器到日志驱动。 60 | 61 | - (默认)拒绝,阻塞从容器到容器驱动 62 | - 非阻塞传递,日志将储存在容器的缓冲区。 63 | 64 | > 当缓冲区满,旧的日志将被丢弃。 65 | 66 | 在 mode 日志选项控制使用 `blocking(默认)` 或者 `non-blocking`, 当设置为 `non-blocking` 需要设置 `max-buffer-size` 参数(默认为 1MB)。 67 | 68 | 支持的驱动 69 | 70 | | | 描述 | 71 | | :----------------------------------------------------------- | :----------------------------------------------------------- | 72 | | `none` | 运行的容器没有日志,`docker logs`也不返回任何输出。 | 73 | | [`local`](https://docs.docker.com/config/containers/logging/local/) | 日志以自定义格式存储,旨在实现最小开销。 | 74 | | [`json-file`](https://docs.docker.com/config/containers/logging/json-file/) | 日志格式为JSON。Docker的默认日志记录驱动程序。 | 75 | | [`syslog`](https://docs.docker.com/config/containers/logging/syslog/) | 将日志消息写入`syslog`。该`syslog`守护程序必须在主机上运行。 | 76 | | [`journald`](https://docs.docker.com/config/containers/logging/journald/) | 将日志消息写入`journald`。该`journald`守护程序必须在主机上运行。 | 77 | | [`gelf`](https://docs.docker.com/config/containers/logging/gelf/) | 将日志消息写入Graylog扩展日志格式(GELF)端点,例如Graylog或Logstash。 | 78 | | [`fluentd`](https://docs.docker.com/config/containers/logging/fluentd/) | 将日志消息写入`fluentd`(转发输入)。该`fluentd`守护程序必须在主机上运行。 | 79 | | [`awslogs`](https://docs.docker.com/config/containers/logging/awslogs/) | 将日志消息写入Amazon CloudWatch Logs。 | 80 | | [`splunk`](https://docs.docker.com/config/containers/logging/splunk/) | 使用HTTP事件收集器将日志消息写入`splunk`。 | 81 | | [`etwlogs`](https://docs.docker.com/config/containers/logging/etwlogs/) | 将日志消息写为Windows事件跟踪(ETW)事件。仅适用于Windows平台。 | 82 | | [`gcplogs`](https://docs.docker.com/config/containers/logging/gcplogs/) | 将日志消息写入Google Cloud Platform(GCP)Logging。 | 83 | | [`logentries`](https://docs.docker.com/config/containers/logging/logentries/) | 将日志消息写入Rapid7 Logentries。 | 84 | 85 | 86 | 87 | 使用 Docker-CE 版本,`docker logs `命令 仅仅适用于以下驱动程序(前面 docker logs 详解也提及到了) 88 | 89 | - local 90 | - json-file 91 | - journald 92 | 93 | ![1558055133186](https://djxblog.oss-cn-shenzhen.aliyuncs.com/picture/docker/docker-log-driver.png) 94 | 95 | #### Docker 日志驱动常用命令 96 | 97 | 查看系统当前设置的日志驱动 98 | 99 | ```bash 100 | docker info |grep "Logging Driver" / docker info --format '{{.LoggingDriver}}' 101 | ``` 102 | 103 | 查看单个容器的设置的日志驱动 104 | 105 | ```bash 106 | docker inspect -f '{{.HostConfig.LogConfig.Type}}' 容器id 107 | ``` 108 | 109 | #### Docker 日志驱动全局配置更改 110 | 111 | 修改日志驱动,在配置文件 `/etc/docker/daemon.json`(注意该文件内容是 JSON 格式的)进行配置即可。 112 | 113 | 示例: 114 | 115 | ``` 116 | { 117 | "log-driver": "syslog" 118 | } 119 | ``` 120 | 121 | 以上更改是针对所有的容器的日志驱动的。我们也可以单独为单一容器设置日志驱动。 122 | 123 | #### Docker 单一容器日志驱动配置 124 | 125 | 在 运行容器的时候指定 日志驱动 ` --log-driver `。 126 | 127 | ```bash 128 | docker run -itd --log-driver none alpine ash # 这里指定的日志驱动为 none 129 | ``` 130 | 131 | 132 | 133 | #### 日志驱动 一 、local 134 | 135 | `local` 日志驱动 记录从容器的 `STOUT/STDERR` 的输出,并写到宿主机的磁盘。 136 | 137 | 默认情况下,local 日志驱动为每个容器保留 100MB 的日志信息,并启用自动压缩来保存。(经过测试,保留100MB 的日志是指没有经过压缩的日志) 138 | 139 | local 日志驱动的储存位置 `/var/lib/docker/containers/容器id/local-logs/` 以 `container.log` 命名。 140 | 141 | **local 驱动支持的选项** 142 | 143 | | 选项 | 描述 | 示例值 | 144 | | :--------- | :----------------------------------------------------------- | :------------------------- | 145 | | `max-size` | 切割之前日志的最大大小。可取值为(k,m,g), 默认为20m。 | `--log-opt max-size=10m` | 146 | | `max-file` | 可以存在的最大日志文件数。如果超过最大值,则会删除最旧的文件。**仅在max-size设置时有效。默认为5。 | `--log-opt max-file=3` | 147 | | `compress` | 对应切割日志文件是否启用压缩。默认情况下启用。 | `--log-opt compress=false` | 148 | 149 | 150 | 151 | **全局日志驱动设置为—local** 152 | 153 | 在配置文件 `/etc/docker/daemon.json`(注意该文件内容是 JSON 格式的)进行配置即可。 154 | 155 | ``` 156 | { 157 | "log-driver": "local", 158 | "log-opts": { 159 | "max-size": "10m" 160 | } 161 | } 162 | ``` 163 | 164 | 重启 docker 即可生效。 165 | 166 | **单个容器日志驱动设置为—local** 167 | 168 | 运行容器并设定为 `local` 驱动。 169 | 170 | ```bash 171 | # 运行一个容器 ,并设定日志驱动为 local ,并运行命令 ping www.baidu.com 172 | [root@localhost docker]# docker run -itd --log-driver local alpine ping www.baidu.com 173 | 3795b6483534961c1d5223359ad1106433ce2bf25e18b981a47a2d79ad7a3156 174 | # 查看运行的容器的 日志驱动是否是 local 175 | [root@localhost docker]# docker inspect -f '{{.HostConfig.LogConfig.Type}}' 3795b6483534961c 176 | local 177 | # 查看日志 178 | [root@localhost local-logs]# tail -f /var/lib/docker/containers/3795b6483534961c1d5223359ad1106433ce2bf25e18b981a47a2d79ad7a3156/local-logs/container.log 179 | NNdoutםѰ͕̈:64 bytes from 14.215.177.38: seq=816 ttl=55 time=5.320 ms 180 | NNdoutهµ͕̈͡:64 bytes from 14.215.177.38: seq=817 ttl=55 time=4.950 ms 181 | ``` 182 | 183 | 184 | 185 | > 注意事项: 经过测试,当我们产生了100 MB 大小的日志时 会有 四个压缩文件和一个 `container.log`: 186 | > 187 | > ```bash 188 | > [root@localhost local-logs]# ls -l 189 | > total 32544 190 | > -rw-r-----. 1 root root 18339944 May 16 09:41 container.log 191 | > -rw-r-----. 1 root root 3698660 May 16 09:41 container.log.1.gz 192 | > -rw-r-----. 1 root root 3726315 May 16 09:41 container.log.2.gz 193 | > -rw-r-----. 1 root root 3805668 May 16 09:41 container.log.3.gz 194 | > -rw-r-----. 1 root root 3744104 May 16 09:41 container.log.4.gz 195 | > ``` 196 | > 197 | > 那么当超过了 100MB 的日志文件,日志文件会继续写入到 `container.log`,但是会将 `container.log` 日志中老的日志删除,追加新的,也就是 当写满 100MB 日志后 ,再产生一条新日志,会删除 `container.log` 中的一条老日志,保存 100MB 的大小。**这个 对我们是会有一些影响的,** 198 | > 199 | > ```tex 200 | > 当我运行系统时 第一天由于bug产生了 100MB 日志,那么之前的日志就已经有 80MB 日志变成的压缩包,所以我在后续的运行中,只能获取最近的 20MB日志。 201 | > ``` 202 | 203 | 204 | 205 | #### 日志驱动 二、 默认的日志驱动—JSON 206 | 207 | **所有容器默认的日志驱动 `json-file`**。 208 | 209 | `json-file` 日志驱动 记录从容器的 `STOUT/STDERR` 的输出 ,用 JSON 的格式写到文件中,日志中不仅包含着 输出日志,还有时间戳和 输出格式。下面是一个 `ping www.baidu.com` 对应的 JSON 日志 210 | 211 | ```json 212 | {"log":"64 bytes from 14.215.177.39: seq=34 ttl=55 time=7.067 ms\r\n","stream":"stdout","time":"2019-05-16T14:14:15.030612567Z"} 213 | ``` 214 | 215 | json-file 日志的路径位于 `/var/lib/docker/containers/container_id/container_id-json.log`。 216 | 217 | `json-file` 的 日志驱动支持以下选项: 218 | 219 | | 选项 | 描述 | 示例值 | 220 | | :---------- | :----------------------------------------------------------- | :--------------------------------------- | 221 | | `max-size` | 切割之前日志的最大大小。可取值单位为(k,m,g), 默认为-1(表示无限制)。 | `--log-opt max-size=10m` | 222 | | `max-file` | 可以存在的最大日志文件数。如果切割日志会创建超过阈值的文件数,则会删除最旧的文件。**仅在max-size设置时有效。**正整数。默认为1。 | `--log-opt max-file=3` | 223 | | `labels` | 适用于启动Docker守护程序时。此守护程序接受的以逗号分隔的与日志记录相关的标签列表。 | `--log-opt labels=production_status,geo` | 224 | | `env` | 适用于启动Docker守护程序时。此守护程序接受的以逗号分隔的与日志记录相关的环境变量列表。 | `--log-opt env=os,customer` | 225 | | `env-regex` | 类似于并兼容`env`。用于匹配与日志记录相关的环境变量的正则表达式。 | `--log-opt env-regex=^(os|customer).` | 226 | | `compress` | 切割的日志是否进行压缩。默认是`disabled`。 | `--log-opt compress=true` | 227 | 228 | **`json-file` 的日志驱动示例** 229 | 230 | ```bash 231 | # 设置 日志驱动为 json-file ,我们也可以不设置,因为默认就是 json-file 232 | docker run -itd --name test-log-json --log-driver json-file alpine ping www.baidu.com 233 | 199608b2e2c52136d2a17e539e9ef7fbacf97f1293678aded421dadbdb006a5e 234 | 235 | # 查看日志,日志名称就是 容器名称-json.log 236 | tail -f /var/lib/docker/containers/199608b2e2c52136d2a17e539e9ef7fbacf97f1293678aded421dadbdb006a5e/199608b2e2c52136d2a17e539e9ef7fbacf97f1293678aded421dadbdb006a5e-json.log 237 | 238 | {"log":"64 bytes from 14.215.177.39: seq=13 ttl=55 time=15.023 ms\r\n","stream":"stdout","time":"2019-05-16T14:13:54.003118877Z"} 239 | {"log":"64 bytes from 14.215.177.39: seq=14 ttl=55 time=9.640 ms\r\n","stream":"stdout","time":"2019-05-16T14:13:54.999011017Z"} 240 | {"log":"64 bytes from 14.215.177.39: seq=15 ttl=55 time=8.938 ms\r\n","stream":"stdout","time":"2019-05-16T14:13:55.998612636Z"} 241 | {"log":"64 bytes from 14.215.177.39: seq=16 ttl=55 time=18.086 ms\r\n","stream":"stdout","time":"2019-05-16T14:13:57.011235913Z"} 242 | {"log":"64 bytes from 14.215.177.39: seq=17 ttl=55 time=12.615 ms\r\n","stream":"stdout","time":"2019-05-16T14:13:58.007104112Z"} 243 | {"log":"64 bytes from 14.215.177.39: seq=18 ttl=55 time=11.001 ms\r\n","stream":"stdout","time":"2019-05-16T14:13:59.007559413Z"} 244 | ``` 245 | 246 | #### 日志驱动 三、syslog 247 | 248 | syslog 日志驱动将日志路由到 syslog 服务器,syslog 以原始的字符串作为 日志消息元数据,接收方可以提取以下的消息: 249 | 250 | - level 日志等级 ,如`debug`,`warning`,`error`,`info`。 251 | - timestamp 时间戳 252 | - hostname 事件发生的主机 253 | - facillty 系统模块 254 | - 进程名称和进程 ID 255 | 256 | **`syslog` 日志驱动全局配置** 257 | 258 | 编辑 `/etc/docker/daemon.json` 文件 259 | 260 | ```json 261 | { 262 | "log-driver": "syslog", 263 | "log-opts": { 264 | "syslog-address": "udp://1.2.3.4:1111" 265 | } 266 | } 267 | ``` 268 | 269 | 重启 docker 即可生效。 270 | 271 | | Option | Description | Example value | 272 | | :----------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | 273 | | `syslog-address` | 指定syslog 服务所在的服务器和使用的协议和端口。 格式:`[tcp|udp|tcp+tls]://host:port,unix://path, orunixgram://path`. 默认端口是 514. | `--log-opt syslog-address=tcp+tls://192.168.1.3:514`, `--log-opt syslog-address=unix:///tmp/syslog.sock` | 274 | | `syslog-facility` | 使用的 `syslog` 的设备, 具体设备名称见 [syslog documentation](https://tools.ietf.org/html/rfc5424#section-6.2.1). | `--log-opt syslog-facility=daemon` | 275 | | `syslog-tls-ca-cert` | 如果使用的是 `tcp+tls` 的地址,指定CA 证书的地址,如果没有使用,则不设置该选项。 | `--log-opt syslog-tls-ca-cert=/etc/ca-certificates/custom/ca.pem` | 276 | | `syslog-tls-cert` | 如果使用的是 `tcp+tls` 的地址,指定 TLS 证书的地址,如果没有使用,则不设置该选项。 | `--log-opt syslog-tls-cert=/etc/ca-certificates/custom/cert.pem` | 277 | | `syslog-tls-key` | 如果使用的是 `tcp+tls` 的地址,指定 TLS 证书 key的地址,如果没有使用,则不设置该选项。** | `--log-opt syslog-tls-key=/etc/ca-certificates/custom/key.pem` | 278 | | `syslog-tls-skip-verify` | 如果设置为 true ,会跳过 TLS 验证,默认为 false | `--log-opt syslog-tls-skip-verify=true` | 279 | | `tag` | 将应用程序的名称附加到 `syslog` 消息中,默认情况下使用容器ID的前12位去 标记这个日志信息。 | `--log-opt tag=mailer` | 280 | | `syslog-format` | `syslog` 使用的消息格式 如果未指定则使用本地 UNIX syslog 格式,rfc5424micro 格式具有微妙时间戳。 | `--log-opt syslog-format=rfc5424micro` | 281 | | `labels` | 启动 docker 时,配置与日志相关的标签,以逗号分割 | `--log-opt labels=production_status,geo` | 282 | | `env` | 启动 docker 时,指定环境变量用于日志中,以逗号分隔 | `--log-opt env=os,customer` | 283 | | `env-regex` | 类似并兼容 `env`, | `--log-opt env-regex=^(os\|customer)` | 284 | 285 | **单个容器日志驱动设置为—syslog ** 286 | 287 | `Linux` 系统中 我们用的系统日志模块时 `rsyslog` ,它是基于`syslog` 的标准实现。我们要使用 syslog 驱动需要使用 系统自带的 `rsyslog` 服务。 288 | 289 | ```bash 290 | # 查看当前 rsyslog 版本和基本信息 291 | [root@localhost harbor]# rsyslogd -v 292 | rsyslogd 8.24.0, compiled with: 293 | PLATFORM: x86_64-redhat-linux-gnu 294 | PLATFORM (lsb_release -d): 295 | FEATURE_REGEXP: Yes 296 | GSSAPI Kerberos 5 support: Yes 297 | FEATURE_DEBUG (debug build, slow code): No 298 | 32bit Atomic operations supported: Yes 299 | 64bit Atomic operations supported: Yes 300 | memory allocator: system default 301 | Runtime Instrumentation (slow code): No 302 | uuid support: Yes 303 | Number of Bits in RainerScript integers: 64 304 | 305 | See http://www.rsyslog.com for more information. 306 | ``` 307 | 308 | 配置 syslog , 在配置文件 `/etc/rsyslog.conf` 大约14-20行,我们可以看到两个配置,一个udp,一个tcp ,都是监听 514 端口,提供 syslog 的接收。选择 tcp 就将 tcp 的两个配置的前面 # 号注释即可。 309 | 310 | ``` 311 | # Provides UDP syslog reception 312 | #$ModLoad imudp 313 | #$UDPServerRun 514 314 | 315 | # Provides TCP syslog reception 316 | #$ModLoad imtcp 317 | #$InputTCPServerRun 514 318 | ``` 319 | 320 | 然后重启 rsyslog,我们可以看到514端口在监听。 321 | 322 | ```bash 323 | systemctl restart rsyslog 324 | [root@localhost harbor]# netstat -ntul |grep 514 325 | tcp 0 0 0.0.0.0:514 0.0.0.0:* LISTEN 326 | tcp6 0 0 :::514 :::* LISTEN 327 | ``` 328 | 329 | 启动一个以 `syslog` 为驱动的容器。 330 | 331 | ```bash 332 | docker run -d -it -p 87:80 --log-driver syslog --log-opt syslog-address=tcp://127.0.0.1:514 --name nginx-syslog nginx 333 | 334 | ``` 335 | 336 | 访问并查看日志 337 | 338 | ```bash 339 | # 访问nginx 340 | curl 127.0.0.1:87 341 | # 查看访问日志 342 | tail -f /var/log/messages 343 | May 17 15:56:48 localhost fe18924aefde[6141]: 172.17.0.1 - - [17/May/2019:07:56:48 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"#015 344 | May 17 15:58:16 localhost fe18924aefde[6141]: 172.17.0.1 - - [17/May/2019:07:58:16 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"#015 345 | ``` 346 | 347 | 348 | 349 | #### 日志驱动 四、Journald 350 | 351 | `journald` 日志驱动程序将容器的日志发送到 `systemd journal`, 可以使用 `journal API` 或者使用 `docker logs` 来查日志。 352 | 353 | 354 | 355 | 除了日志本身以外, `journald` 日志驱动还会在日志加上下面的数据与消息一起储存。 356 | 357 | | Field | Description | 358 | | :----------------------------------- | :----------------------------------------------------------- | 359 | | `CONTAINER_ID` | 容器ID,为 12个字符 | 360 | | `CONTAINER_ID_FULL` | 完整的容器ID,为64个字符 | 361 | | `CONTAINER_NAME` | 启动时容器的名称,如果容器后面更改了名称,日志中的名称不会更改。 | 362 | | `CONTAINER_TAG`, `SYSLOG_IDENTIFIER` | 容器的tag. | 363 | | `CONTAINER_PARTIAL_MESSAGE` | 当日志比较长的时候使用标记来表示(显示日志的大小) | 364 | 365 | 选项 366 | 367 | | 选项 | 是否必须 | 描述 | 368 | | :---------- | :------- | :----------------------------------------------------------- | 369 | | `tag` | 可选的 | 指定要在日志中设置`CONTAINER_TAG`和`SYSLOG_IDENTIFIER`值的模板。 | 370 | | `labels` | 可选的 | 以逗号分隔的标签列表,如果为容器指定了这些标签,则应包含在消息中。 | 371 | | `env` | 可选的 | 如果为容器指定了这些变量,则以逗号分隔的环境变量键列表(应包含在消息中)。 | 372 | | `env-regex` | 可选的 | 与env类似并兼容。用于匹配与日志记录相关的环境变量的正则表达式 。 | 373 | 374 | 375 | 376 | **`journald` 日志驱动全局配置** 377 | 378 | 编辑 `/etc/docker/daemon.json` 文件 379 | 380 | ``` 381 | { 382 | "log-driver": "journald" 383 | } 384 | ``` 385 | 386 | **单个容器日志驱动设置为—`journald`** 387 | 388 | ``` 389 | docker run -d -it --log-driver=journald \ 390 | --log-opt labels=location \ 391 | --log-opt env=TEST \ 392 | --env "TEST=false" \ 393 | --label location=china \ 394 | --name nginx-journald\ 395 | -p 80:80\ 396 | nginx 397 | ``` 398 | 399 | 查看日志 `journalctl` 400 | 401 | ```bash 402 | # 只查询指定容器的相关消息 403 | journalctl CONTAINER_NAME=webserver 404 | # -b 指定从上次启动以来的所有消息 405 | journalctl -b CONTAINER_NAME=webserver 406 | # -o 指定日志消息格式,-o json 表示以json 格式返回日志消息 407 | journalctl -o json CONTAINER_NAME=webserver 408 | # -f 一直捕获日志输出 409 | journalctl -f CONTAINER_NAME=webserver 410 | ``` 411 | 412 | > 如果我们的容器在启动的时候加了 -t 参数,启用了 TTY 的话,那么我查看日志是会像下面一样 413 | > 414 | > ```text 415 | > May 17 17:19:26 localhost.localdomain 2a338e4631fe[6141]: [104B blob data] 416 | > May 17 17:19:32 localhost.localdomain 2a338e4631fe[6141]: [104B blob data] 417 | > ``` 418 | > 419 | > 显示`[104B blob data]` 而不是完整日志原因是因为有 `\r` 的存在,如果我们要完整显示,需要加上参数 `--all` 。 420 | 421 | 422 | 423 | ## 三、 生产环境中该如何储存容器中的日志 424 | 425 | 我们在上面看到了 Docker 官方提供了 很多日志驱动,但是上面的这些驱动都是针对的 标准输出的日志驱动。 426 | 427 | #### 容器日志分类 428 | 429 | 容器的日志实际是有两大类的: 430 | 431 | - **标准输出的** ,也就是 STDOUT 、STDERR ,**这类日志我们可以通过 Docker 官方的日志驱动进行收集。** 432 | 433 | 示例:Nginx 日志,Nginx 日志有 `access.log` 和 `error.log` ,我们在 Docker Hub 上可以看到 Nginx 的 dockerfile 对于这两个日志的处理是: 434 | 435 | ```dockerfile 436 | RUN ln -sf /dev/stdout /var/log/nginx/access.log \ 437 | && ln -sf /dev/stderr /var/log/nginx/error.log 438 | ``` 439 | 440 | 都软连接到 `/dev/stdout` 和 `/dev/stderr` ,也就是标准输出,所以这类 容器是可以使用 Docker 官方的日志驱动。 441 | 442 | - **文本日志**,存在在于容器内部,并没有重定向到 容器的标准输出的日志。 443 | 444 | 示例: Tomcat 日志,Tomcat 有 catalina、localhost、manager、admin、host-manager,我们可以在 Docker Hub 看到 Tomcat 的 dockerfile 只有对于 catalina 进行处理,其它日志将储存在容器里。 445 | 446 | ```dockerfile 447 | CMD ["catalina.sh", "run"] 448 | ``` 449 | 450 | 我们运行了一个 Tomcat 容器 ,然后进行访问后,并登陆到容器内部,我们可以看到产生了文本日志: 451 | 452 | ```bash 453 | root@25ba00fdab97:/usr/local/tomcat/logs# ls -l 454 | total 16 455 | -rw-r-----. 1 root root 6822 May 17 14:36 catalina.2019-05-17.log 456 | -rw-r-----. 1 root root 0 May 17 14:36 host-manager.2019-05-17.log 457 | -rw-r-----. 1 root root 459 May 17 14:36 localhost.2019-05-17.log 458 | -rw-r-----. 1 root root 1017 May 17 14:37 localhost_access_log.2019-05-17.txt 459 | -rw-r-----. 1 root root 0 May 17 14:36 manager.2019-05-17.log 460 | ``` 461 | 462 | 这类容器我们下面有专门的方案来应对。 463 | 464 | ### 一、当是完全是标准输出的类型的容器 465 | 466 | 我们可以选择 json-file 、syslog、local 等 Docker 支持的日志驱动。 467 | 468 | 469 | 470 | ### 二、当有文件文本日志的类型容器 471 | 472 | #### 方案一 挂载目录 bind 473 | 474 | 创建一个目录,将目录挂载到 容器中产生日志的目录。 475 | 476 | ```bash 477 | --mount type=bind,src=/opt/logs/,dst=/usr/local/tomcat/logs/ 478 | ``` 479 | 480 | 示例: 481 | 482 | ```bash 483 | # 创建挂载目录/opt/logs 484 | [root@fy-local-2 /]# mkdir /opt/logs 485 | # 创建容器tomcat-bind 并将 /opt/logs 挂载至 /usr/local/tomcat/logs/ 486 | [root@fy-local-2 /]# docker run -d --name tomcat-bind -P --mount type=bind,src=/opt/logs/,dst=/usr/local/tomcat/logs/ tomcat 487 | [root@fy-local-2 /]# ls -l /opt/logs/ 488 | total 12 489 | -rw-r----- 1 root root 6820 May 22 17:31 catalina.2019-05-22.log 490 | -rw-r----- 1 root root 0 May 22 17:31 host-manager.2019-05-22.log 491 | -rw-r----- 1 root root 459 May 22 17:31 localhost.2019-05-22.log 492 | -rw-r----- 1 root root 0 May 22 17:31 localhost_access_log.2019-05-22.txt 493 | -rw-r----- 1 root root 0 May 22 17:31 manager.2019-05-22.log 494 | ``` 495 | 496 | 497 | 498 | #### 方案二 使用数据卷 volume 499 | 500 | 创建数据卷,创建容器时绑定数据卷, 501 | 502 | ```bash 503 | --mount type=volume src=volume_name dst=/usr/local/tomcat/logs/ 504 | ``` 505 | 506 | 示例: 507 | 508 | ```bash 509 | # 创建tomcat应用数据卷名称为 tomcat 510 | [root@fy-local-2 /]# docker volume create tomcat 511 | # 创建容器tomcat-volume 并指定数据卷为 tomcat,绑定至 /usr/local/tomcat/logs/ 512 | [root@fy-local-2 /]# docker run -d --name tomcat-volume -P --mount type=volume,src=tomcat,dst=/usr/local/tomcat/logs/ tomcat 513 | # 查看数据卷里面的内容 514 | [root@fy-local-2 /]# ls -l /var/lib/docker/volumes/tomcat/_data/ 515 | total 12 516 | -rw-r----- 1 root root 6820 May 22 17:33 catalina.2019-05-22.log 517 | -rw-r----- 1 root root 0 May 22 17:33 host-manager.2019-05-22.log 518 | -rw-r----- 1 root root 459 May 22 17:33 localhost.2019-05-22.log 519 | -rw-r----- 1 root root 0 May 22 17:33 localhost_access_log.2019-05-22.txt 520 | -rw-r----- 1 root root 0 May 22 17:33 manager.2019-05-22.log 521 | 522 | ``` 523 | 524 | #### 方案三 计算容器 rootfs 挂载点 525 | 526 | 此方案的文字内容摘抄于 527 | 528 | 使用挂载宿主机目录的方式采集日志对应用会有一定的侵入性,因为它要求容器启动的时候包含挂载命令。如果采集过程能对用户透明那就太棒了。事实上,可以通过计算容器 rootfs 挂载点来达到这种目的。 529 | 530 | 和容器 rootfs 挂载点密不可分的一个概念是 [storage driver](https://docs.docker.com/storage/storagedriver/)。实际使用过程中,用户往往会根据 linux 版本、文件系统类型、容器读写情况等因素选择合适的 storage driver。不同 storage driver 下,容器的 rootfs 挂载点遵循一定规律,因此我们可以根据 storage driver 的类型推断出容器的 rootfs 挂载点,进而采集容器内部日志。下表展示了部分 storage dirver 的 rootfs 挂载点及其计算方法。 531 | 532 | | Storage driver | rootfs 挂载点 | 计算方法 | 533 | | :------------- | :------------------------------------------- | :----------------------------------------------------------- | 534 | | aufs | /var/lib/docker/aufs/mnt/ | id 可以从如下文件读到。 `/var/lib/docker/image/aufs/layerdb/mounts//mount-id` | 535 | | overlay | /var/lib/docker/overlay//merged | 完整路径可以通过如下命令得到。 `docker inspect -f '{{.GraphDriver.Data.MergedDir}}' ` | 536 | | overlay2 | /var/lib/docker/overlay2//merged | 完整路径可以通过如下命令得到。 `docker inspect -f '{{.GraphDriver.Data.MergedDir}}' ` | 537 | | devicemapper | /var/lib/docker/devicemapper/mnt//rootfs | id 可以通过如下命令得到。 `docker inspect -f '{{.GraphDriver.Data.DeviceName}}' ` | 538 | 539 | 示例: 540 | 541 | ```bash 542 | # 创建容器 tomcat-test 543 | [root@fy-local-2 /]# docker run -d --name tomcat-test -P tomcat 544 | 36510dd653ae7dcac1d017174b1c38b3f9a226f9c4e329d0ff656cfe041939ff 545 | # 查看tomcat-test 容器的 挂载点位置 546 | [root@fy-local-2 /]# docker inspect -f '{{.GraphDriver.Data.MergedDir}}' 36510dd653ae7dcac1d017174b1c38b3f9a226f9c4e329d0ff656cfe041939ff 547 | /var/lib/docker/overlay2/c10ec54bab8f3fccd2c5f1a305df6f3b1e53068776363ab0c104d253216b799d/merged 548 | # 查看挂载点的目录结构 549 | [root@fy-local-2 /]# ls -l /var/lib/docker/overlay2/c10ec54bab8f3fccd2c5f1a305df6f3b1e53068776363ab0c104d253216b799d/merged 550 | total 4 551 | drwxr-xr-x 1 root root 179 May 8 13:05 bin 552 | drwxr-xr-x 2 root root 6 Mar 28 17:12 boot 553 | drwxr-xr-x 1 root root 43 May 22 17:27 dev 554 | lrwxrwxrwx 1 root root 33 May 8 13:08 docker-java-home -> /usr/lib/jvm/java-8-openjdk-amd64 555 | drwxr-xr-x 1 root root 66 May 22 17:27 etc 556 | drwxr-xr-x 2 root root 6 Mar 28 17:12 home 557 | drwxr-xr-x 1 root root 6 May 16 08:50 lib 558 | drwxr-xr-x 2 root root 34 May 6 08:00 lib64 559 | drwxr-xr-x 2 root root 6 May 6 08:00 media 560 | drwxr-xr-x 2 root root 6 May 6 08:00 mnt 561 | drwxr-xr-x 2 root root 6 May 6 08:00 opt 562 | drwxr-xr-x 2 root root 6 Mar 28 17:12 proc 563 | drwx------ 1 root root 27 May 22 17:29 root 564 | drwxr-xr-x 3 root root 30 May 6 08:00 run 565 | drwxr-xr-x 2 root root 4096 May 6 08:00 sbin 566 | drwxr-xr-x 2 root root 6 May 6 08:00 srv 567 | drwxr-xr-x 2 root root 6 Mar 28 17:12 sys 568 | drwxrwxrwt 1 root root 29 May 16 08:50 tmp 569 | drwxr-xr-x 1 root root 19 May 6 08:00 usr 570 | drwxr-xr-x 1 root root 41 May 6 08:00 var 571 | # 查看日志 572 | [root@fy-local-2 /]# ls -l /var/lib/docker/overlay2/c10ec54bab8f3fccd2c5f1a305df6f3b1e53068776363ab0c104d253216b799d/merged/usr/local/tomcat/logs/ 573 | total 20 574 | -rw-r----- 1 root root 14514 May 22 17:40 catalina.2019-05-22.log 575 | -rw-r----- 1 root root 0 May 22 17:27 host-manager.2019-05-22.log 576 | -rw-r----- 1 root root 1194 May 22 17:40 localhost.2019-05-22.log 577 | -rw-r----- 1 root root 0 May 22 17:27 localhost_access_log.2019-05-22.txt 578 | -rw-r----- 1 root root 0 May 22 17:27 manager.2019-05-22.log 579 | 580 | ``` 581 | 582 | 583 | 584 | #### 方案四 在代码层中实现直接将日志写入redis 585 | 586 | docker ——》redis ——》Logstash——》Elasticsearch 587 | 588 | 通过代码层面,直接将日志写入`redis`,最后写入 `Elasticsearch`。 589 | 590 | 591 | 592 | 以上就是对 Docker 日志的所有的概念解释和方提供,具体采用什么方案,根据公司的具体的业务来选择。合适的才是最好的。 593 | 594 | -------------------------------------------------------------------------------- /Zabbix/zabbix-tcp-connection.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0 4 | 2019-06-24T08:12:20Z 5 | 6 | 7 | Templates 8 | 9 | 10 | 11 | 682 | 683 | 684 | 685 | {Template TCP Connection Status:tcp.status[timewait].last()}>10000 686 | 0 687 | 688 | There are too many TCP TIME_WAIT status 689 | 0 690 | 691 | 692 | 0 693 | 4 694 | 695 | 0 696 | 0 697 | 698 | 699 | 700 | 701 | 702 | 703 | TCP Status 704 | 900 705 | 200 706 | 0.0000 707 | 100.0000 708 | 1 709 | 1 710 | 0 711 | 1 712 | 0 713 | 0.0000 714 | 0.0000 715 | 0 716 | 0 717 | 0 718 | 0 719 | 720 | 721 | 0 722 | 0 723 | C80000 724 | 0 725 | 2 726 | 0 727 | 728 | Template TCP Connection Status 729 | tcp.status[closed] 730 | 731 | 732 | 733 | 1 734 | 0 735 | 00C800 736 | 0 737 | 2 738 | 0 739 | 740 | Template TCP Connection Status 741 | tcp.status[closewait] 742 | 743 | 744 | 745 | 2 746 | 0 747 | 0000C8 748 | 0 749 | 2 750 | 0 751 | 752 | Template TCP Connection Status 753 | tcp.status[closing] 754 | 755 | 756 | 757 | 3 758 | 0 759 | C800C8 760 | 0 761 | 2 762 | 0 763 | 764 | Template TCP Connection Status 765 | tcp.status[established] 766 | 767 | 768 | 769 | 4 770 | 0 771 | 00C8C8 772 | 0 773 | 2 774 | 0 775 | 776 | Template TCP Connection Status 777 | tcp.status[finwait1] 778 | 779 | 780 | 781 | 5 782 | 0 783 | C8C800 784 | 0 785 | 2 786 | 0 787 | 788 | Template TCP Connection Status 789 | tcp.status[finwait2] 790 | 791 | 792 | 793 | 6 794 | 0 795 | C8C8C8 796 | 0 797 | 2 798 | 0 799 | 800 | Template TCP Connection Status 801 | tcp.status[lastack] 802 | 803 | 804 | 805 | 7 806 | 0 807 | 960000 808 | 0 809 | 2 810 | 0 811 | 812 | Template TCP Connection Status 813 | tcp.status[listen] 814 | 815 | 816 | 817 | 8 818 | 0 819 | 009600 820 | 0 821 | 2 822 | 0 823 | 824 | Template TCP Connection Status 825 | tcp.status[synrecv] 826 | 827 | 828 | 829 | 9 830 | 0 831 | 000096 832 | 0 833 | 2 834 | 0 835 | 836 | Template TCP Connection Status 837 | tcp.status[synsent] 838 | 839 | 840 | 841 | 10 842 | 0 843 | 960096 844 | 0 845 | 2 846 | 0 847 | 848 | Template TCP Connection Status 849 | tcp.status[timewait] 850 | 851 | 852 | 853 | 854 | 855 | 856 | --------------------------------------------------------------------------------