0%

什么是ELK

https://www.elastic.co/cn/what-is/elk-stack

ELK 全称 ELK Stack,它的更新换代产品叫 Elastic Stack

ELK = Elasticsearch + Logstash + Kibana

  • Elasticsearch:搜索和分析引擎
  • Logstash:服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到诸如 Elasticsearch 等“存储库”中
  • Kibana:让用户在 Elasticsearch 中使用图形和图表对数据进行可视化

什么是Elasticsearch

https://www.elastic.co/cn/what-is/elasticsearch

什么是 Logstash

Logstash 是 Elastic Stack 的核心产品之一,可用来对数据进行聚合和处理,并将数据发送到 Elasticsearch。Logstash 是一个开源的服务器端数据处理管道,允许您在将数据索引到 Elasticsearch 之前同时从多个来源采集数据,并对数据进行充实和转换。

什么是 kibana

https://www.elastic.co/cn/what-is/kibana

为什么使用ELK

ELK 组件在海量日志系统的运维中,可用于解决以下主要问题:

  • 分布式日志数据统一收集,实现集中式查询和管理
  • 故障排查
  • 安全信息和事件管理
  • 报表功能

elasticsearch

基本概念

参考博客:https://www.cnblogs.com/qdhxhz/p/11448451.html

重点理解 index 和 document 这两个概念:index(索引)类似kafka的topic,oss的bucket,要尽量控制 index 的数量;index中的单条数据称为document(文档),相当于mysql表中的行

之前的版本中,索引和文档中间还有个type(类型)的概念,每个索引下可以建立多个type,document存储时需要指定index和type,因为一个index中的type并不隔离,document不能重名,所以type并没有多少意义。从7.0版本开始,一个index只能建一个名为_doc的type,8.0.0 以后将完全取消

下面是一个document的源数据:

  • _index:文档所属索引名称
  • _type:文档所属类型名
  • _id:doc主键,写入时指定,如果不指定,则系统自动生成一个唯一的UUID值
  • _version:doc版本信息,保证doc的变更能以正确的顺序执行,避免乱序造成的数据丢失
  • _seq_no:严格递增的顺序号,shard级别严格递增,保证后写入的doc的_seq_no大于先写入的doc的_seq_no
  • _primary_term:和_seq_no一样是一个整数,每当primary shard发生重新分配时,比如重启,primary选举等,_primary_term会递增1
  • found:查询的ID正确那么ture, 如果 Id 不正确,就查不到数据,found字段就是false
  • _source:文档的原始JSON数据

apt安装

elasticsearch 集群中 master 与 slave 的区别:

master:统计各节点状态信息、集群状态信息统计、索引的创建和删除、索引分配的管理、关闭节点等
slave:从 master 同步数据、等待机会成为 master

  1. apt 安装

    1
    [root@elk2-ljk src]$dpkg -i elasticsearch-7.11.1-amd64.deb

    主要目录:

    1
    2
    3
    /usr/share/elasticsearch	# 主目录
    /etc/elasticsearch # 配置文件目录
    ...
  2. 修改hosts

    1
    2
    3
    4
    5
    [root@elk2-ljk src]$vim /etc/hosts
    ...
    10.0.1.121 elk1-ljk.local
    10.0.1.122 elk2-ljk.local
    10.0.1.123 elk3-ljk.local
  3. 修改配置文件 elasticsearch.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@elk2-ljk /]$grep '^[a-Z]' /etc/elasticsearch/elasticsearch.yml
    cluster.name: es-cluster # ELK的集群名称,名称相同即属于是同一个集群
    node.name: node-2 # 当前节点在集群内的节点名称
    path.data: /data/elasticsearch/data # ES数据保存目录
    path.logs: /data/elasticsearch/logs # ES日志保存目
    bootstrap.memory_lock: true # 服务启动的时候锁定足够的内存,防止数据写入swap
    network.host: 10.0.1.122 # 监听本机ip
    http.port: 9200 # 监听端口
    # 集群中node节点发现列表,最好使用hostname,这里为了方便,使用ip
    discovery.seed_hosts: ["elk1-ljk.local", "elk2-ljk.local", "elk3-ljk.local"]
    # 集群初始化那些节点可以被选举为master
    cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]
    gateway.recover_after_nodes: 2 # 一个集群中的 N 个节点启动后,才允许进行数据恢复处理,默认是 1
    # 设置是否可以通过正则或者_all 删除或者关闭索引库,默认 true 表示必须需要显式指定索引库名称,生产环境建议设置为 true,删除索引库的时候必须指定,否则可能会误删索引库中的索引库
    action.destructive_requires_name: true
  4. 修改内存限制

    1
    2
    3
    [root@elk2-ljk src]$vim /usr/lib/systemd/system/elasticsearch.service
    ...
    LimitMEMLOCK=infinity # 无限制使用内存
    1
    2
    3
    [root@elk2-ljk src]$vim /usr/local/elasticsearch/config/jvm.options
    -Xms2g # 最小内存限制
    -Xmx2g # 最大内存限制
  5. 创建数据目录并修改属主

    1
    2
    [root@elk2-ljk src]$mkdir -p /data/elasticsearch
    [root@elk3-ljk src]$chown -R elasticsearch:elasticsearch /data/elasticsearch
  6. 启动

    1
    2
    3
    4
    5
    6
    [root@elk1-ljk src]$systemctl start elasticsearch.service 	# 稍等几分钟

    [root@elk1-ljk ~]$curl http://10.0.1.121:9200/_cat/nodes
    10.0.1.123 13 96 0 0.14 0.32 0.22 cdhilmrstw - node-3
    10.0.1.122 28 97 0 0.01 0.02 0.02 cdhilmrstw * node-2 # master
    10.0.1.121 26 96 2 0.13 0.07 0.03 cdhilmrstw - node-1

源码编译

启动总是失败,各种报错,解决不了…

安装 elasticsearch 插件

插件是为了完成不同的功能,官方提供了一些插件但大部分是收费的,另外也有一些开发爱好者提供的插件,可以实现对 elasticsearch 集群的状态监控与管理配置等功能

head 插件

在 elasticsearch 5.x 版本以后不再支持直接安装 head 插件,而是需要通过启动一个服务方式

github 地址:https://github.com/mobz/elasticsearch-head

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# git太慢,这里用迅雷下载zip包,然后上传
[root@elk1-ljk src]$unzip master.zip
[root@elk1-ljk src]$cd elasticsearch-head-master/
[root@elk1-ljk elasticsearch-head-master]$npm install grunt -save
[root@elk1-ljk elasticsearch-head-master]$npm install # 这一步要等很久
[root@elk1-ljk elasticsearch-head-master]$npm run start # 前台启动

# 开启跨域访问支持,每个节点都需要开启
[root@elk3-ljk ~]$vim /etc/elasticsearch/elasticsearch.yml
...
http.cors.enabled: true
http.cors.allow-origin: "*"

[root@elk2-ljk games]$systemctl restart elasticsearch.service # 重启elasticsearch

kopf 插件

过时的插件,只支持 elasticsearc 1.x 或 2.x 的版本

cerebro 插件

新开源的 elasticsearch 集群 web 管理程序,需要 java11 或者更高版本

github 地址:https://github.com/lmenezes/cerebro

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@elk2-ljk src]$unzip cerebro-0.9.3.zip
[root@elk2-ljk src]$cd cerebro-0.9.3/
[root@elk2-ljk cerebro-0.9.3]$vim conf/application.conf
...
# host列表
hosts = [
{
host = "http://10.0.1.122:9200"
name = "es-cluster1" # host的名称,如果有多个elasticsearch集群,可以用这个name区分
# headers-whitelist = [ "x-proxy-user", "x-proxy-roles", "X-Forwarded-For" ]
}
]

[root@elk2-ljk cerebro-0.9.3]$./bin/cerebro # 前台启动

监控 elasticsearch 集群状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@elk3-ljk ~]$curl http://10.0.1.122:9200/_cluster/health?pretty=true
{
"cluster_name" : "es-cluster",
"status" : "green", # green:运行正常、yellow:副本丢失、red:主分片丢失
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 0,
"active_shards" : 0,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}

zabbix 添加监控

logstash

官方参考文档:https://www.elastic.co/guide/en/logstash/current/index.html

logstash是一个具有3个阶段的处理管道:输入 –> 过滤器 –> 输出

输入生成事件,过滤器修改数据(日志),输出将数据(日志)发送到其他地方

安装

logstash 依赖 java,可以自己配置 java 环境,如果不配置,logstash 会使用其自带的 openjdk

1
[root@elk2-ljk src]$dpkg -i logstash-7.11.1-amd64.deb

命令

1
[root@elk2-ljk bin]$./logstash --help
  • -n:node name,就是节点的hostname,例如:elk2-ljk.local
  • -f:从特定的文件或目录加载logstash配置。如果给定一个目录,该目录中的所有文件将按字典顺序合并,然后作为单个配置文件进行解析。您还可以指定通配符(globs),任何匹配的文件将按照上面描述的顺序加载。如果不指定,默认读取 /etc/logstash/pipelines.yml
  • -e:从命令行加载logstash配置,一般不用
  • -t:检查配置文件是否合法,重启logstash之前,建议先检查一遍配置文件

插件

logstash 的输入和输出都依赖插件

不同的插件使用不同的配置,但是所有输入插件都支持以下配置选项:

配置项 类型 说明
add_field hash Add a field to an event
codec codec 用于输入数据的编解码器。输入编解码器是一种方便的方法,可以在数据进入输入之前对其进行解码,而不需要在Logstash管道中使用单独的过滤器
enable_metric boolean Disable or enable metric logging for this specific plugin instance by default we record all the metrics we can, but you can disable metrics collection for a specific plugin.
id string 唯一的ID,如果没有指定,logstash会自动生成一个,尤其是多个相同类型的插件时,强烈建议配置此项,例如有多个file输入,应当配置此项防止混淆
tags array Add any number of arbitrary tags to your event.
This can help with processing later.
type string 类型,例如收集 /var/log/syslog 日志,type可以设置为 “system”;收集网站日志,type可以设置为 “web”。
此项用的较多,一般会根据判断 type 值来进行输出或过滤

所有输出插件都支持以下配置选项:

配置项 类型 说明
codec codec 用于输出数据的编解码器。输出编解码器是一种方便的方法,可以在数据离开输出之前对数据进行编码,而不需要在Logstash管道中使用单独的过滤器
enable_metric boolean Disable or enable metric logging for this specific plugin instance. By default we record all the metrics we can, but you can disable metrics collection for a specific plugin.
id string 唯一的ID,如果没有指定,logstash会自动生成一个,尤其是多个相同类型的插件时,强烈建议配置此项,例如有多个file输出,应当配置此项防止混淆

配置

配置:https://www.elastic.co/guide/en/logstash/current/configuration.html
配置文件结构:https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html
配置文件语法:https://www.elastic.co/guide/en/logstash/current/event-dependent-configuration.html
使用环境变量:https://www.elastic.co/guide/en/logstash/current/environment-variables.html
配置文件示例:https://www.elastic.co/guide/en/logstash/current/config-examples.html
数据发送到es:https://www.elastic.co/guide/en/logstash/current/connecting-to-cloud.html

1
2
3
4
5
6
7
8
9
10
11
input {
...
}

filter {
...
}

output {
...
}

多配置文件:

https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html
https://elasticstack.blog.csdn.net/article/details/100995868

1
2
3
4
5
6
7
[root@elk2-ljk logstash]$cat pipelines.yml 
# This file is where you define your pipelines. You can define multiple.
# For more information on multiple pipelines, see the documentation:
# https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html

- pipeline.id: main
path.config: "/etc/logstash/conf.d/*.conf"

测试

标准输入输出

stdin:标准输入插件
output:标准输出插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@elk2-ljk conf.d]$cat /etc/logstash/conf.d/test.conf 
input {
stdin {}
}

output {
stdout {}
}
[root@elk2-ljk conf.d]$/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/test.conf
... # 启动得等一会
[INFO ] 2021-03-04 18:10:06.020 [Api Webserver] agent - Successfully started Logstash API endpoint {:port=>9600}
hello word # 标准输入
{
"@timestamp" => 2021-03-04T10:10:15.528Z, # 当前事件的发生时间
"host" => "elk2-ljk.local", # 标记事件发生的节点
"@version" => "1", # 事件版本号,一个事件就是一个 ruby 对象
"message" => "hello word" # 息的具体内容
}

输出到文件

输出到 elasticsearch

kibana

开源的数据分析和可视化平台,可以 对 Elasticsearch 索引中的数据进行搜索、查看、交互操作,可以很方便的利用图表、表格及地图对数据进行多元化的分析和呈现

安装

1
2
3
4
5
6
7
8
9
10
[root@elk1-ljk src]$tar zxf kibana-7.11.1-linux-x86_64.tar.gz
[root@elk1-ljk src]$mv kibana-7.11.1-linux-x86_64 /usr/local/kibana
[root@elk1-ljk src]$cd /usr/local/kibana
[root@elk1-ljk kibana]$grep '^[a-Z]' config/kibana.yml # 修改以下配置项
server.port: 5601
server.host: "10.0.1.121"
elasticsearch.hosts: ["http://10.0.1.121:9200"]
i18n.locale: "zh-CN"

[root@elk1-ljk kibana]$./bin/kibana --allow-root # 启动

因为笔记本的性能问题,将elasticsearch集群缩减为elasticsearch单节点,这导致kibana无法连接到elasticsearch,启动失败。解决办法:将elasticsearch的数据目录清空,然后重启

