更新
20240909
- 优化了监控日志按照 年月 目录存放
- 新增对同一个数据库多实例情况的巡检
简要说明
这个 shell 脚本用于数据库服务器上的日常检查:
- 系统检查:系统时间、CPU、内存、磁盘、IO
- 达梦数据库服务:实例、数据守护、集群状态
- 实例检查:日志是否出现 ERROR \ FATAL 等报错,出现报错则将报错信息重定向到存放报错的文件
这个 shell
脚本使用的命令都是平时工作中使用到的命令
特别是查看文件内容并输出指定的内容,使用 grep
awk
sed
cut
等命令结合。
复用性
此脚本直接拿到新机器执行,只需要修改 实例数据文件 的路径就可以了,虽然在脚本里可以实现查找实例数据文件,考虑到有的服务器上文件特别多,每次执行脚本都查找一遍,效率不好(虽然也不差这几秒)。
此外,达梦数据库的配置文件名称其实都是一致的,不需要修改
脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
|
#!/bin/bash
####################################################################################################
# Author: Wei Qi
# Remark: 1.系统检查:CPU、内存、磁盘、IO、网络、系统时间
# 2.数据库服务检查:实例、守护、监视器
# 3.实例检查:日志、会话
# 全局变量使用 VarName 方式命名,局部变量使用 var_name 方式命名
# CreateDate: 2024-07-23
# Version: 1.0
# ModifyDate:
# ModifyRemark:
####################################################################################################
###################################### 全局变量 手动修改 ############################################
# 服务、实例全局变量
# 服务配置文件名
DmIniName="dm.ini"
DmWatcherIniName="dmwatcher.ini"
DmMonitorIniName="dmmonitor.ini"
DmMalIniName="dmmal.ini"
# 配置备库 IP PORT
# TelnetIP="10.xx.xx.xxx"
# TelnetPORT="5236"
## 查找 数据库用户 的主目录
## cut -d: 是根据 : 进行分割 -f6 是返回分割后的第6列
# UserHomePath=$(getent passwd dmdba | cut -d: -f6)
# 有的实例数据文件不在主目录下,手动配置
UserHomePath="/u01/dmdata/zgfxq"
# 定义变量,实例配置文件路径
FindDmIniPath=$(find ${UserHomePath} -name ${DmIniName})
DmIniPath=${FindDmIniPath}
# DmIniPath=$(find / -name "dm.ini")
# FindDmWatcherIniPath=$(find ${UserHomePath} -name ${DmWatcherIniName})
# DmWatcherIniPath=${FindDmWatcherIniPath}
# FindDmMonitorIniPath=$(find ${UserHomePath} -name ${DmMonitorIniName})
# DmMonitorIniPath=${FindDmMonitorIniPath}
FindDmMalIniPath=$(find ${UserHomePath} -name ${DmMalIniName})
DmMalIniPath=${FindDmMalIniPath}
echo "DmIniPath : ${DmIniPath}"
echo "DmMalIniPath : ${DmMalIniPath}"
# 定义达梦各服务端口变量
# grep -w 使用精准匹配
AllDmServicePort=$(cat "${DmIniPath}" | grep -w PORT_NUM | awk '{print $3}') # 数据实例端口
AllDmWatcherPort=$(cat "${DmMalIniPath}" | grep -w MAL_DW_PORT | awk '{print $3}') # 数据守护进程端口
echo "AllDmServicePort : ${AllDmServicePort}"
echo "AllDmWatcherPort : ${AllDmWatcherPort}"
# 获取实例名称
DmInstanceName=$(cat "${DmIniPath}" | grep -w INSTANCE_NAME | awk '{print $3}')
# 获取当前 IP
# GetSystemIp=$(hostname -I)
####################################################################################################
# 巡检开始
echo "巡检脚本开始"
########################################## 系统巡检 ################################################
# 系统时间检查
getSystemTime() {
current_time=$(date)
echo "当前系统时间: ${current_time}"
echo ""
}
# 当前系统信息
getOsSystem() {
os_type=$(uname)
os_hostname=$(hostname)
os_ip=$(hostname -I | awk '{print $1}')
echo "当前机器:${os_type} | ${os_hostname} | ${os_ip}"
echo ""
}
# 获取CPU使用率
getCpuUsage() {
# 使用 bn1 获取固定的 top 输出
cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
echo "CPU使用率: ${cpu_usage}%"
echo ""
}
# 获取内存使用率
getMemUsage() {
mem_total=$(free -h | grep Mem | awk '{print $2}')
mem_used=$(free -h | grep Mem | awk '{print $3}')
mem_usage=$(free -h | grep Mem | awk '{print$3/$2 * 100.0}')
echo "内存总量:${mem_total}; 内存使用:${mem_used}; 内存使用率: ${mem_usage}%"
echo ""
}
# 获取磁盘空间使用情况
getDiskUsage() {
echo "磁盘空间使用情况:"
# 获取标题行
# df -h | head -n 1
# 排除这些盘,并循环打印排除后的每一行
df -h | grep -vE '^Filesystem|tmpfs|cdrom' | while read line
do
echo "${line}"
done
echo ""
}
# 获取磁盘IO监控数据
getIoStat() {
echo "磁盘IO情况: "
iostat
# 判断 iowait 值
iostatIowait=$(iostat | awk '/^avg-cpu/ {getline; print$4 * 100.0}')
if [[ $iostatIowait -ge 80 ]]; then
echo "磁盘 IO ${iostatIowait}% 大于 80%,可能存在 IO 瓶颈"
else
echo "磁盘 IO ${iostatIowait}% 正常"
fi
# 判断 idel 值
iostatIdel=$(iostat | awk '/^avg-cpu/ {getline; print$6}')
# bash 只支持整数比较, 采用 bc 进行判断是否为 true, true = 1 则返回
# if [[ $iostatIdel -ge 80 ]]; then
if [[ $(echo "$iostatIdel >= 80" | bc) -eq 1 ]]; then
echo "当前 CPU ${iostatIdel}% 资源充足"
elif [[ $(echo "$iostatIdel <= 10"| bc) -eq 1 ]]; then
echo "当前 CPU ${iostatIdel}% 资源紧张"
else
echo "当前 CPU ${iostatIdel}% 资源适中"
fi
echo ""
}
# 获取网络资源监控数据
# getNetwork() {
# echo "网络接口流量统计(单位: KB/s): "
# sar -n DEV 1 1 | grep Average
# echo ""
# }
########################################## 服务巡检 ################################################
echo "服务检查开始 --------------------------- "
# 达梦数据库服务
getDatabaseService() {
dm_service=$(ps -ef | grep dmserver | grep "${DmIniName}" | grep -v grep | awk '{print $1,$2}')
dm_service_port=$(netstat -nltp | grep "${AllDmServicePort}" | awk '{print $4}' | cut -d: -f4)
# 检查变量是否非空
if [ -n "${dm_service}" ] && [ -n "${dm_service_port}" ]; then
echo "当前用户、进程 PID : ${dm_service}, 端口:${dm_service_port} | dm 正常"
else
echo "没有找到 达梦服务 进程"
fi
}
# 达梦数据守护服务
getDatabaseWatcher() {
dm_watcher=$(ps -ef | grep "${DmWatcherIniName}" | grep -v grep | awk '{print $1,$2}')
dm_watcher_port=$(netstat -nltp | grep "${AllDmWatcherPort}" | awk '{print $4}' | cut -d: -f4)
# 检查变量是否非空
if [ -n "${dm_watcher}" ] && [ -n "${dm_watcher_port}" ]; then
echo "当前用户、进程 PID : ${dm_watcher} | dmwatcher 正常"
else
echo "没有找到 达梦数据守护 进程"
fi
}
# 达梦确认监视器服务
getDatabaseMonitor() {
dm_monitor=$(ps -ef | grep ${DmMonitorIniName} | grep -v grep | awk '{print $1,$2}')
# 检查变量是否非空
if [ -n "${dm_monitor}" ]; then
echo "当前用户、进程 PID : ${dm_monitor} | dmmonitor 正常"
else
echo "没有找到 达梦监视器 进程"
fi
}
# 主备网络连通
# getDatabaseTelnetIpPort() {
# telnet "${TelnetIP}" "${TelnetPORT}"
# if [ $? -eq 0 ]; then
# echo "达梦端口连通正常"
# else
# echo "达梦端口连通失败!!!"
# fi
# }
########################################## 实例巡检 ################################################
# 日志检查
# 变量
# 实例路径(用户主目录)
DmServicePath=$(getent passwd dmdba | cut -d: -f6)
# 获取当前目录
PwdPath=$(cd "$(dirname "$0")" || exit; pwd)
echo "PwdPath : ${PwdPath}"
# 获取当前日期
CurrentYearMonth=$(date +%Y%m)
CurrentYearMonthDay=$(date +%Y-%m-%d)
# 检查目录文件是否存在, 不存在则创建,用于存放 ErrorLog
LogPathName="dmErrorLog"
LogFileName="dm_error_log_$(date +%Y%m%d).log"
# 判断目录文件
getCreateDir() {
if [ ! -d "${PwdPath}/${LogPathName}" ]; then
mkdir -p "${PwdPath}/${LogPathName}"
echo "日志目录已创建"
else
echo "日志目录已存在"
fi
}
getCreateFile() {
if [ ! -f "${PwdPath}/${LogPathName}/${LogFileName}" ]; then
touch "${PwdPath}/${LogPathName}/${LogFileName}"
echo "日志文件已创建"
else
echo "日志文件已存在"
fi
}
echo "实例检查开始 --------------------------- "
# 会话数量
getMaxSession() {
max_session=$(netstat -nat | awk '{print $4}' | grep 5236 | wc -l)
# 引用配置文件路径变量
cat_dmini_max_session=$(cat ${DmIniPath} | grep MAX_SESSIONS | awk '{print $3}')
echo "当前会话数量:${max_session}, 达梦最大会话数量:${cat_dmini_max_session}, 活动会话占比:${max_session}/${cat_dmini_max_session}"
echo ""
}
# 实例日志
getDmServiceLog() {
dmservice_log_full_path="${DmServicePath}/dmdbms/log/dm_${DmInstanceName}_${CurrentYearMonth}.log"
cat_dmservice_error_log=$(cat ${dmservice_log_full_path} | grep -e '\[ERROR]' -e '\[FATAL]' | grep ${CurrentYearMonthDay})
if [ $? -eq 0 ]; then
save_dmserver_error_log="${PwdPath}/${LogPathName}/${LogFileName}"
echo "${cat_dmservice_error_log}" >> "${save_dmserver_error_log}"
if [ -s "${save_dmserver_error_log}" ]; then
echo "警告:今天 ${CurrentYearMonthDay} 数据库实例日志已写入"
echo "================ ${CurrentYearMonthDay} : dm_${DmInstanceName}_${CurrentYearMonth}.log 写入完成 =======================" >> ${save_dmserver_error_log}
else
echo "数据库实例日志无新内容"
fi
else
echo "正常:${CurrentYearMonthDay} 数据库实例日志 dm_server 无 Error or Fatal"
fi
# echo ""
}
# 数据守护日志
getDmWatcherLog() {
dmwatcher_log_full_path="${DmServicePath}/dmdbms/log/dm_dmwatcher_${DmInstanceName}_${CurrentYearMonth}.log"
cat_dmwatcher_error_log=$(cat ${dmwatcher_log_full_path} | grep -e '\[ERROR]' -e '\[FATAL]' | grep ${CurrentYearMonthDay})
# 有输出内容则返回状态码 0 ,表示成功匹配到了相应的内容
if [ $? -eq 0 ]; then
save_dmserver_error_log="${PwdPath}/${LogPathName}/${LogFileName}"
echo "${cat_dmwatcher_error_log}" >> "${save_dmserver_error_log}"
if [ -s "${save_dmserver_error_log}" ]; then
echo "警告:今天 ${CurrentYearMonthDay} 数据守护日志已写入"
echo "================= ${CurrentYearMonthDay} : dm_dmwatcher_${DmInstanceName}_${CurrentYearMonth}.log 写入完成 ======================= " >> ${save_dmserver_error_log}
else
echo "数据守护日志无新内容"
fi
else
echo "正常:${CurrentYearMonthDay} 数据守护进程日志 dm_watcher 无 Error or Fatal"
fi
# echo ""
}
# 监视器(检查集群状态)
getDmMonitorLog() {
dmmonitor_log_full_path="${DmServicePath}/dmdbms/log/"
save_dmserver_error_log="${PwdPath}/${LogPathName}/${LogFileName}"
# ls -lt 按修改时间,正序排序, head -n 1 显示第一个文件(最新文件)
dmmonitor_log_new_head=$(ls -lt "${dmmonitor_log_full_path}" | grep dmmonitor | head -n 1 | awk '{print $9}')
# 从 dmmal.ini 获取集群各个节点IP
# grep -n 打印行号, -w 输出相关的行内容
get_dmgroup_ip_a=$(cat "${DmMalIniPath}" | grep -n MAL_INST_HOST | grep -w 8 | awk '{print $3}')
get_dmgroup_ip_b=$(cat "${DmMalIniPath}" | grep -n MAL_INST_HOST | grep -w 18 | awk '{print $3}')
# 需要绝对路径,不然找不到这个日志名
cat_dmmonit_status=$(tail -n 35 "${dmmonitor_log_full_path}/${dmmonitor_log_new_head}")
# awk 使用 ip1 和 ip2 存储 集群IP 信息,找到第 5 列 ISTATUS 的值
# 使用正确的方式传递变量给 awk 。 这里将这个变量的输出内容 <<< 传给 awk 命令
check_dmmonitor_status=$(awk -v ip1="${get_dmgroup_ip_a}" -v ip2="${get_dmgroup_ip_b}" '$1 == ip1 { istatus1 = $5 }$1 == ip2 { istatus2 = $5 } END { print istatus1, istatus2 }' <<< "${cat_dmmonit_status}")
# 检查 istatus1 和 istatus2 的值
if [[ $check_dmmonitor_status == *"OPEN"* ]]; then
echo "正常:集群节点服务状态为 OPEN"
else
echo "警告:集群节点服务状态不为 OPEN"
# 如果服务异常,将状态写入日志文件
echo "警告:${CurrentYearMonthDay} 集群节点服务状态异常 -${check_dmmonitor_status}" >> ${save_dmserver_error_log}
echo "================= ${CurrentYearMonthDay} : dmmonitor_${DmInstanceName}_${CurrentYearMonth}.log 写入完成 ======================= " >> ${save_dmserver_error_log}
fi
echo ""
}
# 保存巡检报告
report_file="/opt/checkDayBash/log/system_check_$(date +%Y%m%d%H%M%S).log"
{
echo "============================== 系统巡检 =============================="
getSystemTime # ok
getOsSystem # ok
getCpuUsage # ok
getMemUsage # ok
getDiskUsage # ok
getIoStat # ok
# getNetwork # ok
echo ""
echo "=========================== 数据库服务巡检 ==========================="
getDatabaseService # ok
getDatabaseWatcher # ok
getDatabaseMonitor # ok
# getDatabaseTelnetIpPort # ok
echo ""
echo "============================== 实例巡检 =============================="
getCreateDir
getCreateFile
echo "日志检查: "
echo ""
getDmServiceLog # ok
getDmWatcherLog # ok
getDmMonitorLog # ok
getMaxSession # ok
} > "${report_file}"
echo "巡检脚本结束"
echo "巡检报告已保存至 ${report_file}"
|
效果
查看巡检报告
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
|
============================== 系统巡检 ==============================
当前系统时间: 2024年 07月 26日 星期五 08:37:26 CST
当前机器:Linux | YD-FXQDB01-3-161 | 1X.XXX.XXX.161
CPU使用率: 0.2%
内存总量:254Gi; 内存使用:37Gi; 内存使用率: 14.5669%
磁盘空间使用情况:
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/klas-root 860G 107G 754G 13% /
/dev/sda2 1014M 194M 821M 20% /boot
/dev/sda1 511M 6.5M 505M 2% /boot/efi
/dev/loop0 1.1G 1.1G 0 100% /mnt/dmrom
磁盘IO情况:
Linux 4.19.90-24.4.v2101.ky10.aarch64 (YD-FXQDB01-3-161) 2024年07月26日 _aarch64_ (64 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.03 0.00 0.02 0.00 0.00 99.95
Device tps kB_read/s kB_wrtn/s kB_dscd/s kB_read kB_wrtn kB_dscd
dm-0 6.61 0.23 369.90 0.00 863876 1365033852 0
loop0 0.00 0.46 0.00 0.00 1686907 0 0
sda 6.39 0.24 369.90 0.00 887725 1365036529 0
磁盘 IO 0% 正常
当前 CPU 99.95% 资源充足
=========================== 数据库服务巡检 ===========================
当前用户、进程 PID : dmdba 2834456, 端口:5236 | dm 正常
当前用户、进程 PID : dmdba 2616858 | dmwatcher 正常
当前用户、进程 PID : dmdba 2617379 | dmmonitor 正常
============================== 实例巡检 ==============================
日志目录已存在
日志文件已创建
日志检查:
正常:2024-07-26 数据库实例日志 dm_server 无 Error or Fatal
正常:2024-07-26 数据守护进程日志 dm_watcher 无 Error or Fatal
正常:集群节点服务状态为 OPEN
当前会话数量:79, 达梦最大会话数量:5000, 活动会话占比:79/5000
|
脚本 20240911
在函数内部定义一个参数,用来传入数组里的变量,实现循环的效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
|
#!/bin/bash
#####################################################################################
# Author: Wei Qi
# Remark: 1.系统检查:CPU、内存、磁盘、IO、网络、系统时间
# 2.数据库服务检查:实例、守护、监视器
# 3.实例检查:日志、会话
# 全局变量使用 VarName 方式命名,局部变量使用 var_name 方式命名
# CreateDate: 2024-07-23
# Version: 2.0
# Modify: 2024-09-11 1.采用循环传参的方式,增加检查第二个数据库实例的数据库服务状态、日志、会话
# 2.优化日志输出,以年月为一个目录存放
#####################################################################################
################################ 全局变量 手动修改 #####################################
# 数据库实例
DBInstanceName=("AMOP"
"zgfxq"
)
# 数据库实例配置文件
DmIniName="dm.ini"
DmWatcherIniName="dmwatcher.ini"
DmMalIniName="dmmal.ini"
DmMonitorIniName="dmmonitor.ini"
# 数据库服务路径
DmServicePath=$(getent passwd dmdba | cut -d: -f6)
############################### 判断目录是否创建 #####################################
# 创建存放日志的文件
# 获取当前目录
PwdPath=$(cd "$(dirname "$0")" || exit; pwd)
# 获取当前日期
CurrentYearMonth=$(date +%Y%m)
CurrentYearMonthDay=$(date +%Y-%m-%d)
# 检查目录文件是否存在, 不存在则创建,用于存放 ErrorLog
LogPathName="dmErrorLog"
LogFileName="dm_error_log_$(date +%Y%m%d).log"
# 创建存放达梦日志的错误输出文件
getCreateDirDm() {
if [ ! -d "${PwdPath}/${LogPathName}/${CurrentYearMonth}" ]; then
mkdir -p "${PwdPath}/${LogPathName}/${CurrentYearMonth}"
echo "[OK] 达梦日志记录目录已创建"
else
echo "[WARNING] 达梦日志记录目录已创建"
fi
}
getCreateFileDm() {
if [ ! -f "${PwdPath}/${LogPathName}/${CurrentYearMonth}/${LogFileName}" ]; then
touch "${PwdPath}/${LogPathName}/${CurrentYearMonth}/${LogFileName}"
echo "[OK] 达梦日志文件已创建"
else
echo "[WARNING] 达梦日志文件已存在"
fi
}
# 创建存放巡检日志的文件
getCreateDirLog() {
if [ ! -d "${PwdPath}/log/${CurrentYearMonth}" ]; then
mkdir -p "${PwdPath}/log/${CurrentYearMonth}"
echo "[OK] 巡检日志目录已创建"
else
echo "[WARNING] 巡检日志目录已存在"
fi
}
#################################### 服务巡检 #########################################
# 达梦数据库服务
getDatabaseService() {
local service=$1
local service_port=$2
dm_service=$(ps -ef | grep ${service} | grep "${DmIniName}" | grep -v grep | awk '{print $1,$2}')
dm_service_port=$(netstat -nltp | grep "${service_port}" | awk '{print $4}' | cut -d: -f4)
# 检查变量是否非空
if [ -n "${dm_service}" ] && [ -n "${dm_service_port}" ]; then
echo "[OK] 当前用户、进程 PID : ${dm_service}, 端口:${dm_service_port} | dm 正常"
else
echo "[WARNING] 没有找到达梦服务进程"
fi
}
# 达梦数据守护服务
getDatabaseWatcher() {
local service=$1
local service_port=$2
dm_watcher=$(ps -ef | grep ${service} | grep "${DmWatcherIniName}" | grep -v grep | awk '{print $1,$2}')
dm_watcher_port=$(netstat -nltp | grep "${service_port}" | awk '{print $4}' | cut -d: -f4)
# 检查变量是否非空
if [ -n "${dm_watcher}" ] && [ -n "${dm_watcher_port}" ]; then
echo "[OK] 当前用户、进程 PID : ${dm_watcher} | dmwatcher 正常"
else
echo "[WARNING] 没有找到达梦数据守护进程"
fi
}
# 达梦确认监视器服务
getDatabaseMonitor() {
local service=$1
# 检查达梦确认监视器进程
dm_monitor=$(ps -ef | grep ${service} | grep ${DmMonitorIniName} | grep -v grep | awk '{print $1,$2}')
# 检查变量是否非空
if [ -n "${dm_monitor}" ]; then
echo "[OK] 当前用户、进程 PID : ${dm_monitor} | dmmonitor 正常"
else
echo "[WARNING] 没有找到达梦监视器进程"
fi
}
#################################### 实例巡检 #########################################
# 会话数量
getMaxSession() {
local DBServicePort=$1
max_session=$(netstat -nat | awk '{print $4}' | grep "${DBServicePort}" | wc -l)
# 引用配置文件路径变量
cat_dmini_max_session=$(cat "${DBInstanceNameProfilePath}/${DmIniName}" | grep MAX_SESSIONS | awk '{print $3}')
echo "当前会话数量:${max_session}, 达梦最大会话数量:${cat_dmini_max_session}, 活动会话占比:${max_session}/${cat_dmini_max_session}"
echo ""
}
# 实例日志
getDmServiceLog() {
local DBInstanceName=$1
dmservice_log_full_path="${DmServicePath}/dmdbms/log/dm_${DBInstanceName}_${CurrentYearMonth}.log"
cat_dmservice_error_log=$(cat ${dmservice_log_full_path} | grep -e '\[ERROR]' -e '\[FATAL]' | grep ${CurrentYearMonthDay})
if [ $? -eq 0 ]; then
save_dmserver_error_log="${PwdPath}/${LogPathName}/${CurrentYearMonth}/${LogFileName}"
echo "${cat_dmservice_error_log}" >> "${save_dmserver_error_log}"
if [ -s "${save_dmserver_error_log}" ]; then
echo "[WARNING] 今天 ${CurrentYearMonthDay} 数据库实例日志已写入"
echo "================ ${CurrentYearMonthDay} : dm_${DBInstanceName}_${CurrentYearMonth}.log 写入完成 =======================" >> ${save_dmserver_error_log}
else
echo "数据库实例日志无新内容"
fi
else
echo "[OK] ${CurrentYearMonthDay} 数据库实例日志 dm_server 无 Error or Fatal. 扫描日志文件: ${dmservice_log_full_path}"
fi
# echo ""
}
# 数据守护日志
getDmWatcherLog() {
local DBInstanceName=$1
dmwatcher_log_full_path="${DmServicePath}/dmdbms/log/dm_dmwatcher_${DBInstanceName}_${CurrentYearMonth}.log"
cat_dmwatcher_error_log=$(cat ${dmwatcher_log_full_path} | grep -e '\[ERROR]' -e '\[FATAL]' | grep ${CurrentYearMonthDay})
# 有输出内容则返回状态码 0 ,表示成功匹配到了相应的内容
if [ $? -eq 0 ]; then
save_dmserver_error_log="${PwdPath}/${LogPathName}/${CurrentYearMonth}/${LogFileName}"
echo "${cat_dmwatcher_error_log}" >> "${save_dmserver_error_log}"
if [ -s "${save_dmserver_error_log}" ]; then
echo "[WARNING] 今天 ${CurrentYearMonthDay} 数据守护日志已写入"
echo "================= ${CurrentYearMonthDay} : dm_dmwatcher_${DBInstanceName}_${CurrentYearMonth}.log 写入完成 ======================= " >> ${save_dmserver_error_log}
else
echo "数据守护日志无新内容"
fi
else
echo "[OK] ${CurrentYearMonthDay} 数据守护进程日志 dm_watcher 无 Error or Fatal. 扫描日志文件: ${dmwatcher_log_full_path}"
fi
# echo ""
}
# 监视器(检查集群状态)
getDmMonitorLog() {
dmmonitor_log_full_path="${DmServicePath}/dmdbms/log"
# ls -lt 按修改时间,正序排序, head -n 1 显示第一个文件(最新文件)
dmmonitor_log_new_head=$(ls -lt "${dmmonitor_log_full_path}" | grep dmmonitor | head -n 1 | awk '{print $9}')
# 从 dmmal.ini 获取集群各个节点IP
# grep -n 打印行号, -w 输出相关的行内容
get_dmgroup_ip_a=$(cat "${DBInstanceNameProfilePath}${DmMalIniName}" | grep -n MAL_INST_HOST | grep -w 8 | awk '{print $3}')
get_dmgroup_ip_b=$(cat "${DBInstanceNameProfilePath}${DmMalIniName}" | grep -n MAL_INST_HOST | grep -w 18 | awk '{print $3}')
# 需要绝对路径,不然找不到这个日志名
cat_dmmonit_status=$(tail -n 35 "${dmmonitor_log_full_path}/${dmmonitor_log_new_head}")
# awk 使用 ip1 和 ip2 存储 集群IP 信息,找到第 5 列 ISTATUS 的值
# 使用正确的方式传递变量给 awk 。 这里将这个变量的输出内容 <<< 传给 awk 命令
check_dmmonitor_status=$(awk -v ip1="${get_dmgroup_ip_a}" -v ip2="${get_dmgroup_ip_b}" '$1 == ip1 { istatus1 = $5 }$1 == ip2 { istatus2 = $5 } END { print istatus1, istatus2 }' <<< "${cat_dmmonit_status}")
# 检查 istatus1 和 istatus2 的值
if [[ $check_dmmonitor_status == *"OPEN"* ]]; then
echo "[OK] 集群节点服务状态为 OPEN"
else
echo "[WARNING] 集群节点服务状态: 非 OPEN 状态"
fi
echo ""
}
#################################### 系统巡检 ########################################
# 系统时间检查
getSystemTime() {
current_time=$(date)
echo "当前系统时间: ${current_time}"
echo ""
}
# 当前系统信息
getOsSystem() {
os_type=$(uname)
os_hostname=$(hostname)
os_ip=$(hostname -I | awk '{print $1}')
echo "当前机器:${os_type} | ${os_hostname} | ${os_ip}"
echo ""
}
# 获取CPU使用率
getCpuUsage() {
# 使用 bn1 获取固定的 top 输出
cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
echo "CPU使用率: ${cpu_usage}%"
echo ""
}
# 获取内存使用率
getMemUsage() {
mem_total=$(free -h | grep Mem | awk '{print $2}')
mem_used=$(free -h | grep Mem | awk '{print $3}')
mem_usage=$(free -h | grep Mem | awk '{print$3/$2 * 100.0}')
echo "内存总量:${mem_total}; 内存使用:${mem_used}; 内存使用率: ${mem_usage}%"
echo ""
}
# 获取磁盘空间使用情况
getDiskUsage() {
echo "磁盘空间使用情况:"
# 获取标题行
# df -h | head -n 1
# 排除这些盘,并循环打印排除后的每一行
df -h | grep -vE '^Filesystem|tmpfs|cdrom' | while read line
do
echo "${line}"
done
echo ""
}
# 获取磁盘IO监控数据
getIoStat() {
echo "磁盘IO情况: "
iostat
# 判断 iowait 值
iostatIowait=$(iostat | awk '/^avg-cpu/ {getline; print$4 * 100.0}')
if [[ $iostatIowait -ge 80 ]]; then
echo "磁盘 IO ${iostatIowait}% 大于 80%,可能存在 IO 瓶颈"
else
echo "磁盘 IO ${iostatIowait}% 正常"
fi
# 判断 idel 值
iostatIdel=$(iostat | awk '/^avg-cpu/ {getline; print$6}')
# bash 只支持整数比较, 采用 bc 进行判断是否为 true, true = 1 则返回
# if [[ $iostatIdel -ge 80 ]]; then
if [[ $(echo "$iostatIdel >= 80" | bc) -eq 1 ]]; then
echo "当前 CPU ${iostatIdel}% 资源充足"
elif [[ $(echo "$iostatIdel <= 10"| bc) -eq 1 ]]; then
echo "当前 CPU ${iostatIdel}% 资源紧张"
else
echo "当前 CPU ${iostatIdel}% 资源适中"
fi
echo ""
}
#################################### 脚本运行 #########################################
echo "脚本开始 $(date +%Y-%m-%d_%H:%M:%S)"
getCreateDirDm
getCreateFileDm
getCreateDirLog
report_file="/opt/checkDayBash/log/${CurrentYearMonth}/system_check_$(date +%Y%m%d_%H%M%S).log"
{
echo "============================== 系统巡检 =============================="
getSystemTime
getOsSystem
getCpuUsage
getMemUsage
getDiskUsage
getIoStat
echo "============================== 数据库巡检 =============================="
for service in "${DBInstanceName[@]}"; do
# 当前实例名
echo "当前实例名 ${service}: " >> "${report_file}"
# 实例配置文件路径
DBInstanceNameProfilePath=$(ps -ef | grep dmserver | grep "${service}" | grep -v grep | awk '{print $9}' | cut -d= -f2 | sed 's/\dm.ini//')
# 数据库实例端口
DBServicePort=$(cat "${DBInstanceNameProfilePath}${DmIniName}" | grep -w PORT_NUM | awk '{print $3}')
DBWatcherPort=$(cat "${DBInstanceNameProfilePath}${DmMalIniName}" | grep -w MAL_DW_PORT | awk '{print $3}')
# echo "数据库实例端口:${DBServicePort}"
# echo "守护端口:${DBWatcherPort}"
echo "# 服务巡检"
getDatabaseService "${service}" "${DBServicePort}"
getDatabaseWatcher "${service}" "${DBWatcherPort}"
getDatabaseMonitor "${service}"
echo "# 实例巡检"
getMaxSession "${DBServicePort}"
getDmServiceLog "${service}"
getDmWatcherLog "${service}"
getDmMonitorLog
done
} >> "${report_file}"
echo "脚本结束 $(date +%Y-%m-%d_%H:%M:%S)"
|
效果
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
|
[root@YD-FXQDB01-3-161 202409]# cat system_check_20240913_090114.log
============================== 系统巡检 ==============================
当前系统时间: 2024年 09月 13日 星期五 09:01:14 CST
当前机器:Linux | YD-FXQDB01-3-161 | 1XX.XXX.XXX.161
CPU使用率: 0.2%
内存总量:254Gi; 内存使用:49Gi; 内存使用率: 19.2913%
磁盘空间使用情况:
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/klas-root 860G 127G 733G 15% /
/dev/sda2 1014M 194M 821M 20% /boot
/dev/sda1 511M 6.5M 505M 2% /boot/efi
/dev/loop0 1.1G 1.1G 0 100% /mnt/dmrom
磁盘IO情况:
Linux 4.19.90-24.4.v2101.ky10.aarch64 (YD-FXQDB01-3-161) 2024年09月13日 _aarch64_ (64 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.05 0.00 0.02 0.00 0.00 99.93
Device tps kB_read/s kB_wrtn/s kB_dscd/s kB_read kB_wrtn kB_dscd
dm-0 8.32 0.11 501.58 0.00 868852 3975183572 0
loop0 0.00 0.21 0.00 0.00 1686907 0 0
sda 8.12 0.11 501.58 0.00 892701 3975186249 0
磁盘 IO 0% 正常
当前 CPU 99.93% 资源充足
============================== 数据库巡检 ==============================
当前实例名 AMOP:
# 服务巡检
[OK] 当前用户、进程 PID : dmdba 2750927, 端口:5237 | dm 正常
[WARNING] 没有找到达梦数据守护进程
[WARNING] 没有找到达梦监视器进程
# 实例巡检
当前会话数量:128, 达梦最大会话数量:10000, 活动会话占比:128/10000
[OK] 2024-09-13 数据库实例日志 dm_server 无 Error or Fatal. 扫描日志文件: /home/dmdba/dmdbms/log/dm_AMOP_202409.log
[OK] 2024-09-13 数据守护进程日志 dm_watcher 无 Error or Fatal. 扫描日志文件: /home/dmdba/dmdbms/log/dm_dmwatcher_AMOP_202409.log
[WARNING] 集群节点服务状态: 非 OPEN 状态
当前实例名 zgfxq:
# 服务巡检
[OK] 当前用户、进程 PID : dmdba 2834456, 端口:5236 | dm 正常
[OK] 当前用户、进程 PID : dmdba 2616858 | dmwatcher 正常
[OK] 当前用户、进程 PID : dmdba 2617379 | dmmonitor 正常
# 实例巡检
当前会话数量:110, 达梦最大会话数量:5000, 活动会话占比:110/5000
[OK] 2024-09-13 数据库实例日志 dm_server 无 Error or Fatal. 扫描日志文件: /home/dmdba/dmdbms/log/dm_zgfxq_202409.log
[OK] 2024-09-13 数据守护进程日志 dm_watcher 无 Error or Fatal. 扫描日志文件: /home/dmdba/dmdbms/log/dm_dmwatcher_zgfxq_202409.log
[OK] 集群节点服务状态为 OPEN
|