1.需求背景

系统程序突然报错,报错信息如下:

The transaction log for database '@dbname' is full. To find out why space in the log cannot be reused, see the log_reuse_wait_desc column in sys.databases

此时查看log文件,已达2T。

当时的紧急处理方案是,移除掉镜像,修改数据库恢复模式(由full修改为simple),收缩日志。

为了防止类似问题再次发生,需对log 文件的大小进行监控,当到达阈值后,触发告警。

2.主要基础组件(类)

配置文件 qqmssqltest_db_server_conf.ini

同过此配置文件获取DB Server信息、DB信息、UID信息、邮件服务器信息等。

[sqlserver]
db_user = XXXXXX
db_pwd = XXXXXXX [sqlserver_qq]
db_host = 110.119.120.114
db_port = 1433 [windows]
user =
pwd = [mail]
host = zheshiceshidemail.qq.com
port = 25
user =
pwd =
sender = zhejiushiceshidebuyaodangzhen@qq.com

获取连接串的组件mssql_get_db_connect.py

# -*- coding: utf-8 -*-

import sys
import os
import datetime
import configparser
import pymssql
# pip3 install pymssql-2.1.4-cp37-cp37m-win_amd64.whl
# pip3 install pymssql -i https://pypi.doubanio.com/simple # 获取连接串信息
def mssql_get_db_connect(db_host, db_port):
db_host = db_host
db_port = db_port db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
config = configparser.ConfigParser()
config.read(db_ps_file, encoding="utf-8")
db_user = config.get('sqlserver', 'db_user')
db_pwd = config.get('sqlserver', 'db_pwd') conn = pymssql.connect(host=db_host, port=db_port, user=db_user, password=db_pwd, charset="utf8", login_timeout=5, timeout=600, autocommit=True) return conn

执行SQL语句的组件mysql_exec_sql.py

# -*- coding: utf-8 -*-

import mysql_get_db_connect

def mysql_exec_dml_sql(db_host, db_port, exec_sql):
conn = mysql_get_db_connect.mysql_get_db_connect(db_host, db_port)
with conn.cursor() as cursor_db:
cursor_db.execute(exec_sql)
conn.commit() def mysql_exec_select_sql(db_host, db_port, exec_sql):
conn = mysql_get_db_connect.mysql_get_db_connect(db_host, db_port)
with conn.cursor() as cursor_db:
cursor_db.execute(exec_sql)
sql_rst = cursor_db.fetchall() return sql_rst def mysql_exec_select_sql_include_colnames(db_host, db_port, exec_sql):
conn = mysql_get_db_connect.mysql_get_db_connect(db_host, db_port)
with conn.cursor() as cursor_db:
cursor_db.execute(exec_sql)
sql_rst = cursor_db.fetchall()
col_names = cursor_db.description
return sql_rst, col_names

发邮件的功能send_monitor_mail.py

# -*- coding: utf-8 -*-

# pip3 install PyEmail
import smtplib
from email.mime.text import MIMEText
import configparser
import os
import sys # 发送告警邮件
def send_monitor_mail(mail_subject, mail_body, mail_receivers="testwukongbaigujing@qq.com"):
db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
config = configparser.ConfigParser()
config.read(db_ps_file, encoding="utf-8")
mail_host = config.get('mail', 'host')
mail_port = config.get('mail', 'port')
# mail_user = config.get('mail', 'user')
# mail_pwd = config.get('mail', 'pwd')
sender = config.get('mail', 'sender')
# receivers = config.get('mail', 'receivers') # 发送HTML格式邮件
message = MIMEText(mail_body, 'html', 'utf-8')
# message = MIMEText(mail_body, 'plain', 'utf-8')
message['subject'] = mail_subject
message['From'] = sender
message['To'] = mail_receivers try:
smtpObj = smtplib.SMTP()
smtpObj.connect(mail_host, mail_port) # 25 为 SMTP 端口号
# SMTP AUTH extension not supported by server.
# https://github.com/miguelgrinberg/microblog/issues/76
# smtpObj.ehlo()
# smtpObj.starttls()
# smtpObj.login(mail_user, mail_pwd)
smtpObj.sendmail(sender, mail_receivers, message.as_string())
smtpObj.quit()
print("邮件发送成功")
except Exception as e:
print(e)
# except smtplib.SMTPException:
# print("Error: 无法发送邮件")

3.主要功能代码

收集到的DB数据文件的信息保存到表mssql_dblogsize中,其建表的脚本如下:

CREATE TABLE [dbo].[mssql_dblogsize](
[id] [int] IDENTITY(1,1) NOT NULL,
[createtime] [datetime] NULL,
[vip] [nvarchar](100) NULL,
[port] [nvarchar](100) NULL,
[Environment] [nvarchar](200) NULL,
[Dbname] [varchar](200) NULL,
[Logical_Name] [varchar](200) NULL,
[Physical_Name] [varchar](1500) NULL,
[Size] [bigint] NULL,
PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO ALTER TABLE [dbo].[mssql_dblogsize] ADD DEFAULT (getdate()) FOR [createtime]
GO

为了方便对表mssql_dblogsize的数据进行管理和展示,在其基础上抽象加工出了一个视图v_mssql_dblogsize,注意Size大小的转换(Size/128/1024 as SizeGB)

创建视图的脚本如下:

CREATE view [dbo].[v_mssql_dblogsize]
as
SELECT [id]
,[createtime]
,[vip]
,[port]
,[Environment]
,[Dbname]
,[Logical_Name]
,[Physical_Name]
,Size/128/1024 as SizeGB
FROM [dbo].[mssql_dblogsize]
where size >50*128*1024
and Physical_Name like '%ldf%'
GO

本测试实例使用的数据库为qqDB,监控的各个DB Server保存在了表QQDBServer中,注意Port 不一定为标准端口1433.

collect_mssql_dblogsize_info.py

# -*- coding: utf-8 -*-

import sys
import os
import configparser
import pymssql
import mssql_get_db_connect
import mssql_exec_sql
from datetime import datetime def collect_mssql_dblogsize_info(): db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
config = configparser.ConfigParser()
config.read(db_ps_file, encoding="utf-8")
m_db_host = config.get('sqlserver_qq', 'db_host')
m_db_port = config.getint('sqlserver_qq', 'db_port') # 获取需要遍历的DB列表
exec_sql_1 = """
SELECT IP, case Port when '1444,1433' then '1433' else Port end as Port, Environment
FROM qqDB.dbo.QQDBServer
where InUse =1 AND ServerType IN ('SQL')
and IP=VIP ;
"""
sql_rst_1 = mssql_exec_sql.mssql_exec_select_sql(m_db_host, m_db_port, exec_sql_1)
for j in sql_rst_1:
db_host_2 = j[0]
db_port_2 = j[1]
db_Environment = j[2]
exec_sql_2 = """
select '""" + db_host_2 + """' as vip, '""" + db_port_2 + """' as port, '""" + db_Environment + """' as Environment,DB_NAME(database_id) AS DatabaseName,
Name AS Logical_Name,
Physical_Name, size
FROM master.sys.master_files;
"""
try:
sql_rst_2 = mssql_exec_sql.mssql_exec_select_sql(db_host_2, db_port_2, exec_sql_2)
except Exception as e:
print(e) for k in sql_rst_2:
exec_sql_3 = """
insert into qqDB..mssql_dblogsize([vip], [port], [Environment], [Dbname], [Logical_Name], [Physical_Name], [Size])
values('%s', '%s', '%s', '%s', '%s', '%s', '%s');
"""
conn = mssql_get_db_connect.mssql_get_db_connect(m_db_host, m_db_port)
with conn.cursor() as cursor_db:
cursor_db.execute(exec_sql_3 % (k[0], k[1], k[2], k[3], k[4], k[5], k[6] ))
conn.commit()
collect_mssql_dblogsize_info()

告警邮件的功能实现为mssql_alert_dblogsize.py,此份代码的告警阈值设置的为50G,数据来自于视图v_mssql_dblogsize。

# -*- coding: utf-8 -*-

import sys
import os
import configparser
import pymssql
import mssql_get_db_connect
import mssql_exec_sql
import datetime
import send_monitor_mail
import pandas as pd def mssql_alert_dblogsize():
mail_subject = "SQL Server DB Log Size Greater than 50G, please check!!! "
mail_receivers = "testDBAgrp@qtiantianq.com" db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
config = configparser.ConfigParser()
config.read(db_ps_file, encoding="utf-8")
m_db_host = config.get('sqlserver_qq', 'db_host')
m_db_port = config.getint('sqlserver_qq', 'db_port') # 获取需要遍历的DB列表 exec_sql_4 = """
SELECT [vip] as IP,[port],[Environment],[Dbname]
,[Logical_Name],[Physical_Name],[SizeGB],[createtime]
FROM qqDB.[dbo].[v_mssql_dblogsize]
order by VIP,Dbname;
"""
sql_rst_4, col_name = mssql_exec_sql.mssql_exec_select_sql_include_colnames(m_db_host, m_db_port, exec_sql_4)
# print(sql_rst_4) if len(sql_rst_4):
mail_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') columns = []
for i in range(len(col_name)):
columns.append(col_name[i][0]) df = pd.DataFrame(columns=columns)
for i in range(len(sql_rst_4)):
df.loc[i] = list(sql_rst_4[i]) mail_body = df.to_html(index=False, justify="left").replace('<th>', '<th style = "color:red; text-align:left; background-color: yellow">')
mail_html = "<html><body><h4>" + "Deal All : " + "<br><h4>" + "以下数据库的db log文件,已大于50G.请及时检查,谢谢! " + "<br><h4>" + mail_body + "</body></html>" send_monitor_mail.send_monitor_mail(mail_subject=mail_subject, mail_body=mail_html, mail_receivers=mail_receivers) mssql_alert_dblogsize()

4.实现

定时任务是通过windows的计划任务来实现的,在此不做过多的叙述。告警邮件的部分截图如下:

5.附录

1.报错定位,判断是不是log文件过大

https://blog.csdn.net/weixin_30785593/article/details/99912405

2.关于为什么数据库log文件过大,我们可以参考以下分享的文章

https://blog.csdn.net/chinadm123/article/details/44941275

通过Python实现对SQL Server 数据文件大小的监控告警的更多相关文章

  1. Red Gate - SQL Source Control实现对SQL SERVER 的源代码控制

    原文地址:http://bbs.csdn.net/topics/350165431 SQL Server 一直没有一款很好的源码控制器,之前自己曾尝试自己写一个,将所有的 脚本 自动生成到某一目录下, ...

  2. C#winform窗体实现对sql server数据库的增删改查

    1.运行效果截图 2.输入用户名,密码进行查询 查找成功则显示 查找不成功显示用户信息不存在 3.输入用户名与密码,向数据库中添加用户信息 添加后数据库表信息 4.查看全部信息 5.根据编号信息进行查 ...

  3. 【转】sql server数据收集和监控

    转自:https://www.cnblogs.com/zhijianliutang/p/4476403.html 相关系列: https://www.cnblogs.com/zhijianliutan ...

  4. Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问

    本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...

  5. 浅谈SQL Server数据内部表现形式

    在上篇文章 浅谈SQL Server内部运行机制 中,与大家分享了SQL Server内部运行机制,通过上次的分享,相信大家已经能解决如下几个问题: 1.SQL Server 体系结构由哪几部分组成? ...

  6. SQL server数据异地备份到OSS

    背景需求: 某部门需要将windows机器上的SQL server数据做一个异地备份,经过对现有的软硬件资源评估,决定使用阿里云的OSS存储 方法:利用SQLserver自带的维护计划做指定数据库的备 ...

  7. SQL server数据缓存依赖

    SQL server数据缓存依赖有两种实现模式,轮询模式,通知模式. 1  轮询模式实现步骤 此模式需要SQL SERVER 7.0/2000/2005版本以上版本都支持        主要包含以下几 ...

  8. [SQL]SQL Server数据表的基础知识与增查删改

    SQL Server数据表的基础知识与增查删改 由张晨辉(学生) 于19天 前发表 | 阅读94次 一.常用数据类型 .整型:bigint.int.smallint.tinyint .小数:decim ...

  9. Sql Server数据的加密与解密

    Sql Server数据的加密与解密 在sql server中,我们如何为数据进行加密与解密,避免使用者窃取机密数据? 对于一些敏感数据,如密码.卡号,一般不能使用正常数值来存储.否则会有安全隐患.以 ...

随机推荐

  1. ClickHouse源码笔记3:函数调用的向量化实现

    分享一下笔者研读ClickHouse源码时分析函数调用的实现,重点在于分析Clickhouse查询层实现的接口,以及Clickhouse是如何利用这些接口更好的实现向量化的.本文的源码分析基于Clic ...

  2. Winform 判断打印机是否可用,实现设置默认打印机功能

    Winform 判断打印机是否可用,实现设置默认打印机功能 http://www.cnblogs.com/zfanlong1314/p/3878563.html

  3. Android获取OneNET云平台数据

    尝试HttpURLConnection "get"方式获取了www.baidu.com的数据后,试着获取OneNET云平台的设备数据(设备数据已成功上传至云平台) .java文件 ...

  4. Vue脚手架中默认的margin怎么清除

    问题情景:开发中发现我的项目四周有白边,但是并没有设置样式 问题原因:vue脚手架中静态文件夹public中的index.html造成的 解决方案:找到vue脚手架中index.html页面,设置ma ...

  5. easyPOI基本用法

    参考网址:http://www.wupaas.com/ 1.Excel文件的导入导出 项目源码:后台:https://github.com/zhongyushi-git/easypoi-demo-ad ...

  6. CentOS7安装Maven3.6.3及Git2.8.3

    安装Maven3.6.3 点击进入官网 1:下载 wget https://mirror.bit.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-m ...

  7. 异常控制流(csapp)

    [前言]程序按照一定顺序执行称为控制转移.最简单的是平滑流,跳转.调用和返回等指令会造成平滑流的突变.系统也需要能够对系统状态的变化做出反应,这些系统状态不能被内部程序变量捕获但是,操作系统通过使控制 ...

  8. PVE连接Wi-Fi

    连接wifi参考文章: https://lzxz1234.cn/archives/417 services看不全信息 connmanctl> services 之后信息太多,看不到上面的怎么办? ...

  9. ant-design-vue中table自定义列

    1. 使用背景 在项目中使用ant-vue的a-table控件过程中,需要显示序号列或者在列中显示图片,超链,按钮等UI信息.经过查询文档customCell和customRender可以实现以上需求 ...

  10. JVM 中的异常

    StackOverflowError 在 JVM 的栈中,如果线程要创建的栈帧大小大于栈容量的大小时,就会抛出 java.lang.StackOverflowError.比如下面的代码 public ...