1
2
3
4
5
6
[root@elk1-ljk data]$systemctl stop elasticsearch.service 	# 停止elasticsearch
[root@elk1-ljk data]$ls /data/elasticsearch/
data logs
[root@elk1-ljk data]$rm -rf /data/elasticsearch/* # 清空数据目录
[root@elk1-ljk data]$systemctl start elasticsearch.service # 重新启动elasticsearch
[root@elk1-ljk kibana]$./bin/kibana --allow-root # 再次启动kibana

查看状态

通过 logstash 收集日志

SonarQube 是一个用于代码质量管理的开放平台,通过插件机制,SonarQube 可以集成不同的测试
工具,代码分析工具,以及持续集成工具,例如Hudson/Jenkins 等

官网:https://www.sonarqube.org/

部署SonarQube

略…

jenkins服务器部署扫描器 sonar-scanner

官方文档: https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/

部署sonar-scanner

顾名思义,扫描器的具体工作就是扫描代码,sonarqube通过调用扫描器sonar-scanner进行代码质量分析

下载地址: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/

1
2
3
4
5
[root@jenkins src]$unzip sonar-scanner-cli-4.6.0.2311.zip
[root@jenkins src]$mv sonar-scanner-4.6.0.2311/ /usr/local/sonar-scanner
[root@jenkins src]$vim /usr/local/sonar-scanner/conf/sonar-scanner.properties
sonar.host.url=http://10.0.1.102:9000 # 指向sonarqube服务器的地址
sonar.sourceEncoding=UTF-8 # Default source code encoding

准备测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@jenkins src]$unzip sonar-examples-master.zip ^C
[root@jenkins src]$cd sonar-examples-master/projects/languages/php/php-sonar-runner
[root@jenkins php-sonar-runner]$ll
total 24
drwxr-xr-x 3 root root 4096 Mar 2 23:30 ./
drwxr-xr-x 4 root root 4096 Jul 25 2016 ../
-rw-r--r-- 1 root root 453 Jul 25 2016 README.md
-rw-r--r-- 1 root root 331 Jul 25 2016 sonar-project.properties
drwxr-xr-x 2 root root 4096 Jul 25 2016 src/
-rw-r--r-- 1 root root 272 Jul 25 2016 validation.txt
[root@jenkins php-sonar-runner]$cat sonar-project.properties # 确保有这个文件
# Required metadata
sonar.projectKey=org.sonarqube:php-simple-sq-scanner
sonar.projectName=PHP :: Simple Project :: SonarQube Scanner
sonar.projectVersion=1.0

# Comma-separated paths to directories with sources (required)
sonar.sources=src

# Language
sonar.language=php

# Encoding of the source files
sonar.sourceEncoding=UTF-8

在源代码目录执行扫描

在 sonar-project.properties 这个文件的目录下,执行 sonar-scanner 即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
[root@jenkins php-sonar-runner]$ll
total 24
drwxr-xr-x 3 root root 4096 Mar 2 23:30 ./
drwxr-xr-x 4 root root 4096 Jul 25 2016 ../
-rw-r--r-- 1 root root 453 Jul 25 2016 README.md
-rw-r--r-- 1 root root 331 Jul 25 2016 sonar-project.properties
drwxr-xr-x 2 root root 4096 Jul 25 2016 src/ # 代码
-rw-r--r-- 1 root root 272 Jul 25 2016 validation.txt
[root@jenkins php-sonar-runner]$
[root@jenkins php-sonar-runner]$/usr/local/sonar-scanner/bin/sonar-scanner # 测试
INFO: Scanner configuration file: /usr/local/sonar-scanner/conf/sonar-scanner.properties
INFO: Project root configuration file: /usr/local/src/sonar-examples-master/projects/languages/php/php-sonar-runner/sonar-project.properties
INFO: SonarScanner 4.6.0.2311
INFO: Java 11.0.10 Oracle Corporation (64-bit)
INFO: Linux 4.15.0-136-generic amd64
INFO: User cache: /root/.sonar/cache
INFO: Scanner configuration file: /usr/local/sonar-scanner/conf/sonar-scanner.properties
INFO: Project root configuration file: /usr/local/src/sonar-examples-master/projects/languages/php/php-sonar-runner/sonar-project.properties
INFO: Analyzing on SonarQube server 7.9.5
INFO: Default locale: "en_US", source code encoding: "UTF-8"
INFO: Load global settings
INFO: Load global settings (done) | time=225ms
INFO: Server id: 3B6AA649-AXfye5RyEWrAjeeRmPxd
INFO: User cache: /root/.sonar/cache
INFO: Load/download plugins
INFO: Load plugins index
INFO: Load plugins index (done) | time=126ms
INFO: Plugin [l10nzh] defines 'l10nen' as base plugin. This metadata can be removed from manifest of l10n plugins since version 5.2.
INFO: Load/download plugins (done) | time=3633ms
INFO: Process project properties
INFO: Execute project builders
INFO: Execute project builders (done) | time=18ms
INFO: Project key: org.sonarqube:php-simple-sq-scanner
INFO: Base dir: /usr/local/src/sonar-examples-master/projects/languages/php/php-sonar-runner
INFO: Working dir: /usr/local/src/sonar-examples-master/projects/languages/php/php-sonar-runner/.scannerwork
INFO: Load project settings for component key: 'org.sonarqube:php-simple-sq-scanner'
INFO: Load quality profiles
INFO: Load quality profiles (done) | time=293ms
INFO: Load active rules
INFO: Load active rules (done) | time=3061ms
WARN: SCM provider autodetection failed. Please use "sonar.scm.provider" to define SCM of your project, or disable the SCM Sensor in the project settings.
INFO: Indexing files...
INFO: Project configuration:
INFO: Load project repositories
INFO: Load project repositories (done) | time=19ms
INFO: 1 file indexed
INFO: Quality profile for php: Sonar way
INFO: ------------- Run sensors on module PHP :: Simple Project :: SonarQube Scanner
INFO: Load metrics repository
INFO: Load metrics repository (done) | time=134ms
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by net.sf.cglib.core.ReflectUtils$1 (file:/root/.sonar/cache/866bb1adbf016ea515620f1aaa15ec53/sonar-javascript-plugin.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of net.sf.cglib.core.ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
INFO: Sensor JaCoCo XML Report Importer [jacoco]
INFO: Sensor JaCoCo XML Report Importer [jacoco] (done) | time=12ms
INFO: Sensor JavaXmlSensor [java]
INFO: Sensor JavaXmlSensor [java] (done) | time=7ms
INFO: Sensor HTML [web]
INFO: Sensor HTML [web] (done) | time=144ms
INFO: Sensor PHP sensor [php]
INFO: 1 source files to be analyzed
INFO: 1/1 source files have been analyzed
INFO: No PHPUnit test report provided (see 'sonar.php.tests.reportPath' property)
INFO: No PHPUnit coverage reports provided (see 'sonar.php.coverage.reportPaths' property)
INFO: Sensor PHP sensor [php] (done) | time=1652ms
INFO: Sensor Analyzer for "php.ini" files [php]
INFO: Sensor Analyzer for "php.ini" files [php] (done) | time=26ms
INFO: ------------- Run sensors on project
INFO: Sensor Zero Coverage Sensor
INFO: Sensor Zero Coverage Sensor (done) | time=21ms
INFO: No SCM system was detected. You can use the 'sonar.scm.provider' property to explicitly specify it.
INFO: Calculating CPD for 1 file
INFO: CPD calculation finished
INFO: Analysis report generated in 189ms, dir size=83 KB
INFO: Analysis report compressed in 17ms, zip size=14 KB
INFO: Analysis report uploaded in 1437ms
INFO: ANALYSIS SUCCESSFUL, you can browse http://10.0.1.102:9000/dashboard?id=org.sonarqube%3Aphp-simple-sq-scanner
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://10.0.1.102:9000/api/ce/task?id=AXfzlFbUEMwg_dNR3M3w
INFO: Analysis total time: 13.302 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 21.257s
INFO: Final Memory: 8M/40M
INFO: ------------------------------------------------------------------------
[root@jenkins php-sonar-runner]$

web 看测试结果:

jenkins 执行代码扫描

上面是命令行执行 sonar-scanner 命令进行测试,可以结合 jenkins 进行测试,无非就是将命令写到脚本里,让jenkins 自动执行

官方网站: https://jenkins.io/zh/

Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建、部署、自动化, 满足任何项目的需要。

部署jenkins

Jenkins 支持各种运行方式,可通过系统包、Docker 或者通过一个独立的 Java 程序

安装 JDK

Jenkins 基于 JAVA 实现,安装 Jenkins 前需要先安装 JDK

1
2
3
4
[root@jenkins ~]$java -version
java version "1.8.0_271"
Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)

安装 jenkins

1
2
3
4
5
$wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/debian-stable/jenkins_2.263.4_all.deb	# 清华源下载dep包
[root@jenkins src]$apt install daemon # 依赖的包,如果没有,会报错,所以提前装上
[root@jenkins src]$ln -s /usr/local/jdk/bin/java /usr/bin/java # Jenkins只会在/bin:/usr/bin:/sbin:/usr/sbin找java,所以设置$PATH不好使,得做个软连接

[root@jenkins src]$dpkg -i jenkins_2.263.4_all.deb # 安装

主要文件:

1
2
3
4
5
6
7
/etc/default/jenkins
/etc/init.d/jenkins
/etc/logrotate.d/jenkins
/usr/share/jenkins/jenkins.war # 实际上就是启动这个war包
/var/cache/jenkins/
/var/lib/jenkins/
/var/log/jenkins/

修改 jenkins 服务的用户

默认jenkins服务使用 jenkins 帐号启动,将文件复制到生产服务器可能会遇到权限问题,需要先su到对应的用户,这里学习环境为了方便,修改为root用户,注意:工作中还是使用 jenkins 普通用户

1
2
3
4
5
[root@jenkins src]$vim /etc/default/jenkins 
#JENKINS_USER=$NAME
#JENKINS_GROUP=$GROUP
JENKINS_USER=root # 直接修改为root,不要修改$NAME变量
JENKINS_GROUP=root

访问jenkins 页面

创建管理员用户

先创建用户,然后使用刚创建的用户登录

安装插件

Jenkins 是完全插件化的服务,我们想实现什么功能,不是改配置文件,而是下载插件

修改更新源为国内清华源:

1
2
3
4
5
6
7
8
9
[root@jenkins src]$cat /var/lib/jenkins/hudson.model.UpdateCenter.xml
<?xml version='1.1' encoding='UTF-8'?>
<sites>
<site>
<id>default</id>
<url>https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json</url>
</site>
</sites>
[root@jenkins src]$systemctl restart jenkins.service

有以下几种安装插件的方式:

  • 在线安装:官网,也是默认的方式,比较慢

  • 在线安装:清华大学镜像源,sed或者编辑器把 update-center.json 中的Jenkins网址替换为清华源

    1
    2
    3
    4
    # 将:
    https://updates.jenkins.io/download/plugins/warnings/5.0.1/warnings.hpi
    # 替换为:
    https://mirrors-i.tuna.tsinghua.edu.cn/jenkins/plugins/warnings/5.0.1/warnings.hpi
  • 离线安装:手动下载插件,然后放到 /var/lib/jenkins/plugins/,重启 Jenkins 即可

  • 通过web界面安装

搜索需要 gitlab(和gitlab相连)和 Blue Ocean(显示信息更加好看)的相关插件并安装

配置 jenkins 权限管理

默认jenkins用户可以执行所有操作,为了更好的分层控制,可以实现基于角色的权限管理,先创建角色和用户,给角色授权,然后把用户管理到角色

安装插件

安装插件:Role-based Authorization Strategy

如果直接下载失败,可以直接清华源下载,将插件放在 /var/lib/jenkins/plugins 目录下

创建新用户

新建 xiaoming 和 xiaogang 两个用户:

更改认证方式

新建任务

通常选择“构建一个自由风格的软件项目”,新建四个任务:test1-job1、test1-job2、test2-job1、test2-job2

创建角色并对角色分配权限

  1. 创建全局角色
    创建全局读角色,只有读权限

  2. 创建 item 角色
    创建两个 item 角色,test1-role、test2-role,通过正则匹配分配任务

    ![](https://img.lujinkai.cn/blog/ljk/1614438723442.png

将用户关联到角色

测试普通用户登录

xiaogang 用户只能看到 test1.* 匹配的项目:test1-job1、test1-job2

xiaoming 用户只能看到 test2.*匹配的项目:test2-job1、test2-job2

jenkins 邮箱配置

邮件发送到组邮件地址,组邮件会转发到组内所有人

配置jenkins到gitlab非交互式拉取代码

需要配置 ssh key (公钥)和 凭据(私钥)

配置 ssh key

实现 jenkins 服务器到 gitlab 服务器的基于密钥的验证,可以让 jenkins 连接到 gitlab 执行操作

  1. 在 jenkins 服务上生成 ssh key
  2. 在 gitlab 服务器上添加上面生成的 ssh key
  3. 在 jenkins 服务器上测试 ssh key

配置凭据

凭据就是私钥,clone项目的时候,可选择不同的凭据(私钥),只要他在gitlab上配置了key(公钥),如果不指定,就以当前用户的私钥作为凭据去clone项目

管理凭据:系统管理 -> 安全 -> Manage Credentials

构建触发器

构建触发器(webhook),有的人称为钩子,实际上是一个HTTP回调,其用于在开发人员向 gitlab 提交代码后能够触发 jenkins 自动执行代码构建操作

以下为新建一个开发分支,只有在开发人员向开发(develop)分支提交代码的时候才会触发代码构建,而向主分支提交的代码不会自动构建,需要运维人员手动部署代码到生产环境

生产中千万不要用,测试一般也不用,都是由开发登陆自己的账号,只能看到自己的job,然后开发自己手动部署

项目关联

用于多个 job 相互关联,需要串行执行多个 job 的场景,不过这个操作基本不用

例如:克隆代码、编译代码、停止tomcat、部署代码、启动tomcat 这些操作使用不同的job执行,这些job需要串行执行

视图

job 太多需要分类

视图可用于归档 job 进行分组显示,比如将一个业务的 job 放在一个视图显示,最常用的是列表视图

jenkins 分布式

在众多Job的场景下,单台jenkins master同时执行代码clone、编译、打包及构建,其性能可能会出现瓶颈从而会影响代码部署效率,影响jenkins官方提供了jenkins分布式构建,将众多job分散运行到不同的jenkins slave节点,大幅提高并行job的处理能力

配置slave节点环境

slave节点需要配置与master一样的基础运行环境,另外也要创建与master相同的数据目录,因为脚本中调用的路径只有相对于master的一个路径,此路径在master与各node节点必须保持一致

1
2
3
4
5
6
7
8
9
10
# 配置java环境
[root@jenkins-slave1 ~]$java -version
java version "1.8.0_271"
Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)

[root@jenkins-slave1 ~]$ln -s /usr/local/jdk/bin/java /usr/bin/java

# 创建数据目录
[root@jenkins-slave1 ~]$mkdir -p /var/lib/jenkins

添加slave节点

可以限制项目只能在指定的节点中执行:

流水线 pipline

流水线 pipline 是 Jenkins 中的头等公民,官方介绍;https://www.jenkins.io/zh/doc/book/pipeline/

本质上,Jenkins 是一个自动化引擎,它支持许多自动模式。 流水线向Jenkins中添加了一组强大的工具, 支持用例 简单的持续集成到全面的CD流水线。通过对一系列的相关任务进行建模, 用户可以利用流水线的很多特性:

  • 代码:流水线是在代码中实现的,通常会检查到源代码控制,使团队有编辑,审查和迭代他们的交付流水线的能力
  • 可持续性:jenkins的重启或者中断后不影响已经执行的Pipline Job
  • 支持暂停:pipline可以选择停止并等待人工输入或批准后再继续执行
  • 可扩展:通过groovy的编程更容易的扩展插件
  • 并行执行:通过groovy脚本可以实现step,stage间的并行执行,和更复杂的相互依赖关系

流水线概念

流水线 pipeline

流水线是用户定义的一个CD流水线模型 。流水线的代码定义了整个的构建过程, 他通常包括构建, 测试和交付应用程序的阶段

节点 node

每个 node 都是一个 jenkins 节点,可以是 jenkins master 也可以是 jenkins agent,node 是执行 step 的具体服务器

阶段 stage

一个 pipline 可以划分为若干个 stage,每个 stage 都是一个操作,比如 clone 代码、代码编译、代码测试和代码部署,阶段是一个逻辑分组,可以跨多个 node 执行

步骤 step

step 是 jenkins pipline 最基本的操作单元,从在服务器创建目录到构建容器镜像,由各类 Jenkins 插件提供实现,例如: sh “make”

流水线语法概述

对 Jenkins 流水线的定义被写在一个文本文件中: Jenkinsfile,该文件可以被提交到项目的源代码的控制仓库。 这是”流水线即代码”的基础;将CD 流水线作为应用程序的一部分,像其他代码一样进行版本化和审查。

Jenkinsfile 能使用两种语法进行编写,声明式和脚本化。

声明式和脚本化的流水线从根本上是不同的。 声明式流水线的是 Jenkins 流水线更近的特性

声明式流水线基础

在声明式流水线语法中, pipeline 块定义了整个流水线中完成的所有的工作。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'make'
}
}
stage('Test'){
steps {
sh 'make check'
junit 'reports/**/*.xml'
}
}
stage('Deploy') {
steps {
sh 'make publish'
}
}
}
}
  • pipeline 是声明式流水线的一种特定语法,他定义了包含执行整个流水线的所有内容和指令的 “block” 。
  • agent是声明式流水线的一种特定语法,它指示 Jenkins 为整个流水线分配一个执行器 (在节点上)和工作区。
  • stage 是一个描述 stage of this Pipeline的语法块。在 Pipeline syntax 页面阅读更多有关声明式流水线语法的stage块的信息。如 above所述, 在脚本化流水线语法中,stage 块是可选的。
  • steps 是声明式流水线的一种特定语法,它描述了在这个 stage 中要运行的步骤。
  • sh 是一个执行给定的shell命令的流水线 step (由 Pipeline: Nodes and Processes plugin提供) 。
  • junit 是另一个聚合测试报告的流水线 step (由 JUnit plugin提供)。
  • node 是脚本化流水线的一种特定语法,它指示 Jenkins 在任何可用的代理/节点上执行流水线 (和包含在其中的任何阶段)这实际上等效于 声明式流水线特定语法的agent

脚本化流水线基础

pipline 语法

官方文档:https://www.jenkins.io/zh/doc/book/pipeline/syntax/

pipline job

创建pipline job

测试简单pipline job运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
node {
stage('clone 代码') {
echo '代码 clone'
}
stage('代码构建') {
echo '代码构建'
}
stage('代码测试') {
echo '代码测试'
}
stage('代码部署') {
echo '代码部署'
}
}

立即构建,查看输出信息:

自动生成拉取代码的pipline脚本

案例

说明

1
2
3
4
5
6
master分支:稳定的分支
develop分支:开发分支

lujinkai:开发人员分支
xiaoming:开发人员分支
...

master分支是上线的代码,develop是开发中的代码,lujinkai、xiaoming等是开发人员分支,开发在自己的分支里面写代码,然后下班前提交、合并到develop分支,等项目开发、测试完,最后再合并到master分支,然后上线

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@kafka2 testproject]$git branch		# 查看本地分支
* master # 分支前标 * 表示当前处于的分支

[root@kafka2 testproject]$git branch -a # 查看所有分支
* master
remotes/origin/HEAD -> origin/master
remotes/origin/ludongsheng
remotes/origin/master

git status # 查看工作区的状态
git branch test # 创建test分支
git merge test # 将test分支合并到当前分支
git log # 查看操作日志
git reflog # 获取每次提交的ID,可以使用--hard根据提交的ID进行版本回退

vim .gitignore # 定义忽略文件,即不放在仓库的文件

git reset --hard HEAD^^ # git版本回滚, HEAD为当前版本,加一个^为上一个,^^为上上一个版本

git reset --hard 5ae4b06 # 回退到指定id的版本

git checkout -b develop # 创建并切换到一个新分支
git checkout develop # 切换分支

git clone -b 分支名 仓库地址 # clone指定分支的代码

流程

  1. 在 gitlab 创建个人分支 lujinkai

  2. 克隆 master 分支到本地

    1
    [root@dev ~]$git clone git@gitlab.ljk.local:testgroup/testproject.git
  3. 切换到自己分支

    1
    [root@dev ~]$git checkout lujinkai
  4. 将develop分支拉下来和个人分支合并

    1
    2
    3
    4
    [root@dev ~]$git pull origin develop

    # git pull <远程主机名> <远程分支名>:<本地分支名>
    # 如果与当前分支合并,则冒号后面的部分可以省略

    以上命令是把远程分支develop拉下来,然后合并到当前分支lujinkai,或者可以拆分成以下步骤:

    1
    2
    3
    4
    git checkout develop			# 切换到分支develop
    git pull origin develop # 远程develop拉下来和本地develop合并
    git checkout lujinkai # 切换到分支lujinkai
    git merge develop --no-commit # 将本地分支develop和当前分支lujinkai合并
  5. 开发代码

  6. 下班了,需要提交代码,但是在提交之前最好再执行一遍上一步,因为在你写代码的过程中,develop分支可能有其他人提交

    1
    [root@dev ~]$git pull origin develop
  7. 添加文件到本地缓存区

    1
    [root@dev ~]$git add .		# . 表示当前目录下的所有文件
  8. 提交内容到本地分支上

    1
    git commit -m "注释, 提交说明"
  9. 上传本地分支到远程分支

    1
    2
    3
    4
    git push

    # 默认提交到本地分支对应的远程分支,或者可以显式指定
    git push origin lujinkai

之后每天 3 - 9 步骤走一遍

DevOps

DevOps 是Development和Operations的组合,也就是开发和运维的简写

什么是持续集成(CI-Continuous integration)

持续集成是指多名开发者在开发不同功能代码的过程当中,可以频繁的将代码行合并到一起并切相互不影响工作

什么是持续部署(CD-continuous deployment)

是基于某种工具或平台实现代码自动化的构建、测试和部署到线上环境以实现交付高质量的产品,持续部署在某种程度上代表了一个开发团队的更新迭代速率

什么是持续交付(Continuous Delivery)

持续交付是在持续部署的基础之上,将产品交付到线上环境,因此持续交付是产品价值的一种交付,是产品价值的一种盈利的实现

GitLab

GitLab 和 GitHub一样属于第三方基于Git开发的作品,免费且开源,与Github类似,可以注册用户,任意提交你的代码,添加SSHKey等等。不同的是,GitLab是可以部署到自己的服务器上,简单来说可把 GitLab 看作个人版的GitHub

Git在每个用户都有一个完整的服务器,然后在有一个中央服务器,用户可以先将代码提交到本 地,没有网络也可以先提交到本地,然后在有网络的时候再提交到中央服务器,这样就大大方便了开发者,而相比CVS和SVN都是集中式的版本控制系统,工作的时候需要先从中央服务器获 取最新的代码,改完之后需要提交,如果是一个比较大的文件则需要足够快的网络才能快速提交完成,而使用分布式的版本控制系统,每个用户都是一个完整的版本库,即使没有中央服务器也可以提交代码或者回滚,最终再把改好的代码提交至中央服务器进行合并即可

SVN

每次提交的文件都单独保存, 即按照文件的提交时间区分不同的版本, 保存至不同的逻辑存储区域,后期恢复时候直接基于之前版本恢复。


Git

Gitlab 与 SVN的数据保存方式不一样,gitlab 虽然 也会在内部 对数据进行逻辑划分保存,但是当后期提交的数据如和之前交的数据没有变化,其就直接 快照之前的文件 ,而不是再将文件重新上传一份再保存一遍,这样既节省 了空间又加快了代码提交速度 。

git 缓存区与工作区等概念

  • 工作区 :clone 的代码或者开发自己编写代码文件所在 的目录 ,通常是代码所在的一 个服务的目录名称
  • 暂存区 :用于存储在工作区中对代码进行修改后的文件所保存的地方,使用 git add 添加
  • 本地仓库: 用于提交存储在工作区和暂存区中改过的文件地方,使 git commit 提交
  • 远程仓库 :多个开发人员共同协作提交代码的仓库,即 gitlab 服务器

Gitlab部署与使用

测试环境:内存4G以上
生产环境:建议CPU2C,内存8G,磁盘10G以上配置,和用户数有关

清华源 centos7:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/
清华源 ubuntu18.04:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu/pool/bionic/main/g/gitlab-ce/

安装

1
2
3
4
[root@gitlab src]$dpkg -i gitlab-ce_13.8.4-ce.0_amd64.deb	# 得等一会
...
configuration in /etc/gitlab/gitlab.rb file. # 配置文件
...

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 需要配置gitlab服务器地址和邮件地址
[root@gitlab src]$vim /etc/gitlab/gitlab.rb
external_url 'http://gitlab.ljk.local' # 修改此行
# 增加下面行,可选邮件通知设置
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "441757636@qq.com"
gitlab_rails['smtp_password'] = "jwopcvnpcawdcbbg"
gitlab_rails['smtp_domain'] = "qq.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
gitlab_rails['gitlab_email_from'] = "441757636@qq.com"

gitlab 相关目录:

1
2
3
4
5
/etc/gitlab     	#配置文件目录
/run/gitlab #运行pid目录
/opt/gitlab #安装目录
/var/opt/gitlab #数据目录
/var/log/gitlab #日志目录

初始化服务

修改完配置文件要执行此操作

1
[root@gitlab src]$gitlab-ctl reconfigure

常用命令:

