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. hadoop环境搭建:完全分布式

    目录 1.硬件配置 2.软件版本 3.准备工作 3.1.建立虚拟机,网络设置为桥接模式 3.2.更改主机名 3.3.绑定主机名和IP,建立各主机间的联系 3.4.关闭防火墙 3.5.配置宿主机host ...

  2. [计算机图形学]光栅化算法:DDA和Bresenham算法

    目录 一.DDA 二.Bresenham 三.绘制图形 1. 绘制直线 2. 绘制圆 3. 绘制椭圆 一.DDA DDA算法是最简单的直线绘制算法.主要思想是利用直线的斜截式:\(y=kx+b\) 对 ...

  3. ImageApparate(幻影)镜像加速服务让镜像分发效率提升 5-10 倍

    作者介绍 李昂,腾讯高级开发工程师,主要关注容器存储和镜像存储相关领域,目前主要负责腾讯容器镜像服务和镜像存储加速系统的研发和设计工作. 李志宇,腾讯云后台开发工程师.负责腾讯云 TKE 集群节点和运 ...

  4. Java流程控制:顺序结构

    一.流程控制 Java中的流程控制语句可以这样分类:顺序结构.选择结构.循环结构.这三种结构就足够解决所有的问题了! 二.顺序结构 描述: Java流程控制的基本结构就是顺序结构,除非特别指明,否则J ...

  5. 进位&&大数字符串处理

    Have Fun with Numbers Notice that the number 123456789 is a 9-digit number consisting exactly the nu ...

  6. 图文详解:阿里宠儿【小兔】RabbitMQ的养成攻略

  7. MySQL数据库插入数据出现 ERROR 1526 (HY000): Table has no partition for value xxx

    MySQL数据库插入数据出现ERROR 1526 (HY000): Table has no partition for value xxx工作的时候发现无法插入数据,报错:ERROR 1526 (H ...

  8. `vi`——终端中的编辑器

    `vi`--终端中的编辑器 目标* `vi` 简介* 打开和新建文件* 三种工作模式* 常用命令* 分屏命令* 常用命令速查图 01. `vi` 简介 1.1 学习 `vi` 的目的 * 在工作中,要 ...

  9. Java数据类型拓展

    public class Demo03 { public static void main(String[] args) { //整数拓展: 二进制0b 十进制 八进制0 十六进制0x int i = ...

  10. Hi3559AV100 NNIE开发(3)RuyiStudio软件 .wk文件生成过程-mobilefacenet.cfg的参数配置

    之后随笔将更多笔墨着重于NNIE开发系列,下文是关于Hi3559AV100 NNIE开发(3)RuyiStudio软件 .wk文件生成过程-mobilefacenet.cfg的参数配置,目前项目需要对 ...