1
2
3
4
5
6
7
8
9
10
gitlab-rails          #用于启动控制台进行特殊操作,如修改管理员密码、打开数据库控制台( gitlab-rails dbconsole)等
gitlab-psql #数据库命令行
gitlab-rake #数据备份恢复等数据操作

gitlab-ctl #客户端命令行操作行
gitlab-ctl stop #停止gitlab
gitlab-ctl start #启动gitlab
gitlab-ctl restar #重启gitlab
gitlab-ctl status #查看组件运行状态
gitlab-ctl tail nginx #查看某个组件的日志

gitlab web 界面

username:root
注意,使用域名访问需要做hosts

关闭账号注册

默认情况下可以直接注册账号,一般都关闭此功能,由管理员统一注册用户

修改邮箱地址

新添加的邮箱不是默认的通知邮箱,下面是设置新邮箱为默认邮箱

设置完后,需要重新登录才能生效,然后可以把之前的默认邮箱删除

创建gitlab账户

创建成功后,需要查看邮件,在邮件链接中重置密码

创建组

使用管理员root创建组,一个组里面可以有多个项目分支,可以将开发添加到组里,再进行设置权限,不同的组对应公司不同的开发项目或者服务模块,不同的组中添加不同的开发人员帐号,即可实现对开发设置权限的管理

管理员创建项目

有三种方式:创建空项目、使用模板、导入项目

将用户添加到组

更多权限:https://docs.gitlab.com/ee/user/permissions.html

gitlab仓库developer权限无法push

默认develop权限无法merge和push到master分支的,可以修改:

在这里,也可以设置也可以保护其他分支

在项目中新建测试页面

使用 陆东生 用户登录,新建分支,继承自master:

git客户端测试clone项目

  1. ssh认证

    1
    2
    ssh-keygen -t rsa
    cat ~/.ssh/id_rsa.pub # 将公钥复制到给gitlab
  2. clone

    1
    git clone git@gitlab.ljk.local:testgroup/testproject.git

git 常用命令

运维常用:git pullgit clonegit reset

gitlab数据备份恢复

  1. 备份前必须先停止gitlab两个服务

    1
    2
    [root@gitlab ~]$gitlab-ctl stop unicorn
    [root@gitlab ~]$gitlab-ctl stop sidekiq
  2. 备份数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@gitlab ~]$gitlab-rake gitlab:backup:create
    ...
    Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data
    and are not included in this backup. You will need these files to restore a backup.
    Please back them up manually.

    # 以上warning表示gitlab.rb和gitlab-secrets.json两个文件包含敏感信息。未被备份到备份文件中。需要手动备份,这两个文件位于 /etc/gitlab

    [root@gitlab ~]$gitlab-ctl start # 备份完成后启动gitlab

    备份数据位于 /var/opt/gitlab/backups/

    1
    2
    [root@gitlab ~]$ls /var/opt/gitlab/backups/
    1614392268_2021_02_27_13.8.4_gitlab_backup.tar
  3. 查看要恢复的文件

    1
    2
    3
    /var/opt/gitlab/backups/   # Gitlab数据备份目录,需要使用命令备份的
    /var/opt/gitlab/nginx/conf # nginx配置文件
    /etc/gitlab/gitlab.rb # gitlab配置文件
  4. 删除项目和用户信息

  5. 执行恢复

    1
    2
    3
    4
    5
    # 恢复前先停止两个服务
    [root@gitlab ~]$gitlab-ctl stop unicorn
    [root@gitlab ~]$gitlab-ctl stop sidekiq
    # 恢复时指定备份文件的时间部分,不需要指定文件的全名
    [root@gitlab ~]$gitlab-rake gitlab:backup:restore BACKUP=备份文件名
  6. 恢复后再将之前停止的两个服务启动

    1
    gitlab-ctl start

gitlab汉化

虽然不推荐,但是有需求,基于第三方开发爱好者实现

汉化包地址: https://gitlab.com/xhang/gitlab

1
2
3
4
5
6
7
8
9
10
git clone https://gitlab.com/xhang/gitlab.git
head -1 /opt/gitlab/version-manifest.txt # 查看当前gitlab版本
cd gitlab
git diff v11.9.8 v11.9.8-zh
git diff v11.9.8 v11.9.8-zh >/root/v11.9.8-zh.diff
gitlab-ctl stop
patch -f -d /opt/gitlab/embedded/service/gitlab-rails -p1 </root/v11.9.8-zh.diff
gitlab-ctl reconfigure
gitlab-ctl start
gitlab-ctl status

常见的代码部署方式

  • 蓝绿部署
  • 金丝雀发布
  • 滚动发布
  • A/B测试

Nexus 是一个强大的 Maven 仓库管理器,它极大地简化了自己内部仓库的维护和外部仓库的访问

官方下载:https://help.sonatype.com/repomanager3/download/download-archives---repository-manager-3

部署Nexus

  1. 下载、解压、创建用户

    1
    2
    3
    4
    5
    6
    7
    8
    [root@nexus src]$useradd -r -s /sbin/nologin nexus		# 创建nexus用户
    [root@nexus src]$tar zxf nexus-3.29.2-02-unix.tar.gz
    [root@nexus src]$mv nexus-3.29.2-02 /usr/local/nexus
    [root@nexus src]$mv sonatype-work/ /usr/local/
    [root@nexus src]$cd /usr/local/
    [root@nexus local]$chown -R nexus:nexus ./nexus/
    [root@nexus local]$chown -R nexus:nexus ./sonatype-work/
    [root@nexus local]$echo 'nexus - nofile 65536' >> /etc/security/limits.conf
  2. Service启动文件,官方提供

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [root@nexus ~]$cat /lib/systemd/system/nexus.service 
    [Unit]
    Description=nexus service
    After=network.target

    [Service]
    Type=forking
    LimitNOFILE=65536
    ExecStart=/usr/local/nexus/bin/nexus start
    ExecStop=/usr/local/nexus/bin/nexus stop
    User=nexus
    Restart=on-abort
    TimeoutSec=600

    [Install]
    WantedBy=multi-user.target

    [root@nexus ~]$systemctl start nexus.service # 需要几分钟时间启动
  3. 设置向导:

  4. 验证默认仓库

    • Hosted:本地仓库,通常我们会部署自己的构件到这一类型的仓库,比如公司的第三方库
    • Proxy:代理仓库,它们被用来代理远程的公共仓库,如 maven 中央仓库(官方仓库)
    • Group:仓库组,用来合并多个 hosted/proxy 仓库,当你的项目希望在多个repository使用资源时就不需要多次引用了,只需要引用一个 group 即可

构建私有 yum 仓库

  1. 配置仓库的数据目录

  2. 仓库配置,以 zabbix 为例

  3. centos 7.x 配置 yum 仓库

    1
    2
    3
    4
    5
    6
    7
    [root@c71 ~]$vim /etc/yum.repos.d/zabbix.repo
    [root@c71 ~]$cat /etc/yum.repos.d/zabbix.repo
    [zabbix-nexus]
    name=zabbix
    baseurl=http://10.0.1.103:8081/repository/zabbix-proxy/
    enabled=1
    gpgcheck=0
  4. 测试:

  5. 下载过的包会缓存下来

数据备份

Nexus 中普通数据信息和元数据是分开存储的,普通数据是保存在 blob 中,而元数据保存在数据库中,所以在备份的时候必须同时进行备份普通数据和元数据,才能在后期恢复数据的时候保证数据的最终完整性

数据量太大,而且不影响用户业务,数据备份没什么意义

默认 tcp

端口      服务              备注
20 FTP 源连接,20或更高TCP端口1024以上
21 FTP 侦听端口
69 / udp FTP
22 ssh
23 telnet
25 smtp 不开启 tls 验证
465 smtp 开启 tls 验证
53 dns
69 tftp
161 snmp
8080 vue、tomcat
8443 tomcat
80 http
443 https
953 rndc 利用rndc工具可以实现管理DNS功能
6443 k8s api server
3306 mysql
6379 redis
8005 tomcat tomcat 默认监听8005端口,这是一个后门,可通过这个端口关闭 tomcat 服务
1100 JMX
10050 zabbix agent
10051 zabbix server
5672 RabbitMQ 消费者访问的端口
15672 RabbitMQ web 管理端口
25672 RabbitMQ 集群状态通信端口
2181 Zookeeper Zookeeper会监听这个端口,接受客户端的访问请求
2888 Zookeeper LF数据同步端口
3888 Zookeeper LF选举端口
9092 kafka
2049 nfsd
873 rsync
67 DHCP Server
68 DHCP Client(ipv4)
546 DHCP Client(ipv6)

http://activemq.apache.org/

ActiveMQ 是一种开源的基于 JMS(Java Message Servie)规范的一种消息中间件的实现,采用 Java 开发,设计目标是提供标准的、面向消息的、能够跨越多语言和多系统的应用集成消息通信中间件

http://kafka.apache.org/

阿里云兼容 kafka 消息队列:https://www.aliyun.com/product/ons

Kafka 是一种高吞吐量的分布式发布订阅消息系统,其具备分布式功能、并可以结合 zookeeper 可以实现动态扩容,用于构建实时数据管道和流应用程序
它具有水平可伸缩性、容错性、快速性

常用消息队列对比:

kafka 优势

kafka为什么性能高?

  1. 顺序写入,kafka数据写入磁盘,不是保存在内存,默认保存168小时
  • kafka通过O(1)的磁盘数据结构提供消息的持久化,即使数以TB的消息存储也能够保持长时间的稳定性能
    • O(1)是最低的时间复杂度,哈希算法就是典型的 O(1) 时间复杂度,无论数据规模多大,都可以在一次计算后找到目标
  • 高吞吐量,即使是非常普通的硬件 Kafka 也可以支持每秒数百万的消息
  • 支持通过 Kafka 服务器分区消息,可以将数据保存到不同的服务器
  • 支持 Hadoop 并行数据加载

kafka 角色

  • broker:中文直译“中间人”,实际就是消息代理,是生产者和消费者中间代理保存消息的中转站,集群中每个 kafka 的 broker 都有唯一的 id,由 server.properties 中的 broker.id 指定,可以把每个kafka节点抽象的看成是一个broker,也可以把整个kafka集群抽象的看成是一个broker

  • topic:话题,生产者和消费者监听同一个topic,生产者往里写消息,消费者从里面读消息

  • partition:分区,也叫分片,物理上的概念,每个分区对应一个文件夹,topic 可以将其消息分片储存,提高性能,然后每个分片做多个副本,保证高可用

    注意:分片数量不要超过kafka节点数量;副本数量也不要超过kafka节点数量;

    • leader:分片副本的角色,主
    • follower:分片副本的角色,从

    对于一个分片,其副本只有一个是leader,其他的都是follower,leader不能和follower在同一个节点,这样就失去了高可用的意义

    高可用:当一个节点故障,其他的follower会选举出一个作为leader

    1
    2
    3
    4
    上图中 topic1 分了两片:topic1-part1、topic1-part2;
    上图中 topic2 只有一片:topic2-part1

    上图中 topic1 和 topic2 的分片都做了三个副本:topicX-part1、topicX-part2、topicX-part3
  • Producer:生产者,负责发布消息到 Kafka broker

  • Consumer:消费者,每个 consumer 属于一个特定的 consuer group(若不指定 group name 则属于默认 group),使用 consumer high level API 时,同一 topic 的一条消息只能被同一个 consumer group内的一个 consumer 消费,但多个 consumer group 可同时消费这一消息

kafka 和 zookeeper 的关系:

kafka 自身无法实现集群和高可用,kafka 依赖 zookeeper 实现集群和高可用

zookeeper 和 kafka 都可以存储数据,zookeeper储存单个数据在1MB以内,只用来保存服务的元数据,不保存业务信息

  1. Broker 依赖于 Zookeeper,每个 Broker 的 id 和 Topic、Partition 这些元数据信息都会写入 Zookeeper 的 ZNode 节点中
  2. Consumer 依赖于 Zookeeper,Consumer 在消费消息时,每消费完一条消息,会将产生的 offset 保存到 Zookeeper 中,下次消费在当前 offset 往后继续消费。注意:kafka0.9 之前 Consumer 的 offset 存储在 Zookeeper 中,kafka0,9 以后 offset存储在本地
  3. Partition 依赖于 Zookeeper,Partition 完成 Replication 备份后,选举出一个Leader,这个是依托于 Zookeeper 的选举机制实现的

kafka 部署

1
2
3
kakfa1.ljk.cn:10.0.1.101
kakfa2.ljk.cn:10.0.1.102
kakfa3.ljk.cn:10.0.1.103

快速部署:http://kafka.apache.org/quickstart

  1. 安装 zookeeper,这里就不配置集群了,安装单机zookeeper

  2. 安装 kafka

    1
    2
    3
    4
    5
    6
    # kafka 下载页面:http://kafka.apache.org/downloads
    [root@kakfa1 src]$tar -xzf kafka_2.13-2.7.0.tgz
    [root@kakfa1 src]$mv kafka_2.13-2.7.0 /usr/local/kafka
    [root@kakfa1 src]$cd /usr/local/
    [root@kakfa1 local]$scp -r ./kafka/ 10.0.1.102:/usr/local
    [root@kakfa1 local]$scp -r ./kafka/ 10.0.1.103:/usr/local
  3. 配置 kafka

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    [root@kakfa1 ~]$vim /etc/hosts
    ...
    10.0.1.101 kafka1.ljk.cn
    10.0.1.102 kafka2.ljk.cn
    10.0.1.103 kafka3.ljk.cn
    10.0.1.101 zk1.ljk.cn # zookeeper地址域名解析

    [root@kakfa1 local]$vim kafka/config/server.properties
    21 broker.id=1 # 每个 broker 在集群中的唯一标识,正整数
    31 listeners=PLAINTEXT://kafka1.ljk.cn:9092
    60 log.dirs=/usr/local/kafka/kafka-logs # kakfa用于保存数据的目录,所有的消都会存储在该目录当中
    65 num.partitions=1 # 设置创建新topic的默认分区数量
    103 log.retention.hours=168 # 设置kafka中消息保留时间,默认为168小时,即7天
    # 指定连接的zookeeper的地址,zk中存储了broker的元数据信息,如果zk是集群,多个zk地址使用逗号分割,这里为了方便,使用单机zookeeper,推荐使用域名,如果使用ip可能无法启动,不知道为什么
    123 zookeeper.connect=zk1.ljk.cn:2181
    126 zookeeper.connection.timeout.ms=6000 # 设置连接zookeeper的超时时间,默认6s

    [root@kakfa2 local]$vim kafka/config/server.properties
    21 broker.id=2
    31 listeners=PLAINTEXT://10.0.1.102:9092
    60 log.dirs=/usr/local/kafka/kafka-logs
    103 log.retention.hours=168
    123 zookeeper.connect=zk1.ljk.cn:2181
    126 zookeeper.connection.timeout.ms=6000

    [root@kakfa3 local]$vim kafka/config/server.properties
    21 broker.id=3
    31 listeners=PLAINTEXT://10.0.1.103:9092
    60 log.dirs=/usr/local/kafka/kafka-logs
    103 log.retention.hours=168
    123 zookeeper.connect=zk1.ljk.cn:2181
    126 zookeeper.connection.timeout.ms=6000
  4. 启动 kafka

    1
    2
    3
    4
    5
    6
    7
    [root@kakfa1 bin]$pwd
    /usr/local/kafka/bin
    [root@kakfa1 bin]$./kafka-server-start.sh -daemon ../config/server.properties

    [root@kakfa2 bin]$./kafka-server-start.sh -daemon ../config/server.properties

    [root@kakfa3 bin]$./kafka-server-start.sh -daemon ../config/server.properties

测试 kafka 读写数据

http://kafka.apache.org/quickstart

创建 topic

1
2
3
4
5
6
[root@kakfa1 bin]$./kafka-topics.sh --create \
--zookeeper zk1.ljk.cn:2181 \
--partitions 3 \
--replication-factor 3 \
--topic lujinkai
Created topic lujinkai.
  • –create:创建topic
  • –zookeeper:指定zk地址,虽然配置文件中已经指定了,但是命令行还要指定
  • –partitions:指定一个topic包含几个partition,就是对topic分片,分片可以提高性能,但是一般不用分片,保持默认值1就可以,如果分片,也不要超过节点的数量
  • –replication-factor:指定partition的副本数量,kafka实现高可用全靠partition的副本,如果设置3,则一个partition就存储3份,注意不是4份
  • –topic:指定名称

假设集群有4个broker,一个topic有4个partition,每个partition有3个副本。下图是每个broker上的副本分配情况:

验证 topic

1
2
3
4
5
6
7
[root@kakfa1 bin]$./kafka-topics.sh --describe \
--zookeeper zk1.ljk.cn:2181 \
--topic lujinkai
Topic: lujinkai PartitionCount: 3 ReplicationFactor: 3 Configs:
Topic: lujinkai Partition: 0 Leader: 3 Replicas: 3,2,1 Isr: 3,2,1
Topic: lujinkai Partition: 1 Leader: 1 Replicas: 1,3,2 Isr: 1,3,2
Topic: lujinkai Partition: 2 Leader: 2 Replicas: 2,1,3 Isr: 2,1,3

说明:lujinkai 这个 topic 有三个分区分别为 0、1、2,分区 0 的 leader 是 3(broker.id),分区 0 有三个副本,并且状态都为 lsr(ln-sync,表示可以参加选举成为 leader)

获取所有 topic

1
2
[root@kakfa1 bin]$./kafka-topics.sh --list --zookeeper zk1.ljk.cn:2181
lujinkai

测试发送消息

1
2
3
4
5
[root@kakfa1 bin]$./kafka-console-producer.sh --topic lujinkai \
--broker-list kafka1.ljk.cn:9092,kafka2.ljk.cn:9092,kafka3.ljk.cn:9092
>hello
>word
>

测试获取消息

1
2
3
4
5
[root@kafka2 bin]$./kafka-console-consumer.sh --topic lujinkai \
--bootstrap-server kafka1.ljk.cn:9092,kafka2.ljk.cn:9092,kafka3.ljk.cn:9092 \
--from-beginning
hello
word
  • –bootstrap-server:kafak集群的地址,实际只写一个地址也行
  • –from-beginning:从最开始的数据进行消费

删除 topic

1
2
3
4
5
[root@kakfa1 bin]$./kafka-topics.sh --delete \
--topic lujinkai \
--zookeeper zk1.ljk.cn:2181
Topic lujinkai is marked for deletion.
Note: This will have no impact if delete.topic.enable is not set to true.

https://zookeeper.apache.org/

ZooKeeper 是一个分布式服务框架,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:命名服务、状态同步、配置中心、集群管理等

命名服务

命名服务是分布式系统最基本的公共服务之一。在分布式系统中,被命名的实体通常可以是集群中的机器、提供的服务地址或远程对象等,这些我们都可以统称它们为名字(Name),其中较为常见的就是一些分布式服务框架(如 RPC、RMI)中的服务地址列表,通过使用命名服务,客户端应用能够根据指定名字来获取资源的实体、服务地址和提供者的信息等

状态同步

每个节点除了存储数据内容和 node 节点状态信息之外,还存储了已经注册的APP 的状态信息,当有些节点或 APP 不可用,就将当前状态同步给其他服务

配置中心

现在我们大多数应用都是采用的是分布式开发的应用,搭建到不同的服务器上,可以使用 ZooKeeper 来实现配置中心,ZooKeeper 采用的是推拉相结合的方式: 客户端向服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送 Watcher 事件通知,客户端接收到这个消息通知后,需要主动到服务端获取最新的数据

集群管理

所谓集群管理,包括 集群监控集群控制 两部分,前者侧重对集群运行时状态的收集,后者则是对集群进行操作与控制

  • 客户端如果对 ZooKeepe 的一个数据节点注册 Watcher 监听,那么当该数据节点的内容或是其子节点列表发生变更时,ZooKeeper 服务器就会向订阅的客户端发送变更通知
  • 对在 ZooKeeper 上创建的临时节点,一旦客户端与服务器之间的会话失效,该临时节点也就被自动除
1
Watcher(事件监听器):Zookeeper中很重要的特性。Zookeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通知到感兴趣的客户端上去,该机制是 Zookeeper实现分布式协调服务的重要特性

0、生产者启动
1、生产者注册至 zookeeper
2、消费者启动并订阅频道
3、zookeeper 通知消费者事件
4、消费者调用生产者
5、监控中心负责统计和监控服务状态

ZooKeeper 单机安装

ZooKeeper 依赖 Java 环境,要求 JDK1.7 及以上

  1. 配置java环境

    1
    2
    3
    4
    [root@zk1 ~]$java -version
    java version "1.8.0_271"
    Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
    Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)
  2. 部署 ZooKeeper
    官网下载地址:https://archive.apache.org/dist/zookeeper/
    注意,要下载带 bin 的包,不带 bin 的只是源码包,不包含必要的 jar 包

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [root@zk1 src]$tar zxf apache-zookeeper-3.5.9-bin.tar.gz  
    [root@zk1 src]$mv apache-zookeeper-3.5.9-bin
    [root@zk1 src]$mv apache-zookeeper-3.5.9-bin /usr/local/zookeeper
    [root@zk1 src]$cd /usr/local/zookeeper/conf/
    [root@zk1 conf]$cp zoo_sample.cfg zoo.cfg
    [root@zk1 conf]$grep ^[a-Z] ./zoo.cfg
    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=/tmp/zookeeper
    clientPort=2181
    admin.serverPort=8180 # AdminServer监听的端口,默认8080,因为tomcat默认端口也是8080,为了避免冲突,这里修改为8180

    关于AdminServer:https://zookeeper.apache.org/doc/r3.5.0-alpha/zookeeperAdmin.html#sc_adminserver_config

  3. 启动 ZooKeeper

    1
    2
    3
    4
    5
    6
    7
    # zkServer.sh 	用于启动、重启、停止 ZooKeeper
    [root@zk1 bin]$pwd
    /usr/local/zookeeper/bin
    [root@zk1 bin]$./zkServer.sh start
    ZooKeeper JMX enabled by default
    Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
    Starting zookeeper ... STARTED
  4. 验证 Zookeeper 状态

    1
    2
    3
    4
    5
    [root@zk1 bin]$./zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
    Client port found: 2181. Client address: localhost. Client SSL: false.
    Mode: standalone

ZooKeeper 集群简介

集群架构:

集群角色:

Zookeeper 集群部署

整个集群中只要有超过集群数量一半的 zookeeper 工作只正常的,那么整个集群对外就是可用的

1
2
3
zk1.ljk.cn:10.0.1.101
zk2.ljk.cn:10.0.1.102
zk3.ljk.cn:10.0.1.103
  1. 各个节点安装 zookeeper,参考上面单机部署,但是先不要启动

  2. 各个节点创建数据目录

    1
    2
    3
    4
    5
    6
    7
    8
    [root@zk1 ~]$cd /usr/local/zookeeper/
    [root@zk1 zookeeper]$mkdir data

    [root@zk2 ~]$cd /usr/local/zookeeper/
    [root@zk2 zookeeper]$mkdir data

    [root@zk3 ~]$cd /usr/local/zookeeper/
    [root@zk3 zookeeper]$mkdir data
  3. 各个节点配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@zk1 conf]$grep ^[a-Z] ./zoo.cfg
    tickTime=2000 # 心跳检测周期,单位为毫秒
    initLimit=10 # leader与follower初始连接心跳次数,即多少个2000毫秒
    syncLimit=5 # leader与follower连接完成之后,后期检测发送和应答的心跳次数,即该follower在5*2000毫秒内不能与leader进行通信,那么此follower将被视为不可用
    dataDir=/usr/local/zookeeper/data # 自定义的zookeeper保存数据的目录
    clientPort=2181 # 客户端连接Zookeeper服务器的端口,Zookeeper会监听这个端口,接受客户端的访问请求
    maxClientCnxns=128 # 单个客户端IP可以和zookeeper保持的连接数
    autopurge.snapRetainCount=3 # 保存快照的数量,启用后ZooKeeper只保存最新的几个快照,其余的会自动清除,最新快照和相应的事务日志分别保留在dataDir和dataLogDir中,默认值为 3。最小值为 3
    autopurge.purgeInterval=1 # 自动清理日志和快照文件的频率,单位小时,默认0,不开启自动清理
    server.1=10.0.1.101:2888:3888 # server.服务器编号=服务器IP:LF数据同步端口:LF选举端口
    server.2=10.0.1.102:2888:3888 # hostname也可以,只要dns能解析到就行
    server.3=10.0.1.103:2888:3888

    [root@zk1 conf]$scp ./zoo.cfg 10.0.1.102:/usr/local/zookeeper/conf
    [root@zk1 conf]$scp ./zoo.cfg 10.0.1.103:/usr/local/zookeeper/conf
  4. 集群id

    1
    2
    3
    4
    5
    [root@zk1 data]$echo 1 > myid

    [root@zk2 data]$echo 2 > myid

    [root@zk3 data]$echo 3 > myid
  5. 启动 zookeeper

    1
    2
    3
    4
    5
    [root@zk1 bin]$./zkServer.sh start

    [root@zk2 bin]$./zkServer.sh start

    [root@zk3 bin]$./zkServer.sh start
  6. 验证 Zookeeper 状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [root@zk1 bin]$./zkServer.sh status 
    ZooKeeper JMX enabled by default
    Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
    Client port found: 2181. Client address: localhost. Client SSL: false.
    Mode: follower # follower

    [root@zk2 bin]$./zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
    Client port found: 2181. Client address: localhost. Client SSL: false.
    Mode: follower # follower

    [root@zk3 bin]$./zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
    Client port found: 2181. Client address: localhost. Client SSL: false.
    Mode: leader # leader

zookeeper 集群选举过程

节点角色状态:

1
2
3
4
LOOKING   # 寻找 Leader 状态,处于该状态需要进入选举流程
LEADING # 领导者状态,处于该状态的节点说明是角色已经是 Leader
FOLLOWING # 跟随者状态,表示 Leader 已经选举出来,当前节点角色是 follower
OBSERVER # 观察者状态,表明当前节点角色是 observer

选举 ID:

1
2
ZXID	# zookeeper transaction id,每个改变Zookeeper状态的操作都会形成一个对应的zxid
myid # 服务器的唯一标识(SID),通过配置myid文件指定,集群中唯一

zookeeper 数据增删改查

任意一台zookeeper节点进行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[root@zk1 bin]$./zkCli.sh -server 10.0.1.102:2181
...
Welcome to ZooKeeper!
JLine support is enabled
[zk: 10.0.1.102:2181(CONNECTING) 0] help
ZooKeeper -server host:port cmd args
addauth scheme auth
close
config [-c] [-w] [-s]
connect host:port
create [-s] [-e] [-c] [-t ttl] path [data] [acl]
delete [-v version] path
deleteall path
delquota [-n|-b] path
get [-s] [-w] path
getAcl [-s] path
history
listquota path
ls [-s] [-w] [-R] path
ls2 path [watch]
printwatches on|off
quit
reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
redo cmdno
removewatches path [-c|-d|-a] [-l]
rmr path
set [-s] [-v version] path data
setAcl [-s] [-v version] [-R] path acl
setquota -n|-b val path
stat [-w] path
sync path

zookeeper 客户端 ZooInspector

Linux:https://github.com/zzhang5/zooinspector
Windows:https://www.cnblogs.com/weiyiming007/p/11951591.html

  1. 下载、解压、双击 build/zookeeper-dev-ZooInspector.jar
  2. 连接成功

阿里云消息队列:https://www.aliyun.com/product/ons

RabbitMQ 基于 erlang 语言开发,具有高并发优点、支持分布式具有消息确认机制、消息持久化机制,消息可靠性和集群可靠性高,简单易用、运行稳定、跨平台、多语言开源

Broker:接收和分发消息的应用,RabbitMQ Server 就是 Message Broker
Virtual host:出于多租户和安全因素设计的,把 AMQP 的基本组件划分到一个虚拟的分组中,类似于网络中的 namespace 概念,当多个不同的用户使用同一个 RabbitMQ server 提供的服务时,可以划分出多个 vhost,每个用户在自己的 vhost创建 exchange/queue 等
Connection:publisher/consumer 和 broker 之间的 TCP 连接。
Channel:如果每一次访问 RabbitMQ 都建立一个 Connection,在消息量大的时候建立 TCP Connection 的开销将是巨大的,效率也较低。Channel 是在 connection 内部建立的逻辑连接,如果应用程序支持多线程,通常每个 thread 创建单独的channel 进行通讯,AMQP method 包含了 channel id 帮助客户端和 message broker 识别 channel,所以 channel 之间是完全隔离的。Channel 作为轻量级的 Connection 极大减少了操作系统建立 TCP connection 的开销。
Exchange:message 到达 broker 的第一站,根据分发规则,匹配查询表中的 routing key,分发消息到 queue 中去。常用的类型有:direct (point-to-point), topic (publish-subscribe) and fanout (multicast)。
Queue:消息最终被送到这里等待 consumer 取走,先进先出,可以持久化到磁盘节点服务器
Binding:exchange 和 queue 之间的虚拟连接,binding 中可以包含 routing key。Binding 信息被保存到 exchange 中的查询表中,用于 message 的分发依据。

RabbitMQ 中的生产者消费者示例

生产者发送消息到 broker server(RabbitMQ),在 Broker 内部,用户创建Exchange/Queue,通过Binding 规则将两者联系在一起,Exchange 分发消息,根据类型/binding 的不同分发策略有区别,消息最后来到 Queue 中,等待消费者取走

RabbitMQ 单机部署

快速部署示例:https://www.rabbitmq.com/install-debian.html#apt-bintray-quick-start

  1. 主机名解析

    1
    2
    3
    4
    5
    6
    7
    [root@mq1 ~]$hostname
    mq1.ljk.cn
    [root@mq1 ~]$hostname -I
    10.0.1.101
    [root@mq1 ~]$vim /etc/hosts
    ...
    10.0.1.101 mq1.ljk.cn mq1
  2. 时间原因,选择 apt 安装,直接执行以下脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #!/bin/sh

    ## If sudo is not available on the system,
    ## uncomment the line below to install it
    # apt-get install -y sudo

    sudo apt-get update -y

    ## Install prerequisites
    sudo apt-get install curl gnupg -y

    ## Install RabbitMQ signing key
    curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | sudo apt-key add -

    ## Install apt HTTPS transport
    sudo apt-get install apt-transport-https

    $distribution='bionic' # ubuntu18.04
    sudo tee /etc/apt/sources.list.d/bintray.rabbitmq.list <<EOF
    ## 默认安装最新版本的 erlang 23.x,可以指定版本例如:erlang-22.x
    deb https://dl.bintray.com/rabbitmq-erlang/debian $distribution erlang
    ## Installs latest RabbitMQ release
    deb https://dl.bintray.com/rabbitmq/debian $distribution main
    EOF

    ## Update package indices
    sudo apt-get update -y

    ## Install rabbitmq-server and its dependencies
    sudo apt-get install rabbitmq-server -y --fix-missing
  3. 安装成功

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [root@zabbix src]$systemctl status rabbitmq-server.service 
    ● rabbitmq-server.service - RabbitMQ broker
    Loaded: loaded (/lib/systemd/system/rabbitmq-server.service; enabled; vendor preset: enabled)
    Active: active (running) since Sun 2021-02-21 02:41:45 UTC; 1h 26min ago
    Main PID: 5992 (beam.smp)
    Status: "Initialized"
    Tasks: 22 (limit: 2289)
    CGroup: /system.slice/rabbitmq-server.service
    ├─5992 /usr/lib/erlang/erts-11.1.8/bin/beam.smp -W w -MBas ageffcbf -MHas ageffcbf -MBlmbcs 512 -MHlmbcs 512 -MMmcs 30 -P 1048576 -t 5000000 -stbt db -zd
    ├─6013 erl_child_setup 32768
    ├─6039 /usr/lib/erlang/erts-11.1.8/bin/epmd -daemon
    ├─6058 inet_gethost 4
    └─6059 inet_gethost 4
    ...
  4. 插件管理
    https://www.rabbitmq.com/management.html
    开启 web 管理界面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [root@zabbix src]$which rabbitmq-plugins
    /usr/sbin/rabbitmq-plugins
    [root@zabbix src]$rabbitmq-plugins enable rabbitmq_management
    Enabling plugins on node rabbit@mq1:
    rabbitmq_management
    The following plugins have been configured:
    rabbitmq_management
    rabbitmq_management_agent
    rabbitmq_web_dispatch
    Applying plugin configuration to rabbit@mq1...
    The following plugins have been enabled:
    rabbitmq_management
    rabbitmq_management_agent
    rabbitmq_web_dispatch

    started 3 plugins.

    # 5672 消费者访问的 端口
    # 15672 web 管理端口
    # 25672 集群状态通信端口
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@mq1 ~]$rabbitmqctl list_users
    Listing users ...
    user tags
    guest [administrator] # guest是初始化的用户,账号密码都是guest,但是只能使用localhost访问

    [root@mq1 ~]$rabbitmqctl add_user ljk 123456 # 添加用户
    Adding user "ljk" ...
    Done. Don't forget to grant the user permissions to some virtual hosts! See 'rabbitmqctl help set_permissions' to learn more.
    [root@mq1 ~]$rabbitmqctl set_user_tags ljk administrator # 用户授权
    Setting tags for user "ljk" to [administrator] ...
    [root@mq1 ~]$rabbitmqctl list_users
    Listing users ...
    user tags
    ljk [administrator] # 授权成功
    guest [administrator]

    使用账号 ljk,密码 123456,成功登录web管理界面:

    登录之后,我们很少进行更改,主要是查看rabbitmq的运行状态

RabbitMQ 集群部署

  • 普通模式:创建好 RabbitMQ 集群之后的默认模式
    所有的mq节点保存相同的元数据,即消息队列,但队列里的数据仅保存一份,消费者从A节点拉取消息,如果消息在B节点,那么B会将消息发送给A节点,然后消费者就能拉取到数据了
    缺点:单点失败
  • 镜像模式:把需要的队列做成镜像队列
    在普通模式的基础上,增加一些镜像策略,消息实体会主动在镜像节点间同步,而不是在 consumer 取数据时临时拉取,解决了单点失败的问题,但是性能下降,增加集群内部网络消耗一个
    队列想做成镜像队列,需要先设置 policy,然后客户端创建队列的时候,rabbitmq 集群根据“队列名称”自动设置是普通集群模式或镜像队列

推荐设计架构:

在一个 rabbitmq 集群里,有 3 台或以上机器,其中 1 台使用磁盘模式(数据保存到内存和磁盘),其它节点使用内存模式(数据只保存到内存),使用磁盘模式的节点,作为数据备份使用

Ubuntu 1804 安装集群版 RabbitMQ

1
2
3
10.0.1.101 mq1.ljk.cn mq1
10.0.1.102 mq1.ljk.cn mq2
10.0.1.103 mq1.ljk.cn mq3

Rabbitmq 的集群是依赖于 erlang 的集群来工作的,所以必须先构建起 erlang 的集群环境,而 Erlang 的集群中各节点是通过一个 magic cookie 来实现的,这个cookie 存放在 /var/lib/rabbitmq/.erlang.cookie 中,文件是 400 的权限,所以必须保证各节点 cookie 保持一致,否则节点之间就无法通信

  1. 各节点安装RabbitMQ并安装插件,参考上面单机部署

  2. 各服务器关闭 RabbitMQ

    1
    2
    3
    [root@mq1 ~]$systemctl stop rabbitmq-server.service
    [root@mq2 ~]$systemctl stop rabbitmq-server.service
    [root@mq3 ~]$systemctl stop rabbitmq-server.service
  3. 在 mq1 同步.erlang.cookie 至其他两台服务器

    1
    2
    3
    [root@mq1 ~]$cd /var/lib/rabbitmq/
    [root@mq1 rabbitmq]$scp .erlang.cookie 10.0.1.102:/var/lib/rabbitmq
    [root@mq1 rabbitmq]$scp .erlang.cookie 10.0.1.103:/var/lib/rabbitmq
  4. 各服务器启动 RabbitMQ

    1
    2
    3
    [root@mq1 ~]$systemctl start rabbitmq-server.service
    [root@mq2 ~]$systemctl start rabbitmq-server.service
    [root@mq3 ~]$systemctl start rabbitmq-server.service
  5. 查看当前集群状态

    1
    2
    3
    [root@mq1 ~]$rabbitmqctl cluster_status
    [root@mq2 ~]$rabbitmqctl cluster_status
    [root@mq3 ~]$rabbitmqctl cluster_status
  6. 创建 RabbitMQ 集群:mq1、mq2作为内存节点,mq3作为磁盘节点

    1
    2
    3
    4
    [root@mq1 ~]$rabbitmqctl stop_app 	#停止 app 服务
    [root@mq1 ~]$rabbitmqctl reset #清空元数据
    [root@mq1 ~]$rabbitmqctl join_cluster rabbit@mq3 --ram #将mq1添加到集群中,并成为内存节点,不加--ram默认是磁盘节点
    [root@mq1 ~]$rabbitmqctl start_app #启动 app 服务
    1
    2
    3
    4
    [root@mq2 ~]$rabbitmqctl stop_app
    [root@mq2 ~]$rabbitmqctl reset
    [root@mq2 ~]$rabbitmqctl join_cluster rabbit@mq3 --ram
    [root@mq2 ~]$rabbitmqctl start_app
  7. 将集群设置为镜像模式,任意节点执行以下命令

    1
    [root@mq1 ~]$rabbitmqctl set_policy ha-all "#" '{"ha-mode":"all"}'
  8. 查看集群状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    [root@mq1 ~]$rabbitmqctl cluster_status               
    Cluster status of node rabbit@mq1 ...
    Basics

    Cluster name: rabbit@mq3.ljk.cn

    Disk Nodes

    rabbit@mq3

    RAM Nodes

    rabbit@mq1
    rabbit@mq2

    Running Nodes

    rabbit@mq1
    rabbit@mq2
    rabbit@mq3

    Versions

    rabbit@mq1: RabbitMQ 3.8.12 on Erlang 23.2.5
    rabbit@mq2: RabbitMQ 3.8.12 on Erlang 23.2.5
    rabbit@mq3: RabbitMQ 3.8.12 on Erlang 23.2.5

    Maintenance status

    Node: rabbit@mq1, status: not under maintenance
    Node: rabbit@mq2, status: not under maintenance
    Node: rabbit@mq3, status: not under maintenance

    Alarms

    (none)

    Network Partitions

    (none)

    Listeners

    Node: rabbit@mq1, interface: [::], port: 15672, protocol: http, purpose: HTTP API
    Node: rabbit@mq1, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
    Node: rabbit@mq1, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
    Node: rabbit@mq2, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
    Node: rabbit@mq2, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
    Node: rabbit@mq2, interface: [::], port: 15672, protocol: http, purpose: HTTP API
    Node: rabbit@mq3, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
    Node: rabbit@mq3, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
    Node: rabbit@mq3, interface: [::], port: 15672, protocol: http, purpose: HTTP API

    Feature flags

    Flag: drop_unroutable_metric, state: enabled
    Flag: empty_basic_get_metric, state: enabled
    Flag: implicit_default_bindings, state: enabled
    Flag: maintenance_mode_status, state: enabled
    Flag: quorum_queue, state: enabled
    Flag: user_limits, state: enabled
    Flag: virtual_host_metadata, state: enabled

RabbitMQ 常用命令

  • 创建 vhost

    1
    2
    [root@mq1 ~]$rabbitmqctl add_vhost test
    Adding vhost "test" ...
  • 列出所有 vhost

    1
    2
    3
    4
    5
    [root@mq1 ~]$rabbitmqctl list_vhosts
    Listing vhosts ...
    name
    /
    test
  • 列出所有队列

    1
    2
    3
    [root@mq1 ~]$rabbitmqctl list_queues
    Timeout: 60.0 seconds ...
    Listing queues for vhost / ...
  • 删除指定 vhost

    1
    2
    [root@mq1 ~]$rabbitmqctl delete_vhost test
    Deleting vhost "test" ...
  • 添加账户 jack 密码为 123456

    1
    2
    3
    [root@mq1 ~]$rabbitmqctl add_user jack 123456
    Adding user "jack" ...
    Done. Don't forget to grant the user permissions to some virtual hosts! See 'rabbitmqctl help set_permissions' to learn more.
  • 更改用户密码

    1
    2
    [root@mq1 ~]$rabbitmqctl change_password jack 654321
    Changing password for user "jack" ...
  • 设置 jack 用户对 test 的 vhost 有读写权限,三个点为配置正则、读和写

    1
    [root@mq1 ~]$rabbitmqctl set_permissions -p test jack ".*" ".*" ".*"  

RabbitMQ API

RabbitMQ Cluster Monitor

集群状态监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/bin/env python
# coding:utf-8
#Author: ZhangJie
import subprocess

running_list = []
error_list = []
false = "false"
true = "true"


def get_status():
obj = subprocess.Popen(
("curl - s - u guest: guest http: // localhost: 15672/api/nodes & > / dev/null"), shell=True, stdout=subprocess.PIPE)

data = obj.stdout.read()
data1 = eval(data)
for i in data1:
if i.get("running") == "true":
running_list.append(i.get("name"))
else:
error_list.append(i.get("name"))


def count_server():
if len(running_list) < 3: # 可以判断错误列表大于 0 或者运行列表小于 3,3未总计的节点数量
print(101) # 100 就是集群内有节点运行不正常了
else:
print(50) # 50 为所有节点全部运行正常


def main():
get_status()
count_server()


if __name__ == "__main__":
main()

内存使用监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# cat rabbitmq_memory.py
#!/bin/env python
# coding:utf-8
#Author: ZhangJie
import subprocess
import sys

running_list = []
error_list = []
false = "false"
true = "true"


def get_status():
obj = subprocess.Popen(
("curl - s - u guest: guest http: // localhost: 15672/api/nodes & > / dev/null"), shell=True, stdout=subprocess.PIPE)

data = obj.stdout.read()
data1 = eval(data)
# print(data1)
for i in data1:
if i.get("name") == sys.argv[1]:
print(i.get("mem_used"))


def main():
get_status()


if __name__ == "__main__":
main()

root@mq-server3: ~ # python3 rabbitmq_memory.py rabbit@mq-server1
85774336
root@mq-server3: ~ # python3 rabbitmq_memory.py rabbit@mq-server2
91099136
root@mq-server3: ~ # python3 rabbitmq_memory.py rabbit@mq-server3
96428032

MQ:Message Queuing,消息队列

Message Queue 的需求由来已久,在 19 世纪 80 年代金融交易中,美国高盛等公司采用 Teknekron 公司的产品,当时的 Message queuing 软件叫做(the informationbus(TIB),后来 TIB 被电信和通讯等公司采用,然后路透社收购了 Teknekron 公司,再然后 IBM 公司开发了 MQSeries,并且微软也开发了Microsoft Message Queue(MSMQ),但是这些商业 MQ 供应商的问题是厂商锁定及使用价格高昂,于是 2001 年,Java Message queuing 试图解决锁定和交互性的问题,但对应用来说反而更加麻烦了,于是 2004 年,摩根大通和 iMatrix 开始着手 Advanced MessageQueuing Protocol (AMQP)开放标准的开发,2006 年,AMQP 规范发布,2007年,Rabbit 技术公司基于 AMQP 标准开发的 RabbitMQ1.0 发布。

消息队列的目的是实现各个APP之间的通信(包括跨网咯通信),APP基于MQ实现消息的发送和接收,实现应用程序之间的通信,实现业务的解耦的异步机制

消息队列作为高并发系统的核心组件之一,能够帮助业务系统解构,提升开发效率和系统稳定性。消息队列主要具有以下优势:

  • 削峰填谷:主要解决瞬时写压力大于应用服务能力导致消息丢失、系统奔溃等问题
  • 系统解耦:解决不同重要程度、不同能力级别系统之间依赖导致一死全死
  • 提升性能:当存在一对多调用时,可以发一条消息给消息系统,让消息系统通知相关系统
  • 蓄流压测:线上有些链路不好压测,可以通过堆积一定量消息再放开来压测

目前主流的消息队列软件有 RabbitMQ、kafka、ActiveMQ、RocketMQ 等,还有小众的消息队列软件如ZeroMQ、Apache Qpid 等

微服务这个概念是从单体服务(单体应用)演化而来的

微服务:micro server,把单体服务拆分成多个小服务,这些小服务就是微服务,每个小服务运行在单独的运行环境,早期一般用虚拟机,现在都是容器(docker + k8s)

  • 微服务落地:容器,k8s + docker
  • 微服务发现对方:注册中心、服务发现,zookeeper
  • 微服务之间相互调用:API
  • 微服务扩容:服务治理,k8s实现服务编排
  • 微服务监控:监控微服务的API等
  • 微服务代码升级和回滚:CI / CD jenkings + gitlab
  • 微服务日志查看:ELK,统一收集和展示

服务是相互调用的,一个服务可以即是服务提供方,同时又是服务消费方

微服务框架

这个开发比较关注微服务框架,作为运维,了解即可

spring boot

spring cloud

dubbo

阿里云微服务:https://promotion.aliyun.com/ntms/act/edasdubbo.html
dubbo 官网:https://dubbo.apache.org/zh/
阿里云 dubbo 简介:https://help.aliyun.com/document_detail/99299.html

dubbo 架构

https://dubbo.apache.org/zh/docs/v2.7/user/preface/architecture/

节点角色说明:

节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

调用关系说明:

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。

连通性
  • 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
  • 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
  • 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
  • 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
  • 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
  • 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
  • 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
  • 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者
健壮性
  • 监控中心宕掉不影响使用,只是丢失部分采样数据
  • 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
  • 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
  • 服务提供者无状态,任意一台宕掉后,不影响使用
  • 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
伸缩性
  • 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
  • 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者
升级性

当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力。下图是未来可能的一种架构:

节点角色说明:

节点 角色说明
Deployer 自动部署服务的本地代理
Repository 仓库用于存储服务应用发布包
Scheduler 调度中心基于访问压力自动增减服务提供者
Admin 统一管理控制台
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心

示例

生产者示例

zk 配置:https://dubbo.apache.org/zh/docs/v2.7/user/references/registry/zookeeper/

注册中心除了zookeeper,还有其他方式:Nacos、Multicast、Redis、Simple

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@provider1 src]$tar zxf dubbo-demo-provider-2.1.5-assembly.tar.gz	# 开发写的包
[root@provider1 src]$cd dubbo-demo-provider-2.1.5/
[root@provider1 dubbo-demo-provider-2.1.5]$ls
bin conf lib

[root@provider1 dubbo-demo-provider-2.1.5]$vim conf/dubbo.properties
dubbo.container=log4j,spring
dubbo.application.name=demo-provider
dubbo.application.owner=
# dubbo.registry.address=zookeeper://10.0.1.101:2181 | zookeeper://10.0.1.102:2181 | zookeeper://10.0.1.103:2181 # 注册中心:zookeeper,z集群k
dubbo.registry.address=zookeeper://10.0.1.101:2181 # 注册中心:zookeeper,单zk
dubbo.monitor.protocol=registry
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.log4j.file=logs/dubbo-demo-provider.log
dubbo.log4j.level=WARN

[root@provider1 dubbo-demo-provider-2.1.5]$./bin/start.sh # 启动provider,可能需要几分钟
Starting the demo-provider ........OK!
PID: 2813
STDOUT: logs/stdout.log

[root@provider1 dubbo-demo-provider-2.1.5]$tail -f logs/stdout.log # 查看日志
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: UseCMSCompactAtFullCollection is deprecated and will likely be removed in a future release.
log4j:WARN No appenders could be found for logger (com.alibaba.dubbo.common.logger.LoggerFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
[2021-02-23 13:25:48] Dubbo service server started! # 启动成功

消费者示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@consumer1 src]$tar zxf dubbo-demo-consumer-2.1.5-assembly.tar.gz	# 开发写的包
[root@consumer1 src]$cd dubbo-demo-consumer-2.1.5/
[root@consumer1 dubbo-demo-consumer-2.1.5]$vim conf/dubbo.properties
dubbo.container=log4j,spring
dubbo.application.name=demo-consumer
dubbo.application.owner=
dubbo.registry.address=zookeeper://10.0.1.101:2181
dubbo.monitor.protocol=registry
dubbo.log4j.file=logs/dubbo-demo-consumer.log
dubbo.log4j.level=WARN
[root@kafka3 dubbo-demo-consumer-2.1.5]$./bin/start.sh # 启动consumer
Starting the demo-consumer ....OK!
PID: 2498
STDOUT: logs/stdout.log

[root@consumer1 dubbo-demo-consumer-2.1.5]$tail -f logs/stdout.log # 查看日志
[13:33:22] Hello world23, response form provider: 10.0.1.101:20880
[13:33:24] Hello world24, response form provider: 10.0.1.101:20880
[13:33:26] Hello world25, response form provider: 10.0.1.101:20880
[13:33:28] Hello world26, response form provider: 10.0.1.101:20880


[root@provider1 dubbo-demo-provider-2.1.5]$tail -f logs/stdout.log
[13:34:18] Hello world51, request from consumer: /10.0.1.103:13243
[13:34:20] Hello world52, request from consumer: /10.0.1.103:13243
[13:34:22] Hello world53, request from consumer: /10.0.1.103:13243
[13:34:24] Hello world54, request from consumer: /10.0.1.103:13243
[13:34:26] Hello world55, request from consumer: /10.0.1.103:13243
[13:34:28] Hello world56, request from consumer: /10.0.1.103:13243

以上示例是一个provider,如果是多个provider,则consumer会轮询读取

zookeeper 验证

dubbo admin

基于 zookeeper 发现并管理 provider 和 consumer

1
2
3
4
5
6
[root@kakfa1 webapps]$systemctl stop tomcat.service  # 先关闭tomcat,否则自动解压会出错
[root@kakfa1 webapps]$unzip dubboadmin.war -d dubboadmin # 别人编译好的包,手动解压
[root@kakfa1 webapps]$vim dubboadmin/WEB-INF/dubbo.properties # 配置文件
dubbo.registry.address=zookeeper://10.0.1.101:2181 # zookeeper地址
dubbo.admin.root.password=root # root用户,账号密码都是root
dubbo.admin.guest.password=guest # 访客

这个 duboadmin 版本比较老,如果需要新版的 dubboadmin,需要手动编译

微服务编译

https://dubbo.apache.org/zh/docs/v2.7/dev/build/

maven

编译c、c++,使用 make、cmake,编译java,使用maven

maven是一个项目管理工具,可以对Java项目进行构建、解决打包依赖等

POM:Project Object Model,项目对象模型,是 Maven 工程的基本工作单元,是一个 XML 文件,包含了项目的基本信息,用于描述项目如何构建,声明项目依赖等,在执行任务或目标时,Maven 会在当前目录中查找 pom 文件,通过读取 pom 文件获取所需的配置信息,然后执行目标

Pom 文件中可以指定以下配置:

1
2
3
4
5
6
7
项目依赖
插件
执行目标
项目构建 profile
项目版本
项目开发者列表
相关邮件列表信息

部署Maven:

1
2
3
4
5
6
7
8
# 官方文档:http://maven.apache.org/install.html
# 官方源:https://archive.apache.org/dist/maven/maven-3/
# 清华源:https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/

[root@kakfa1 src]$wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
[root@kakfa1 src]$tar zxf apache-maven-3.6.3-bin.tar.gz
[root@kakfa1 src]$cd apache-maven-3.6.3/
[root@kakfa1 apache-maven-3.6.3]$export PATH=`pwd`/bin:$PATH

Maven打包命令:

  1. 进入到包含有“pom.xml”的路径,执行:

    1
    mvn clean install package
  2. 有的时候受到测试的干扰,导致无法正在进行编译,这时候可以选择跳过测试:

    1
    2
    3
    4
    mvn clean install package -Dmaven.test.skip=true

    -Dmaven.test.skip=true # 跳过测试,并且不编译测试下的源代码;
    -DskipTests # 不执行测试,但是会进行测试代码的编译;
  3. 如果需要编译的代码异常庞大,需要考虑对编译环境做一些处理,提高编译效率

    1
    2
    3
    mvn -T 4 clean install package -Dmaven.test.skip=true		# 启动多线程编译
    mvn -T 2C clean install package -Dmaven.test.skip=true # 分配编译的CPU个数
    mvn clean install package -Dmaven.test.skip=true -Dmaven.compile.fork=true # 启用多线程编译
  4. 所有的 Maven 都是建立在 JVM 上的,所以进行编译的时候还需要考虑 JVM 参数优化

    1
    2
    3
    # bin/mvn是shell文件,配置参数:“MAVEN_OPTS”
    $ export MAVEN_OPTS="-Xmx6g -Xms6g" >> /etc/profile
    $ . /etc/profile

示例

以 dubbo admin 为例:https://github.com/apache/dubbo-admin/blob/develop/README_ZH.md

  1. 下载代码:

    1
    $ git clone https://github.com/apache/dubbo-admin.git
  2. 指定注册中心地址

    1
    2
    3
    4
    5
    6
    7
    $ vim dubbo-admin-server/src/main/resources/application.properties
    ...
    # centers in dubbo2.7
    admin.registry.address=zookeeper://10.0.1.101:2181
    admin.config-center=zookeeper://10.0.1.101:2181
    admin.metadata-report.address=zookeeper://10.0.1.101:2181
    ...
  3. 构建:

    1
    $ mvn clean package -Dmaven.test.skip=true
  4. 启动:

    1
    2
    3
    4
    $ mvn --projects dubbo-admin-server spring-boot:run
    # 或
    $ cd dubbo-admin-distribution/target;
    $ java -jar dubbo-admin-0.2.0.jar --server.port=8080 # 注意端口冲突
  5. 访问:浏览器访问 http://10.0.1.101:8080

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# vim /apps/zabbix_proxy/etc/zabbix_proxy.conf
ProxyMode=1 #0为主动,1为被动
Server=10.0.58.101 #zabbix server服务器的地址或主机名
Hostname=magedu-jiege-proxy-active #代理服务器名称,与zabbix server添加代理时候的proxy name一致
ListenPort=10051 #zabbix proxy监听端口
LogFile=/tmp/zabbix_proxy.log
PidFile=/apps/zabbix_proxy/run/zabbix_proxy.pid
EnableRemoteCommands=1 #允许zabbix server执行远程命令
DBHost=10.0.58.104 #数据库服务器地址
DBName=zabbix_proxy_active #使用的数据库名称
DBUser=proxy #连接数据库的用户名称
DBPassword=123456 #数据库用户密码
DBPort=3306 #数据库端口
ProxyLocalBuffer=720 #已经提交到zabbix server的数据保留时间
ProxyOfflineBuffer=720 #未提交到zabbix server的时间保留时间
HeartbeatFrequency=60 #心跳间隔检测时间,默认60秒,范围0-3600秒,被动模式不使用
ConfigFrequency=5 #间隔多少秒从zabbix server获取监控项信息
DataSenderFrequency=5 #数据发送时间间隔,默认为1秒,范围为1-3600秒,被动模式不使用
StartPollers=20 #启动的数据采集器数量
JavaGateway=10.0.58.104 #java gateway服务器地址,当需要监控java的时候必须配置否则监控不到数据
JavaGatewayPort=10052 #Javagatewa服务端口
StartJavaPollers=20 #启动多少个线程采集数据
CacheSize=2G #保存监控项而占用的最大内存
HistoryCacheSize=2G #保存监控历史数据占用的最大内存
HistoryIndexCacheSize=128M #历史索引缓存的大小
Timeout=30 #监控项超时时间,单位为秒f
LogSlowQueries=3000 #毫秒,多久的数据库查询会被记录到日志
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
ProxyMode=0			# proxy模式,0:主动模式;1:被动模式
Server=10.0.1.21 # zabbix-server的ip地址,被动模式的监控项使用
ServerPort=10051 # zabbix-server的端口号,默认10051,被动模式下,此参数忽略
Hostname=proxy-qinagdao-active # 在zabbix-server上用于区分proxy,通常设置为ip或主机名
HostnameItem=system.hostname # 功能和hostname一样,可以设置zabbix的键值,所以更方便
ListenPort=10051 # zabbix-proxy监听的本机端口
SourceIP= # 当服务器上有多个ip地址,可以指定使用哪个ip发起请求,一般不用配置

# 日志相关
LogType=file
LogFile=/tmp/zabbix_proxy.log
LogFileSize=0
DebugLevel=3

EnableRemoteCommands=0 # 是否允许远程命令

PidFile=/tmp/zabbix_proxy.pid
SocketDir=/tmp

# 数据库相关
DBHost=localhost
DBName=zabbix_proxy
DBSchema=
DBUser=zabbix
DBPassword=
DBSocket=
DBPort=

######### PROXY SPECIFIC PARAMETERS #############
ProxyLocalBuffer=24 # 发送成功的数据在本地保留多久,单位小时,0-172,也就是最多保留30天
ProxyOfflineBuffer=720 # 未发送成功的数据在本地保留多久,单位小时,0-172,也就是最多保留30天

HeartbeatFrequency=60 # 主动模式下,心跳检测zabbxi-server是否在线,0-3600,单位秒
ConfigFrequency=300 # 主动模式下,,配置的更新周期,1-3600*24*7,单位秒,这个参数建议设置为5分钟
DataSenderFrequency=60 # 数据向zabbix-server的推送周期,1-3600,单位秒

############ 高级参数 ################ 以下参数和 zabbix_server.conf 类似
StartPollers=5

# StartIPMIPollers=0
# StartPollersUnreachable=1
# StartTrappers=5
# StartPingers=1
# StartDiscoverers=1
# StartHTTPPollers=1
# JavaGateway=
# JavaGatewayPort=10052
# StartJavaPollers=0
# StartVMwareCollectors=0
# VMwareFrequency=60
# VMwarePerfFrequency=60
# VMwareCacheSize=8M
# VMwareTimeout=10
# SNMPTrapperFile=/tmp/zabbix_traps.tmp
# StartSNMPTrapper=0
# ListenIP=0.0.0.0
# HousekeepingFrequency=1
# CacheSize=8M
# StartDBSyncers=4
# HistoryCacheSize=16M
# HistoryIndexCacheSize=4M
Timeout=30
# TrapperTimeout=300
# UnreachablePeriod=45
# UnavailableDelay=60
# UnreachableDelay=15
# ExternalScripts=${datadir}/zabbix/externalscripts
# FpingLocation=/usr/sbin/fping
# Fping6Location=/usr/sbin/fping6
# SSHKeyLocation=
# LogSlowQueries=0
LogSlowQueries=3000
# TmpDir=/tmp
# AllowRoot=0
# User=zabbix
# Include=/usr/local/etc/zabbix_proxy.general.conf
# Include=/usr/local/etc/zabbix_proxy.conf.d/
# Include=/usr/local/etc/zabbix_proxy.conf.d/*.conf
# SSLCertLocation=${datadir}/zabbix/ssl/certs
# SSLKeyLocation=${datadir}/zabbix/ssl/keys
# SSLCALocation=
# StatsAllowedIP=
# LoadModulePath=${libdir}/modules
# LoadModule=
# TLSConnect=unencrypted
# TLSAccept=unencrypted
# TLSCAFile=
# TLSCRLFile=
# TLSServerCertIssuer=
# TLSServerCertSubject=
# TLSCertFile=
# TLSKeyFile=
# TLSPSKIdentity=
# TLSPSKFile=
# TLSCipherCert13=
# TLSCipherCert=
# TLSCipherPSK13=
# TLSCipherPSK=
# TLSCipherAll13=
# TLSCipherAll=

大部分同 zabbix_server.conf,以下是不同的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
EnableRemoteCommands=0	# 0/1,是否允许执行远程命令
LogRemoteCommands=0 # 0/1,是否记录远程命令日志
Server=10.0.1.21 # 被动模式,设置为server或proxy的地址,或者都设置,允许10.0.1.21来请求数据
ListenPort=10050 # zabbix_agent监听的本地端口
StartAgents=3 # 0-100,预启动进程数,执行被动检查,默认3个足够了
ServerActive=10.0.1.21 # 主动模式,设置为server或proxy的地址,或者都设置,向10.0.1.21发送数据
Hostname=10.0.1.26 # 主机名称,zabbix_server添加主机时需要此项,通常设置为ip或主机名
HostnameItem=system.hostname # 主机名称,和Hostname冲突,该项是动态的,其支持通过key进行配置,只要是zabbix_get能正常取的数据的key理论都是支持的(包含特殊字符的不支持)
HostMetadata= # 0-255 characters,自动注册使用,静态配置
HostMetadataItem= # 自动注册使用,动态配置

RefreshActiveChecks=120 # 主动模式下,每120秒主动提供一次数据

BufferSend=5 # 数据缓冲的时间
BufferSize=100 # zabbix agent数据缓冲区的大小,当达到该值便会发送所有的数据到zabbix server
MaxLinesPerSecond=20 # zabbix agent发送给zabbix server最大的数据行,1-1000

####### 用户定义的监控参数 #######
UnsafeUserParameters=0 # 0/1,是否允许所有字符参数的传递
UserParameter= # 指定用户自定义参数,可以定义多个,如果要传参,使用[*]
UserParameter=tcp_status[*],/bin/bash /usr/local/zabbix/etc/UserParameter/tcp_conn.sh $1 $2
UserParameter=memcache_status[*],/usr/local/zabbix/etc/UserParameter/memcached_status.sh "$1" "$2" "$3"
UserParameter=redis_status[*],/usr/local/zabbix/etc/UserParameter/redis_status.sh $1 $2 $3
UserParameter=nginx_status[*],/usr/local/zabbix/etc/UserParameter/nginx_status.sh $1 $2 $3
UserParameter=linux41[*],/bin/bash /usr/local/zabbix/etc/UserParameter/linux41.sh $1 $2 $3
UserParameter=qinghe,/usr/bin/python3 /usr/local/zabbix/etc/UserParameter/linux41.py
UserParameter=tcp_status[*],/bin/bash /usr/local/zabbix/etc/UserParameter/tcp_conn.sh $1 $2
UserParameter=memcache_status[*],/usr/local/zabbix/etc/UserParameter/memcached_status.sh "$1" "$2" "$3"
UserParameter=redis_status[*],/usr/local/zabbix/etc/UserParameter/redis_status.sh $1 $2 $3
UserParameter=nginx_status[*],/usr/local/zabbix/etc/UserParameter/nginx_status.sh $1 $2 $3


####### TLS相关参数 #######
TLSConnect=unencrypted
TLSAccept=unencrypted
TLSCAFile=
TLSCRLFile=
TLSServerCertIssuer=
TLSServerCertSubject=
TLSCertFile=
TLSKeyFile=
TLSPSKIdentity=
TLSPSKFile=

####### For advanced users - TLS ciphersuite selection criteria #######
TLSCipherCert13=
TLSCipherCert=
TLSCipherPSK13=
TLSCipherPSK=
TLSCipherAll13=
TLSCipherAll=

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# zabbix_server.conf
# This is a configuration file for Zabbix server daemon
# To get more information about Zabbix, visit http://www.zabbix.com

ListenPort=10051 # 监听端口
SourceIP= # 多IP地址情况下,与其他服务器通信使用的源IP地址,一般不用设置
PidFile=/tmp/zabbix_server.pid # PID文件路径
SocketDir=/tmp # socket文件路径,如果不涉及到本机通信,此参数意义不大

# 日志
LogType=file # 日志类型,支持system、file和console
LogFile=/tmp/zabbix_server.log # 日志路径
LogFileSize=0 # 指定日志滚动写入大小,当达到指定大小时,会删除就日志重新从头写入新日志,0-1024,最大1024M,0表示不限制,建议设置为0,因为这个文件一般不会太大
DebugLevel=3 #自定义日志级别,0-5,默认3 warning,可以设置为4 error

# 数据库
DBHost=192.168.7.104 # 数据库地址
DBName=zabbix_server # 数据库名称
DBSchema= # 数据库访问协议,默认myslq,如果使用其他数据库,需要设置
DBUser=zabbix # 数据库账号名
DBPassword=123456 # 数据库用户密码
DBSocket= # 数据库socket文件,如果mysql不在本机,此参数不需要配置
DBPort=3306 # 数据库端口,默认3306

# 历史数据
HistoryStorageURL= # elasticsearch服务器地址,保存zabbix历史数据到ES里面,优化zabbix性能,新版本zabbix的才支持
HistoryStorageTypes=uint,dbl,str,log,text # elasticsearch索引类型
HistoryStorageDateIndex=0 # 将历史数据保存到不同的elasticsearch索引

# 导出数据相关,一般不会导出数据,所以不需要配置
ExportDir= # 定义实时导出触发器事件,监控项采集值,趋势数据的目录
ExportFileSize=1G # 定义每个导出文件的最大大小

############ 高级参数 ################

StartPollers=16 # 预启动进程数量,收集数据,0-1000,建议此值设置与cpu核数相同
StartIPMIPollers=0 # 预启动进程数量,IPMI收集数据,0-1000,如果有物理服务器,可以打开
StartPreprocessors=3 # 预启动进程数量,用于处理zabbix agent数据,1-1000,建议设置高一些,如果使用proxy,server就不和agent直接接触了,这样可以设置的低一些
StartPollersUnreachable=1 # 预启动进程数量,轮询检查不可达主机,0-1000,设置1个进程就够了,毕竟服务器不会经常挂
StartTrappers=5 # 预启动进程数量,Trappers进程,处理报警信息,0-1000,报警多的话可以多开几个
StartPingers=3 # 预启动进程数量,用于ping检查主机,0-1000,建议设置多一
StartDiscoverers=1 # 自动发现主机的进程数量,0-250,此功能特别消耗资源,建议关闭
StartHTTPPollers=1 # http进程数量,处理web请求,设置1-2足够
StartTimers=1 # 计时器实例数量,记录报错、发邮件等行为的时间,1-1000,设置为2就足够
StartEscalators=1 # escalators进程的初始实例数量,用于处理动作中的自动步骤的进程的数量,0-100
StartAlerters=3 # 报警实例预启动数量,0-100,报警多的话可以开多一点

# 监控java,zabbix不能直监控java,而是通过javagateway间接监控
JavaGateway=192.168.7.101 # javagateway服务器地址,java pollers必须设置
JavaGatewayPort=10052 # javagateway端口,1024-32767
StartJavaPollers=20 # java轮训实例预启动数量,0-1000

# 监控VMware,很少用
StartVMwareCollectors=0 # 用于设置监控VMWARE Esxi主机实例时使用,0-250,若为0则不启用,若要监控ESXI主机,此值最少为1,根据监控ESXI数量设置对应数值
VMwareFrequency=60 # 监控vmware获取最新数据间隔频率,单位为秒,10-86400
VMwarePerfFrequency=60 # 监控vmware获取性能数据间隔
VMwareCacheSize=8M #vmware数据缓存大小,会占用zabbix server服务器内存
VMwareTimeout=10 #超时时间

SNMPTrapperFile=/tmp/zabbix_traps.tmp # snmp触发器临时文件路径
StartSNMPTrapper=0 # 是否启用 snmptrapper功能 ,默认0不启用(配合参数SNMPTrapperFile使用)

ListenIP=0.0.0.0 # 监听地址

# 历史数据相关,通过设置参数,删不干净,通常写sql脚本,直接删库
HousekeepingFrequency=1 # 多少小时清理一次代理端数据库的history数据,0-24,默认1小时,关于多久之前的数据是history数据,在模板的监控项中有设置
MaxHousekeeperDelete=5000 # 每次最多删除历史数据的行数,0-1000000

# 缓存相关,以下缓存空间都是隔离的
CacheSize=128M # zabbix初始化时占用多少系统共享内存用于存储配置信息,HOST,ITEM,TRIGGER数据,视监控主机数量和监控项调整,建议调整到32M或者更大
CacheUpdateFrequency=60 # Zabbix更新缓存数据的频率,单位为秒,范围是1-3600,若管理页面操作不频繁,可以考虑加大参数值
StartDBSyncers=8 # zabbix和数据库同步数据的进程数量,1-100,视数据库服务器I/O繁忙情况,和数据库写能力调整。数值越大,写能力越强。对数据库服务器I/O压力越大
HistoryCacheSize=512M # 历史数据的缓存大小,128K-2G
HistoryIndexCacheSize=128M # 历史数据索引缓存的大小,128K-2G
TrendCacheSize=4M # 划分多少系统共享内存用于存储计算出来的趋势数据,一定程度上可缓解数据库读压力
ValueCacheSize=64M # 历史值缓存的大小,用于缓存历史数据请求的共享内存大小

# 超时相关
Timeout=30 # 数据获取等待超时时间,1-30,建议加大此值,注意若此数值加大,应该考虑参数 StartPollers 是否有相应加大的必要。
TrapperTimeout=300 # 启用trapper功能,用于进程等待超时设置,1-300,单位是秒
UnreachablePeriod=45 # 当主机不可达多少秒后,设置为主机不可用,单位是秒,范围是1-3600
UnavailableDelay=60 # 当主机不可用了,多久检查一次该主机的可用性,单位为秒,范围是1-3600
UnreachableDelay=15 # 同 UnavailableDelay

# 脚本相关
AlertScriptsPath=${datadir}/zabbix/alertscripts # 监控报警脚本路径,取决于编译时datadir参数
ExternalScripts=${datadir}/zabbix/externalscripts # 自定义脚本存储路径

FpingLocation=/usr/bin/fping # fping命令的位置
Fping6Location=/usr/bin/fping6 # fping6命令的位置

SSHKeyLocation= # 用于SSH检查和操作的公钥和私钥的位置。

LogSlowQueries=0 # 设置慢日志查询时间(以毫秒为单位),仅当DebugLevel设置为3、4、5时才可用,0 - 不记录慢查询,范围是1-3600000,数据库自带慢日志查询功能,这里一般也不设置

TmpDir=/tmp # 临时文件目录

StartProxyPollers=1 # 启用多少子进程与proxy端通信,建议此值等于proxy数量,范围是0-250
ProxyConfigFrequency=60 # 被动模式下,被监控主机同步配置文件至proxy的周期,单位秒,1-3600*24*7
ProxyDataFrequency=60 # 被动模式下,zabbix server间隔多少秒向proxy请求历史数据,1-3600

AllowRoot=0 # 是否允许root启动zabbix,0/1

User=zabbix # 设置zabbix启动用户

Include=/usr/local/etc/zabbix_server.general.conf # 导入其他目录的配置文件
Include=/usr/local/etc/zabbix_server.conf.d/
Include=/usr/local/etc/zabbix_server.conf.d/*.conf

# web监控 SSL相关
SSLCertLocation=${datadir}/zabbix/ssl/certs # SSL证书公钥的位置,用于web监控
SSLKeyLocation=${datadir}/zabbix/ssl/keys # SSL客证书私钥位置,用于web监控
SSLCALocation= # SSL CA钥文件目录

StatsAllowedIP= # 允许访问zabbix server的IP地址列表,不过一般通过防火墙限制

# 第三方模块相关
LoadModulePath=${libdir}/modules # 第三方模块目录路径
LoadModule= #第三方模块路径,示例:LoadModule=<path/module.so>

# TLS相关,不过zabbix一般不用证书,即使用,配置在nginx也更合适
TLSCAFile= # CA文件
TLSCRLFile= # 包含已吊销证书的文件的完整路径名。
TLSCertFile= # 公钥文件路径
TLSKeyFile= # 私钥文件路径

以上所有参数的设置,可以先设置一个较小的保守的值,然后通过测试,一点点调整,最终优化到合适的值

监控服务介绍

逻辑布局

整体布局

常见的监控服务

开源监控软件:cacti、naglos、zabbix、smokeping、open-falcon等

Cacti

官网:https://www.cacti.net/
github:https://github.com/Cacti/cacti

1
2
3
Cacti是基于LAMP平台展现的网络流量监测及分析工具,通过SNMP技术或自定义脚本从目标设备/主机获取监控指标信息;其次进行数据存储,调用模板将数据存到数据库,使用rrdtool存储和更新数据,通过rrdtool绘制结果图形;最后进行数据展现,通过Web方式将监控结果呈现出来,常用于在数据中心监控网络设备

目前还有很多 数据中心、IDC服务商 还在用Cacti

缺点:只针对物理设备、虚拟机这样有固定IP地址的设备,不适合容器

Nagios

官网:https://www.nagios.org/

1
Nagios用来监视系统和网络的开源应用软件,利用其众多的插件实现对本机和远端服务的监控,当被监控对象发生异常时,会及时向管理员告警,提供一批预设好的监控插件,用户可以之间调用,也可以自定义Shell脚本来监控服务,适合各企业的业务监控,可通过Web页面显示对象状态、日志、告警信息,分层告警机制及自定义监控相对薄弱

缺点:报警机制比较简单,无法实现分组报警、递归报警等功能

SmokePing

官网地址:https://oss.oetiker.ch/smokeping/

1
Smokeping是一款用于网络性能监测的开源监控软件,主要用于对IDC的网络状况,网络质量,稳定性等做检测,通过rrdtool制图方式,图形化地展示网络的时延情况,进而能够清楚的判断出网络的即时通信情况

可以监测全国各地连接到网站的网速,类似 站长之家 的某些测速功能

Open-falcon

官网:https://www.open-falcon.org/
github:https://github.com/XiaoMi/open-falcon
文档:https://book.open-falcon.org/zh_0_2/contributing.html

1
2
小米公司开源出来的监控软件open-falcon(猎鹰),监控能力和性能较强
插件很多,部署复杂

夜莺

官网:https://n9e.didiyun.com/

1
滴滴出品,一款经过大规模生产环境验证的、分布式高性能的运维监控系统,基于 Open-falcon 二次开发

Zabbix

官网:https://www.zabbix.com/cn/

1
2
3
Zabbix是一个企业级解决方案,支持实时监控数千台服务器,虚拟机和网络设备,采集百万级监控指标,适用于任何IT基础架构、服务、应用程序和资源的解决方案

目前使用较多的开源监控软件,可横向扩展、自定义监控项、支持多种监控方式、可监控网络与服务等

缺点:zabbix使用mysql,数据库部分容易成为瓶颈

Prometheus

针对容器环境的开源监控软件

商业监控解决方案

Zabbix使用场景及系统概述

https://www.zabbix.com/cn/features

使用场景

网络服务器虚拟机应用服务数据库Web安全

系统概述

主要功能

数据采集问题检测可视化告警 & 修复安全 & 认证轻松部署自动发现分布式监控Zabbix API

数据采集

所有监控系统的工作原理都类似,都需要采集被监控对象的数据

周期性时序数据

1
2
3
4
5
- 主机/对象:服务器、路由器、交换机、存储、防火墙、IP、PORT、URL、自定义监控对象…
- 服务器较少时,采集时间可以快点,两三分钟一次
- URL 就是 API
- 自定义监控对象,通过写脚本实现
- 采集目标:监控项,指标数据(metrics data)

数据采集方式:

  1. zabbix-agent 采集本机数据,然后发送给 zabbix-proxy
  2. zabbix-proxy 将数据发送给 zabbix-server
    注意:不是实时转发,zabbix-proxy 也搭配 mysql,负责临时存储数据
  3. zabbix-server 只和zabbix-proxy保持连接即可,将数据存储到 mysql,结束采集

如果不安装(或者无法安装)agent客户端,可以使用特定的协议进行数据采集:

1
2
3
4
5
- SNMP:适用于路由器、交换机等网络设备
- Telnet
- ssh
- IPMI:物理机上如果有IPM接口,可以采集cpu温度、风扇传输等硬件信息
- JMX:监控java
数据存储

监控数据存储系统

1
2
3
4
5
6
7
- SQL: MySQL/MariaDB(Zabbix)
- NoSQL:Redis(Open-falcon)
- rrd: Round Robin Database(Cacti) 环形存储,始终保存一年的数据,一年前的覆盖掉

prometheus:时序数据库
zabbix:MySQL
cacti:rrd
数据类型
1
2
3
4
- 历史数据: 每个监控项采集到的每个监控值,查询时可能会造成数据库负载过大,开发和测试也会查看
- 趋势数据: 趋势表里主要保留某个监控项一个小时内历史数据的最大值、最小值和平均值以及该监控项一个小时内所采集到的数据个数

趋势数据是对历史数据的筛选,历史数据保存时间短一些,30天足以,趋势数据保存时间长一些,可以设置为一年
阈值

可按照预定义的阈值等级实现分层报警,可以80%,不过要考虑基数,Zabbix用的好不好,就看阈值设置的好不好,需要慢慢优化

告警机制

email、短信、微信、语音、故障自治愈(zabbix通知服务器重启,需事先写好脚本,针对物理机和虚拟机)

初级运维 –> 中级运维/高级运维 –> 架构师 –> 总监 –> CTO

1
2
host (host groups) <- templates		# 从模板继承告警配置
host -> items -> triggers -> action (条件-conditions, 操作-operations) # 自定义告警配置
数据展示
1
2
- zabbix web:基于nginx+php
- grafana:以zabbix为数据源,展示更为绚丽的界面

Zabbix 规划及部署

目前最新的LTS版本是5.0,5.0和之前版本有明显区别,但是文档还是英文的,所以目前学习还是以4.0为准

下载页面:https://www.zabbix.com/cn/download

规划

  • 数据库:CPU和磁盘IO一定要快,内存最好32G,磁盘要大,zabbix的监控数据会远大于业务数据量
  • zabbix server:zabbix server 直接装在物理机
    • CPU:16核
    • 磁盘:RAID10、500G
    • 内存:8G(监控几十个节点),16G(监控几百个节点),32G(监控两千个节点)

实验:

部署环境:服务器系统 ubuntu 18.04.5 / Centos 7.x

主机类型 IP地址
zabbix server 10.0.1.21
zabbix 主动代理 10.0.1.22
zabbix 被动代理 10.0.1.23
mysql master 10.0.1.24
mysql slave 10.0.1.25
web server1 10.0.1.26
web server2 10.0.1.27

yum/apt 安装

  1. Install Zabbix repository

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $wget https://repo.zabbix.com/zabbix/4.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_4.0-3+bionic_all.deb
    $ls
    zabbix-release_4.0-3+bionic_all.deb
    $dpkg -c zabbix-release_4.0-3+bionic_all.deb #查看dep包的内容
    ...
    #zabbix.list:官方提供的源
    -rw-r--r-- root/root 118 2019-07-30 16:34 ./etc/apt/sources.list.d/zabbix.list
    ...
    $dpkg -i zabbix-release_4.0-3+bionic_all.deb #安装dep包
    $vim /etc/apt/sources.list.d/zabbix.list #修改zabbix源
    #deb http://repo.zabbix.com/zabbix/4.0/ubuntu bionic main
    #deb-src http://repo.zabbix.com/zabbix/4.0/ubuntu bionic main
    deb https://mirrors.aliyun.com/zabbix/zabbix/4.0/ubuntu bionic main #替换为阿里云的源
    deb-src https://mirrors.aliyun.com/zabbix/zabbix/4.0/ubuntu bionic main
    $apt update
  2. 安装Zabbix server,Web前端,agent

    1
    2
    3
    [root@zabbix-server ~]$apt install zabbix-server-mysql zabbix-frontend-php zabbix-agent
    [root@zabbix-server ~]$systemctl disable mysql.service # 数据库单独装,把自带的禁用掉
    [root@zabbix-server ~]$systemctl stop mysql.service
  3. 安装、配置 mysql

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@mysql-master ~]$apt search mysql-server	# 确保mysql版本不低于5.7
    [root@mysql-master ~]$apt install mysql-server mysql-client

    [root@mysql-master ~]$mysql -uroot -p
    # 创建 zabbix_server 数据库
    mysql> create database zabbix_server character set utf8 collate utf8_bin;
    # 创建 zabbix_server 用户
    mysql> create user zabbix_server@'10.0.%.%' identified by '123456';
    mysql> grant all privileges on zabbix_server.* to zabbix_server@'10.0.%.%';

    [root@mysql-master ~]$vim /etc/mysql/mysql.conf.d/mysqld.cnf
    [mysqld]
    bind-address = 0.0.0.0 # 修改监地址,默认监听127.0.0.1,修改为0.0.0.0

    [root@mysql-master ~]$systemctl restart mysql.service

    数据库初始化:

    1
    [root@zabbix-server ~]$zcat /usr/share/doc/zabbix-server-mysql*/create.sql.gz | mysql -uzabbix_server -p123456 -h10.0.1.24 zabbix_server
  4. 为 Zabbix server 配置数据库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # 编辑配置文件 /etc/zabbix/zabbix_server.conf
    [root@zabbix-server ~]$vim /etc/zabbix/zabbix_server.conf
    DBHost=10.0.1.24
    DBName=zabbix_server
    DBUser=zabbix_server
    DBPassword=123456

    [root@zabbix-server ~]$grep '^[a-Z]' /etc/zabbix/zabbix_server.conf
    LogFile=/var/log/zabbix/zabbix_server.log
    LogFileSize=0
    PidFile=/var/run/zabbix/zabbix_server.pid
    SocketDir=/var/run/zabbix
    DBHost=10.0.1.24
    DBName=zabbix_server
    DBUser=zabbix_server
    DBPassword=123456
    SNMPTrapperFile=/var/log/snmptrap/snmptrap.log
    Timeout=4
    AlertScriptsPath=/usr/lib/zabbix/alertscripts
    ExternalScripts=/usr/lib/zabbix/externalscripts
    FpingLocation=/usr/bin/fping
    Fping6Location=/usr/bin/fping6
    LogSlowQueries=3000
  5. 为Zabbix前端配置PHP

    1
    2
    3
    4
    5
    6
    7
    # 编辑配置文件 /etc/zabbix/apache.conf
    [root@zabbix-server ~]$vim /etc/zabbix/apache.conf
    # php_value date.timezone Europe/Riga
    php_value date.timezone Asia/Shanghai # 修改时区

    # 重启 zabbix 和 apache 服务
    [root@zabbix-server ~]$systemctl restart zabbix-server zabbix-agent apache2
  6. 浏览器访问 http://10.0.1.21/zabbix,然后根据提示一步步配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Database type	MySQL
    Database server 10.0.1.24
    Database port 3306
    Database name zabbix_server
    Database user zabbix_server
    Database password 123456

    Zabbix server 10.0.1.21 # ip 和 主机名 均可
    Zabbix server port 10051
    Zabbix server name zabbix_server # 这里随便写

    # 如果以后更改配置,需要修改两个文件
    # /etc/zabbix/zabbix_server.conf
    # /usr/share/zabbix/conf/zabbix.conf.php # 生成的配置在此文件中

    默认的账号 Admin,密码 zabbix

  7. 默认只能显示英文,所以需要汉化

    1
    2
    3
    4
    5
    6
    7
    8
    # 安装简体中文语言环境
    [root@zabbix-server ~]$apt install language-pack-zh*
    # 增加中文语言环境变量
    [root@zabbix-server ~]$vim /etc/environment
    PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
    LANG="zh_CN.UTF-8" # 添加此行
    # 重新设置本地配置
    [root@zabbix-server ~]$dpkg-reconfigure locales

    1
    2
    # 配置好后,需要重启apacha、php-fpm
    [root@zabbix-server ~]$systemctl restart apache2 php-fpm

    但是,还有部分页面乱码,需要更换默认的字体包:

    从 windows(位于 C:\Windows\Fonts) 系统中挑一个顺眼的字体包,上传到服务器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@zabbix-server fonts]$pwd
    /usr/share/zabbix/assets/fonts # 注意目录
    [root@zabbix-server fonts]$ls | tr ' ' \n
    graphfont.ttf # 默认字体
    simhei.ttf # 刚上传的 黑体
    simkai.ttf # 刚上传的 楷体,这两个都可以,其他的不一定可以


    [root@zabbix-server include]$pwd
    /usr/share/zabbix/include # 注意目录
    # 修改默认字体为黑体,楷体也可以
    [root@zabbix-server include]$sed -i 's/graphfont/simkai/' defines.inc.php
    [root@zabbix-server include]$systemctl restart apache2 php-fpm

    编译安装

    官方文档:https://www.zabbix.com/documentation/4.0/zh/manual/installation/install

    把 apt 安装的 zabbix-server、zabbix-proxy、zabbix-agent 等软件的 service 文件拷贝出来备用,然后恢复快照

    具体详见脚本 script-apt

    注意:

    1. server 和 proxy 不能安装在同一台主机

    2. 如果是centos,安装依赖参考:

      1
      yum install gcc libxml2-devel net-snmp net-snmp-devel curl curl-devel php phpbcmath php-mbstring mariadb mariadb-devel -y
    3. 汉化操作需要手动执行,脚本没有实现这个功能,不要忘记重启php-fpm

Zabbix 监控入门基础

  1. 了解业务结构
  2. 监控
  3. 业务优化

zabbix 概念

配置

  • 模板:

    • 键值(key):最基础的指令,每个键值表示一项数据,比如 system.hostname 表示主机名,zabbix内置了 一些,如果不够用,可以自定义(需要在zabbix_agentd.conf中指定)
    • 监控项(item):主要是由 键值 + 更新周期 组成
    • 应用集:对监控项分组,功能类似的监控项的合集
    • 触发器:据监控项的返回值对比预先设置的阈值,触发器会触发动作
      • 表达式:功能一般选择 last
    • 图形:
    • 自动发现:
    • web场景/web检测:
  • 主机群组

    • 1
  • 主机

    • d
  • 维护

    • w
  • 动作

    • 动作:动作由触发器触发,触发动作选项用来限制触发器的范围,一般选主机群组,只有该主机群组中的主机的触发器可以触发动作,多个触发条件可以选择和/或的关系

    • 操作:动作的操作会调用报警媒介,发送到指定用户,毕竟数据库出问题,需要发给DBA,发给网络工程师也不管用

      • 默认操作步骤持续时间:发送周期,一般配置 60s,即60秒发一次

      • 默认标题 和 消息内容:用{}包裹的变量是宏,zabbix所有内置的宏,参考:官方文档

        1
        2
        3
        4
        # 示例:
        {ALERT.SENDTO} # 报警脚本参数,值来自于用户报警媒介配置,可能是邮件、手机号等等
        {ALERT.SUBJECT} # 报警脚本参数,默认值由动作配置
        {ALERT.MESSAGE} # 报警脚本参数,默认值由动作配置
    • 恢复操作:解决完报警信息后,恢复信息也要发送

    • 更新操作:

  • 关联事件

    • 4
  • 自动发现:添加/移除/更改元素时执行自动操作

    https://www.zabbix.com/cn/auto_discovery
    https://www.zabbix.com/documentation/4.0/zh/manual/discovery/network_discovery

    • 网络发现:定期扫描、发现设备类型,IP,状态,运行时间/停机时间等,并采取预定义的操作。
    • 低级别发现(LLD):自动为设备上不同元素创建监控项,触发器和图形。
    • 主动agent自动注册 使用Zabbix agent自动开始监控新设备
  • 服务

    • 2

管理

  • agent代理程序:即 proxy
  • 报警媒介类型:把报警信息通知给用户的方式,可以配置邮件、短信、微信(通过脚本实现)等方式,以qq邮件为例,将qq邮箱和用户关联起来,发生报警后,qq邮箱作为发件人将报警信息发送到用户的邮箱中
  • 用户

zabbix server

官方文档:https://www.zabbix.com/documentation/4.0/zh/manual/concepts/server

zabbix server 是整个 zabbix 软件的核心程序。
zabbix server是所有配置、统计和操作数据的中央存储中心,也是zabbix监控系统的告警中心。
基本的 zabbix server 的功能分解成为三个不同的组件。他们是:zabbix server、web前端和数据库。

zabbix proxy

官方文档:https://www.zabbix.com/documentation/4.0/zh/manual/concepts/proxy

zabbix proxy 代表 zabbix server 采集监控数据,减轻 zabbix server 的 cpu 和 io 开销。
zabbix proxy 从受监控设备采集监控数据,先将数据缓存到本机数据库,然后传输到所属的 zabbix server。

zabbix agent

官方文档:https://www.zabbix.com/documentation/4.0/zh/manual/concepts/agent

proxy 和 agent 都是代理,但前者是 服务端,后者是客户端

zabbix agent 部署在被监控目标上,以主动监控本地资源和应用程序(硬盘、内存、处理器统计信息等)。

zabbix agent 收集本地的操作信息并将数据报告给 zabbix server 用于进一步处理。一旦出现异常 (例如硬盘空间已满或者有崩溃的服务进程),zabbix server 会主动警告管理员指定机器上的异常。

zabbix agents 的极高效率缘于它可以利用本地系统调用来完成统计数据的采集。

默认监听在 10051 端口。

sender

主要用于测试的命令,例如:如果 Zabbix agent 收集不到数据,可以用这个命令发一下测试数据,看一下是 Zabbix agent 的问题还是网络问题

get

主要用于测试的命令,可以与 Zabbix agent 进行通信,并从 Zabbix agent 那里获取所需的信息

注意:只有 zabbix_agentd.conf 中 Server 配置的 ip 才能从该主机上 get 到数据

监控tomcat

所有的监控,配置步骤都是一样的:

  1. 创建主机
  2. 给主机添加模板

主动与被动监控模式

主动和被动都是相对 agent 来说的,被动模式配置简单,所以默认是被动模式

  • 被动检查:zabbix server(或 proxy)向 agent 要数据,agent 才工作,否则就不工作
  • 主动检查:agent 从 zabbix server 获取监控项列表,然后定期采集数据,主动发送给 zabbix server

被动模式

被动模式下,zabbix server会根据主机关联的模板中的监控项和数据采集间隔时间,周期性的打开随机端口并向zabbix agent服务器的10050发起tcp连接,然后发送获取监控项数据的指令,即zabbix server发送什么指令,zabbix agent就收集什么数据,zabbix server什么时候发送zabbix agent就什么时候采集,zabbix server不发送zabbix agent就闲着,所以zabbix agent也不用关心其监控项和数据采集周期间隔时间

优点就是配置简单,缺点是会加大 zabbix server 的工作量,在数百甚至数千台服务器的环境下会导致 zabbix server 需要轮训向每个 zabbix agent 发送数据采集指令,如果 zabbix server 负载很高还会导致不能及时获取到最新数据

主动模式

主动模式下,zabbix agent 主动向 zabbix server 的10051端口发起 tcp 连接请求(zabbix agent配置文件中指定zabbix server的IP或者主机名),获取到自己的监控项和数据采集周期等信息,然后再周期性的采集指定的数返回给 zabbix server

主动模式可以有效减轻 zabbix server 的压力,推荐使用主动模式

配置主动模式:

  1. 修改 zabbix agent 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # zabbix_agentd.conf
    PidFile=/usr/local/zabbix/run/zabbix_agentd.pid
    LogFile=/tmp/zabbix_agentd.log
    LogFileSize=0
    Server=10.0.1.21 # 被动模式下,指定zabbix server的ip,如果全部监控项都是主动模式,则可注释此项
    StartAgents=3
    ServerActive=10.0.1.21 # 重点,开启主动模式,指定zabbix server的ip
    Hostname=10.0.1.26 # zabbix agent本机的ip
    Timeout=30
    Include=/usr/local/etc/zabbix_agentd.conf.d/*.conf
  2. 生成主动模式模板
    完全克隆zabbix内置的Template OS Linux模板,命名为:Template OS Linux-active,修改监控项的类型,可以单独改,也可以批量更新

  3. 最后把主动模式模板添加到主机上

zabbix proxy

zabbix proxy架构

zabbix proxy对比zbbbix server

功能 zabbxy proxy zabbix server
量级 请量级 相对重量级
图形 带图形控制界面
可以独立工作 是,可以独立采集数据并存储 是,即数据采集、存储、分析、展示于一体
易维护 是,配置完成后基本无需管理 维护也不难
独立数据库 保留少量最近数据 保留指定时间内的所有数据
报警通知 不支持发送邮件通知 支持邮件、短信等告警机制(基于调用脚本)

zabbix proxy部署与使用

zabbix proxy 的大版本必须要和 zabbix server 版本一致,否则会出现兼容性问题

apt/yum安装zabbix proxy

https://www.zabbix.com/documentation/4.0/zh/manual/installation/install_from_packages/debian_ubuntu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 安装软件仓库配置包
$wget https://repo.zabbix.com/zabbix/4.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_4.0-2+bionic_all.deb
$dpkg -i zabbix-release_4.0-2+stretch_all.deb
$sed -i 's@http://repo.zabbix.com@https://mirrors.aliyun.com/zabbix@' /etc/apt/sources.list.d/zabbix.list
$apt update
# 安装 SERVER/PROXY/前端
$apt install zabbix-proxy-mysql
$cat /lib/systemd/system/zabbix-proxy.service # 这里的service文件没有看懂
[Unit]
Description=Zabbix Proxy (MySQL/MariaDB)
Documentation=man:zabbix_proxy
After=network.target mysql.service

[Service]
Type=simple
User=zabbix
Group=zabbix
ExecStart=/usr/sbin/zabbix_proxy --foreground
Restart=on-abnormal

[Install]
WantedBy=multi-user.target

# 配置数据库
略...

编译安装zabbix proxy

  1. 编译安装,参考脚本…
  2. 修改被监控主机的配置文件,Server 和 ServerActive
  3. 管理 -> agent代理程序 -> 创建代理(注意名称要和zabbix_proxy.conf中的hostname对应起来) -> 修改主机的“由agent代理程序监测”参数

zabbix 监控案例实战

  1. 自定义监控项
  2. 通过脚本采集监控项数据
  3. zabbix agent获取监控项数据
  4. 自定义模板和图形及触发器
  5. 验证数据

监控Linux TCP连接状态

  1. 监控TCP连接数脚本

    1
    2
    3
    [root@zabbix-web1 ~]#cat /usr/local/zabbix/data/tcp_conn.sh
    #!/bin/bash
    ss -ant | awk -v TCP_STAT=$1 -v s=0 '$1==TCP_STAT {++s} END {print s}'
  2. zabbix agent添加自定义监控项

    1
    2
    3
    4
    5
    6
    [root@web1 etc]$vim zabbix_agentd.conf
    ...
    UserParameter=tcp_status[*],/bin/bash /usr/local/zabbix/data/tcp_conn.sh $1 $2
    ...
    [root@web1 etc]$chmod a+x zabbix_agentd.conf
    [root@web1 etc]$systemctl restart zabbix-agent
  3. zabbix server测试监控项数据

    1
    2
    3
    4
    5
    6
    [root@zabbix bin]$./zabbix_get -s 10.0.1.26 -p 10050 -k tcp_status[TIME-WAIT]
    1
    [root@zabbix bin]$./zabbix_get -s 10.0.1.26 -p 10050 -k tcp_status[ESTAB]
    2
    [root@zabbix bin]$./zabbix_get -s 10.0.1.26 -p 10050 -k tcp_status[LISTEN]
    9
  4. zabbix web导入模板
    配置-模板-导入

  5. 将TCP监控模板关联至主机

  6. 验证监控数据

监控Memcached

  1. 安装 memcached

  2. 监控脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    [root@web1 data]$grep '^[^#]' /etc/memcached.conf    
    -d
    logfile /var/log/memcached.log
    -m 64
    -p 11211
    -u memcache
    -l 127.0.0.1
    -P /var/run/memcached/memcached.pid

    [root@web1 data]$echo -e "stats\nquit" | nc 127.0.0.1 11211
    STAT pid 5590
    STAT uptime 725
    STAT time 1613618905
    STAT version 1.5.6 Ubuntu
    STAT libevent 2.1.8-stable
    STAT pointer_size 64
    STAT rusage_user 0.072870
    STAT rusage_system 0.048580
    STAT max_connections 1024
    STAT curr_connections 1
    STAT total_connections 4
    STAT rejected_connections 0
    STAT connection_structures 2
    STAT reserved_fds 20
    STAT cmd_get 0
    STAT cmd_set 0
    STAT cmd_flush 0
    STAT cmd_touch 0
    STAT get_hits 0
    STAT get_misses 0
    STAT get_expired 0
    STAT get_flushed 0
    STAT delete_misses 0
    STAT delete_hits 0
    STAT incr_misses 0
    STAT incr_hits 0
    STAT decr_misses 0
    STAT decr_hits 0
    STAT cas_misses 0
    STAT cas_hits 0
    STAT cas_badval 0
    STAT touch_hits 0
    STAT touch_misses 0
    STAT auth_cmds 0
    STAT auth_errors 0
    STAT bytes_read 35
    STAT bytes_written 3795
    STAT limit_maxbytes 67108864
    STAT accepting_conns 1
    STAT listen_disabled_num 0
    STAT time_in_listen_disabled_us 0
    STAT threads 4
    STAT conn_yields 0
    STAT hash_power_level 16
    STAT hash_bytes 524288
    STAT hash_is_expanding 0
    STAT slab_reassign_rescues 0
    STAT slab_reassign_chunk_rescues 0
    STAT slab_reassign_evictions_nomem 0
    STAT slab_reassign_inline_reclaim 0
    STAT slab_reassign_busy_items 0
    STAT slab_reassign_busy_deletes 0
    STAT slab_reassign_running 0
    STAT slabs_moved 0
    STAT lru_crawler_running 0
    STAT lru_crawler_starts 1275
    STAT lru_maintainer_juggles 774
    STAT malloc_fails 0
    STAT log_worker_dropped 0
    STAT log_worker_written 0
    STAT log_watcher_skipped 0
    STAT log_watcher_sent 0
    STAT bytes 0
    STAT curr_items 0
    STAT total_items 0
    STAT slab_global_page_pool 0
    STAT expired_unfetched 0
    STAT evicted_unfetched 0
    STAT evicted_active 0
    STAT evictions 0
    STAT reclaimed 0
    STAT crawler_reclaimed 0
    STAT crawler_items_checked 0
    STAT lrutail_reflocked 0
    STAT moves_to_cold 0
    STAT moves_to_warm 0
    STAT moves_within_lru 0
    STAT direct_reclaims 0
    STAT lru_bumps_dropped 0
    END

    [root@web1 data]$cat memcache_monitor.sh
    #!/bin/bash
    echo -e "stats\nquit" | nc 127.0.0.1 11211 | grep "STAT $1" | awk '{print $3}'
  3. zabbix agent添加自定义监控项

  4. zabbix server测试监控项数据

  5. zabbix web制作模板

    1. 创建模板
    2. 创建监控项
    3. 创建触发器
    4. 创建图形
  6. 模板关联主机

  7. 验证监控项数据

监控Redis

  1. 安装Redis

  2. 监控脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    [root@web1 data]$redis-cli -h 127.0.0.1 -p 6379 info			# 所有info
    ...
    [root@web1 data]$redis-cli -h 127.0.0.1 -p 6379 info clients # 客户端相关info
    # Clients
    connected_clients:1 # 当前连接数
    client_longest_output_list:0
    client_biggest_input_buf:0
    blocked_clients:0
    [root@web1 data]$redis-cli -h 127.0.0.1 -p 6379 info memory # 内存相关info
    # Memory
    used_memory:839288 # 已用内存
    used_memory_human:819.62K
    used_memory_rss:3846144
    used_memory_rss_human:3.67M
    used_memory_peak:841288
    used_memory_peak_human:821.57K
    used_memory_peak_perc:99.76%
    used_memory_overhead:832134
    used_memory_startup:782504
    used_memory_dataset:7154
    used_memory_dataset_perc:12.60%
    total_system_memory:2065870848
    total_system_memory_human:1.92G
    used_memory_lua:37888
    used_memory_lua_human:37.00K
    maxmemory:0
    maxmemory_human:0B
    maxmemory_policy:noeviction
    mem_fragmentation_ratio:4.58
    mem_allocator:jemalloc-3.6.0
    active_defrag_running:0
    lazyfree_pending_objects:0
  3. zabbix agent添加自定义监控项

  4. zabbix server测试监控项数据

  5. zabbix web模板制作

    1. 创建模板
    2. 创建触监控项:当前连接数监控项、已用内存监控项
    3. 创建触发器:当前连接数触发器、已用内存触发器
    4. 创建图形:Redis当前连接数图形、Redis已用内存图形
  6. 模板关联主机

  7. 验证监控项数据

监控 Nginx

  1. 安装nginx

  2. 监控脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    #!/bin/bash
    nginx_active() {
    curl "http://127.0.0.1:/nginx_status/" 2>/dev/null | grep 'Active' | awk '{print $NF}'
    }
    nginx_reading() {
    curl "http://127.0.0.1:/nginx_status/" 2>/dev/null | grep 'Reading' | awk '{print $2}'
    }
    nginx_writing() {
    curl "http://127.0.0.1:/nginx_status/" 2>/dev/null | grep 'Writing' | awk '{print $4}'
    }
    nginx_waiting() {
    curl "http://127.0.0.1:/nginx_status/" 2>/dev/null | grep 'Waiting' | awk '{print $6}'
    }
    nginx_accepts() {
    curl "http://127.0.0.1:/nginx_status/" 2>/dev/null | awk NR==3 | awk '{print $1}'
    }
    nginx_handled() {
    curl "http://127.0.0.1:/nginx_status/" 2>/dev/null | awk NR==3 | awk '{print $2}'
    }
    nginx_requests() {
    curl "http://127.0.0.1:/nginx_status/" 2>/dev/null | awk NR==3 | awk '{print $3}'
    }

    case $1 in
    active)
    nginx_active
    ;;
    reading)
    nginx_reading
    ;;
    writing)
    nginx_writing
    ;;
    waiting)
    nginx_waiting
    ;;
    accepts)
    nginx_accepts
    ;;
    handled)
    nginx_handled
    ;;
    requests)
    nginx_requests
    ;;
    esac
  3. zabbix agent添加自定义监控项

    1
    2
    3
    4
    [root@web1 etc]$cat zabbix_agentd.conf
    ...
    UserParameter=nginx_status[*],/usr/local/zabbix/data/nginx_status.sh $1
    ...
  4. 导入Nginx监控模板

  5. 模板关联主机

  6. 验证监控数据

SNMP 监控

SNMP:Simple Network Management Protocol,简单网络管理协议,TCP/IP协议簇的一个应用层协议

Linux 设备通过 agent 监控,网络设备通过 SNMP 协议监控,主要用于监控华为、思科等网络设备

SNMP有三个版本:目前主要使用的是 v2c 版本

1
2
3
SNMP v1		# 团体名(Community Name)认证
SNMP v2c # 团体名认证,它在兼容SNMP v1的同时又扩充了SNMP v1的功能
SNMP v3 # 基于用户的安全模型(USM,User-Based Security Model)的认证机制

SNMP数据交互

SNMP管理进程与代理进程之间为了交互信息,定义了5种报文:

1
2
3
4
5
get-request			# 从代理进程处提取一个或多个参数值
get-response # 返回的一个或多个参数值。这个操作是由代理进程发出的
trap # 代理进程主动发出的报文,通知管理进程有某些事情发生
get-next-request # 从代理进程处提取一个或多个参数的下一个参数值
set-request # 设置代理进程的一个或多个参数值

SNMP组织结构

SNMP结构非常复杂,一套完整的SNMP系统主要包括以下几个方面:

  1. SNMP报文协议
  2. 管理信息结构(SMI, Structure of Management Information),一套公用的结构和表示符号
  3. 管理信息库(MIB,Management Information Base),管理信息库包含所有代理进程的所有可被查询和修改的参数
  4. OID(Object Identifiers),一个OID是一个唯一的键值对,用于标识具体某一个设备的某个具体信息(对象标识),如端口信息、设备名称等

SNMP MIB

MIB是OID的集合。MIB是基于对象标识树的,对象标识是一个整数序列,中间以”.”分割,这些整数构成一个树型结构,类似于 DNS或Unix的文件系统,MIB被划分为若干个组,如system、 interfaces、 a t(地址转换)和ip组等。iso. org.dod.internet.private.enterprises(1.3 .6 .1.4.1)这个标识,是给厂家自定义而预留的,比如华为:1.3.6.1.4.1.2011,华三:1.3.6.1.4.1.25506

SNMP OID

OID 就是对象标识

snmpwalk工具可以使用SNMP的get请求查询指定OID入口的所有OID树信息。通过snmpwalk也可以查看支持SNMP协议(可网管)的设备的一些其他信息,比如cisco交换机或路由器IP地址、内存使用率等,也可用来协助开发SNMP功能

ubuntu中版本较新,这里以centos7为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$yum -y install net-snmp-utils
$snmpwalk -h
USAGE: snmpwalk [OPTIONS] AGENT [OID]
–h:显示帮助。
–v:指定snmp的版本, 1或者2c或者3。
–c:指定连接设备SNMP密码。 # 重点
–V:显示当前snmpwalk命令行版本。 # 重点,其实基本上也就只用这俩参数
–r:指定重试次数,默认为0次。
–t:指定每次请求的等待超时时间,单为秒,默认为3秒。
–l:指定安全级别:noAuthNoPriv|authNoPriv|authPriv。
–a:验证协议:MD5|SHA。只有-l指定为authNoPriv或authPriv时才需要。
–A:验证字符串。只有-l指定为authNoPriv或authPriv时才需要。
–x:加密协议:DES。只有-l指定为authPriv时才需要。
–X:加密字符串。只有-l指定为authPriv时才需要。

[root@zabbix-server ~]#snmpwalk -v 2c -c 123456 10.0.58.108 1.3.6.1.2.1.1.1
iso.3.6.1.2.1.1.1.0 = STRING: "Linux centos7 3.10.0-1127.el7.x86_64 #1 SMP Tue Mar 31 23:36:51 UTC 2020 x86_64"

[root@zabbix-server ~]#snmpwalk -v 2c -c 123456 10.0.58.108 1.3.6.1.2.1.1.5
iso.3.6.1.2.1.1.5.0 = STRING: "centos7"

配置zabbix

使用zabbix 自带的SNMP,要先修改团体名称,否则 会因为团体名不一致导致zabbix没有权限去获取被监控服务器的snmp利用率

监控 MySQL

监控MySQL连接数、主从同步、同步延迟等

percona-monitoring-plugins

percona 官方出了专门的监控管理软件,所以已经停止维护 percona-monitoring-plugins,以下使用旧的版本

  1. 监控脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [root@mysql-master src]$wget https://downloads.percona.com/downloads/percona-monitoring-plugins/percona-monitoring-plugins-1.1.8/binary/debian/artful/x86_64/percona-zabbix-templates_1.1.8-1.artful_all.deb

    $dpkg -c percona-zabbix-templates_1.1.8-1.artful_all.deb | awk '{print $NF}'
    ...
    ./var/lib/zabbix/percona/scripts/get_mysql_stats_wrapper.sh # 监控脚本,修改手动修改
    ./var/lib/zabbix/percona/scripts/ss_get_mysql_stats.php # 设置mysql的用户名和密码
    ./var/lib/zabbix/percona/templates/userparameter_percona_mysql.conf # userparameter
    ./var/lib/zabbix/percona/templates/zabbix_agent_template_percona_mysql_server_ht_2.0.9-sver1.1.8.xml # 模板文件,直接导入即可
    ...
    $dpkg -i percona-zabbix-templates_1.1.8-1.artful_all.deb

    $cp /var/lib/zabbix/percona/scripts/get_mysql_stats_wrapper.sh /usr/local/zabbix/data/
    $vim /var/lib/zabbix/percona/scripts/ss_get_mysql_stats.php
    <?php
    ...
    $mysql_user = 'root';
    $mysql_pass = '123456';
    ...
  2. 新建模板:直接导入zabbix_agent_template_percona_mysql_server_ht_2.0.9-sver1.1.8.xml即可

  3. 新建主机,并连接到刚创建的模板

自定义脚本监控MySQL

编写脚本监控脚本MySQL主从同步及延迟

slave机器上有两个关键的进程:

  • Slave_SQL_Running:负责自己的slave mysql进程
  • Slave_IO_Running:负责与主机的io通信
1
2
3
4
5
6
# 主从延迟,实际上只靠 Seconds_Behind_Master 这一个参数是不够的
mysql -uroot -p123456 -e "show slave status\G;" | grep "Seconds_Behind_Master:" | awk -F: '{print $2}'

mysql -uroot -e "show slave status\G;" | grep "Slave_IO_Running" | awk -F: '{print $2}' | sed 's/^[ \t]*//g'

mysql -uroot -e "show slave status\G;" | grep "Slave_SQL_Running:" | awk -F: '{print $2}' | sed 's/^[ \t]*//g'

自定义端口和进程监控

zabbix 内置相关key:

1
2
3
4
5
6
7
8
# 检查 TCP 端口 是否处于侦听状态。返回 0 - 未侦听;1 - 正在侦听
net.tcp.listen[port]
# 检查是否能建立 TCP 连接到指定端口。返回 0 - 不能连接;1 - 可以连接
net.tcp.port[<ip>,port]
# 检查服务是否运行并接受 TCP 连接。返回 0 - 服务关闭;1 - 服务运行
net.tcp.service[service,<ip>,<port>]
# 检查 TCP 服务的性能,当服务 down 时返回 0,否则返回连接服务花费的秒数
net.tcp.service.perf[service,<ip>,<port>]

故障自治愈功能

当zabbix 监控到指定的监控项异常的时候,通过指定的操作使故障自动恢复,通常是重启服务等一些简单的操作,也可以调用脚本执行比较复杂的操作

设置监控项和触发器,新建动作,在触发条件里面添加操作,在远程主机通过zabbix 客户端执行命令

  1. zabbix agent需要开启远程命令执行

    1
    2
    3
    # zabbix_agentd.conf
    EnableRemoteCommands=1 # 开启远程执行命令
    UnsafeUserParameters=1 # 允许远程执行命令的时候使用不安全的参数(特殊字符串)
  2. zabbix用户授权

    1
    2
    # /etc/sudoers
    zabbix ALL = NOPASSWD: ALL # 授权指定用户执行特殊命令不再需要密码,比如sudo等
  3. 创建动作
    配置–动作–创建动作

  4. 执行远程操作

  5. 验证自治愈功能

    将被测试的服务手动停止运行,验证能否自动启动或重启,更多操作可以远程执行脚本
    手动将Nginx、Tomcat等web服务停止后,验证zabbix agent能否自动启动或重启

grafana图形展示

grafana 本身只是一个图形显示工具,它独立于zabbix之外,通过zabbix提供的api获取数据,进行展示,其实不只是zabbix,它还可以搭配 prometheus、elasticsearch、mysql 等等,只要你提供数据,它都能给你展示出来

grafana 相比 zabbix 自带的web界面,更加好看

  1. 安装grafana服务
    https://grafana.com/grafana/download?platform=linux

    1
    2
    3
    sudo apt-get install -y adduser libfontconfig1
    wget https://dl.grafana.com/oss/release/grafana_7.4.2_amd64.deb
    sudo dpkg -i grafana_7.4.2_amd64.deb
  2. grafana安装并启用zabbix插件
    https://grafana.com/grafana/plugins/alexanderzobnin-zabbix-app

    1
    2
    3
    4
    5
    6
    7
    8
    grafana-cli plugins install alexanderzobnin-zabbix-app

    # 以上方式可能失败,推荐直接下载,然后移动到插件目录
    $wegt https://storage.googleapis.com/plugins-community/alexanderzobnin-zabbix-app/release/4.1.2/alexanderzobnin-zabbix-app-4.1.2.zip
    $unzip alexanderzobnin-zabbix-app-4.1.2.zip
    $mv alexanderzobnin-zabbix-app /var/lib/grafana/plugins/

    $systemctl restart grafana-server.service
  3. 启动zabbix插件

  4. 添加zabbix 数据源

    1. 添加mysql数据源

    2. 添加zabbix数据源

  5. 添加Dashboard

自定义基础监控模板

略…

结合pyhton脚本监控案例

kubernetes 集群状态监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
[root@kubernetes-master1 ~]# cat /usr/local/zabbix/data/k8s_monitor.py
#!/usr/bin/env python
#coding:utf-8
#Author ZhangShiJie

import subprocess
success_list = []
error_list= []
def get_status():
obj = subprocess.Popen(("curl -sXGET http://10.20.15.209:8080/api/v1/nodes"),shell=True, stdout=subprocess.PIPE)
data = obj.stdout.read()
data1 = eval(data)
data2 = data1.get('items')
#print data2
for i in data2:
data3 = i.get('status')
for i in data3.get('conditions'):
if i.get('reason') == 'KubeletReady':
if i.get('type') == "Ready":
if i.get('status') == 'True':
success_list.append(i.get('status'))
elif i.get('status') == 'False':
error_list.append(i.get('status'))
else:
break
else:
error_list.append(i.get('status'))
#pass
else:
error_list.append(i.get('status'))

def count_status():
if len(error_list) == 0:
print 50
else:
print 100

def main():
get_status()
count_status()

if __name__ == "__main__":
main()

# chmod a+x /usr/local/zabbix/data/k8s_monitor.py

监控MongodbDB复制集状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#cat /usr/local/zabbix/data/mongodb_cluster_monitor.py
#!/bin/env python
#coding:utf-8
#Author: ZhangShiJie

import subprocess
success_list = []
error_list= []

def get_mongodb_status():
obj = subprocess.Popen(("echo 'rs.status()' | /usr/local/mongodb/bin/mongo -u user -p wswd --authenticationDatabase admin \
| grep health | awk -F':' '{print $2}' | awk -F',' '{print $1}'"),shell=True, stdout=subprocess.PIPE)
restful = obj.stdout.read()
data = restful.split()
for i in data:
if i == "1":
success_list.append(i)
else:
error_list.append(i)

def count_status():
if len(error_list) > 0:
print 100
else:
print 50

def main():
get_mongodb_status()
count_status()

if __name__ == "__main__":
main()

#chmod a+x /usr/local/zabbix/data/redis_llen.py

监控Redis列表长度

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@redis ~]#cat /usr/local/zabbix/data/redis_llen.py
#!/usr/bin/env python
#coding:utf-8
#Author ZhangShijie
import redis
def redis_conn():
pool=redis.ConnectionPool(host="10.20.0.252",port=6379,db=0)
conn = redis.Redis(connection_pool=pool)
data = conn.llen('api4-nginx-accesslog')
print(data)
redis_conn()

[root@redis ~]# chmod a+x /usr/local/zabbix/data/redis_llen.py

监控ELK集群状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@elk-s1 ~]# vim /usr/local/zabbix/data/els_status.py

#!/usr/bin/env python
#coding:utf-8
#Author ZhangShijie

import subprocess
false="false"
obj = subprocess.Popen(("curl -sXGET http://10.20.3.128:9200/_cluster/health?
pretty=true"),shell=True, stdout=subprocess.PIPE)
data = obj.stdout.read()
data1 = eval(data)
status = data1.get("status")
if status == "green":
print "100"
else:
print "50"

[root@elk-s1 ~]# chmod a+x /usr/local/zabbix/data/els_status.py

监控RabbitMQ集群节点状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#cat /usr/local/zabbix/data/rabbit_cluster_monitor.py
#!/bin/env python
#coding:utf-8
#Author: ZhangShiJie

import subprocess
running_list = []
error_list = []
false="false"
true="true"
def get_status():
obj = subprocess.Popen(("curl -sXGET -u guest:guest http://10.20.3.171:15671/api/nodes"),shell=True,stdout=subprocess.PIPE)
data = obj.stdout.read()
data1 = eval(data)
for i in data1:
if i.get("running") == "true":
running_list.append(i.get("name"))
else:
error_list.append(i.get("name"))
def count_server():
if len(running_list) < 3: #可以判断错误列表大于0或者运行列表小于3,3未总计的节点数量
print 100 #100就是集群内有节点运行不正常了
else:
print 50 #50为所有节点全部运行正常
def main():
get_status()
count_server()
if __name__ == "__main__":
main()

#chmoa a+x /usr/local/zabbix/data/rabbit_cluster_monitor.py

Zabbix 事件通知机制

出现故障报警的时候,可以通过不同方式通知管理员进行故障处理,尽快恢复业务

1
2
3
# zabbix_server.conf
AlertScriptsPath=/usr/lib/zabbix/alertscripts #报警脚本路径
ExternalScripts=/usr/lib/zabbix/externalscripts #外部脚本路径

报警的最核心就是把报警媒介配置好,包括它前后的部分

  1. 添加报警媒介(邮件、短信、微信)
  2. 将报警媒介添加到动作的操作中,这样通过动作,就将触发器和报警媒介关联起来了
  3. 将报警媒介添加到用户,这样,当有触发器报警,就会通过报警媒介通知到用户

邮件通知

短信通知

微信通知

略..,和短信通知差不多

Zabbix 自动化运维

批量部署 Agent

使用agent,实现agent的自动化批量安装,可以通过源码或apt等方式安装

API

通过 zabbix web 进行的操作,都提供对应的API,可以通过编程的方式实现

API简介:https://www.zabbix.com/documentation/4.0/zh/manual/api
API列表:https://www.zabbix.com/documentation/4.0/zh/manual/api/reference

动态发现主机