1.需求背景

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

  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信息、邮件服务器信息等。

  1. [sqlserver]
  2. db_user = XXXXXX
  3. db_pwd = XXXXXXX
  4.  
  5. [sqlserver_qq]
  6. db_host = 110.119.120.114
  7. db_port = 1433
  8.  
  9. [windows]
  10. user =
  11. pwd =
  12.  
  13. [mail]
  14. host = zheshiceshidemail.qq.com
  15. port = 25
  16. user =
  17. pwd =
  18. sender = zhejiushiceshidebuyaodangzhen@qq.com

获取连接串的组件mssql_get_db_connect.py

  1. # -*- coding: utf-8 -*-
  2.  
  3. import sys
  4. import os
  5. import datetime
  6. import configparser
  7. import pymssql
  8. # pip3 install pymssql-2.1.4-cp37-cp37m-win_amd64.whl
  9. # pip3 install pymssql -i https://pypi.doubanio.com/simple
  10.  
  11. # 获取连接串信息
  12. def mssql_get_db_connect(db_host, db_port):
  13. db_host = db_host
  14. db_port = db_port
  15.  
  16. db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
  17. config = configparser.ConfigParser()
  18. config.read(db_ps_file, encoding="utf-8")
  19. db_user = config.get('sqlserver', 'db_user')
  20. db_pwd = config.get('sqlserver', 'db_pwd')
  21.  
  22. conn = pymssql.connect(host=db_host, port=db_port, user=db_user, password=db_pwd, charset="utf8", login_timeout=5, timeout=600, autocommit=True)
  23.  
  24. return conn

执行SQL语句的组件mysql_exec_sql.py

  1. # -*- coding: utf-8 -*-
  2.  
  3. import mysql_get_db_connect
  4.  
  5. def mysql_exec_dml_sql(db_host, db_port, exec_sql):
  6. conn = mysql_get_db_connect.mysql_get_db_connect(db_host, db_port)
  7. with conn.cursor() as cursor_db:
  8. cursor_db.execute(exec_sql)
  9. conn.commit()
  10.  
  11. def mysql_exec_select_sql(db_host, db_port, exec_sql):
  12. conn = mysql_get_db_connect.mysql_get_db_connect(db_host, db_port)
  13. with conn.cursor() as cursor_db:
  14. cursor_db.execute(exec_sql)
  15. sql_rst = cursor_db.fetchall()
  16.  
  17. return sql_rst
  18.  
  19. def mysql_exec_select_sql_include_colnames(db_host, db_port, exec_sql):
  20. conn = mysql_get_db_connect.mysql_get_db_connect(db_host, db_port)
  21. with conn.cursor() as cursor_db:
  22. cursor_db.execute(exec_sql)
  23. sql_rst = cursor_db.fetchall()
  24. col_names = cursor_db.description
  25. return sql_rst, col_names

发邮件的功能send_monitor_mail.py

  1. # -*- coding: utf-8 -*-
  2.  
  3. # pip3 install PyEmail
  4. import smtplib
  5. from email.mime.text import MIMEText
  6. import configparser
  7. import os
  8. import sys
  9.  
  10. # 发送告警邮件
  11. def send_monitor_mail(mail_subject, mail_body, mail_receivers="testwukongbaigujing@qq.com"):
  12. db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
  13. config = configparser.ConfigParser()
  14. config.read(db_ps_file, encoding="utf-8")
  15. mail_host = config.get('mail', 'host')
  16. mail_port = config.get('mail', 'port')
  17. # mail_user = config.get('mail', 'user')
  18. # mail_pwd = config.get('mail', 'pwd')
  19. sender = config.get('mail', 'sender')
  20. # receivers = config.get('mail', 'receivers')
  21.  
  22. # 发送HTML格式邮件
  23. message = MIMEText(mail_body, 'html', 'utf-8')
  24. # message = MIMEText(mail_body, 'plain', 'utf-8')
  25. message['subject'] = mail_subject
  26. message['From'] = sender
  27. message['To'] = mail_receivers
  28.  
  29. try:
  30. smtpObj = smtplib.SMTP()
  31. smtpObj.connect(mail_host, mail_port) # 25 为 SMTP 端口号
  32. # SMTP AUTH extension not supported by server.
  33. # https://github.com/miguelgrinberg/microblog/issues/76
  34. # smtpObj.ehlo()
  35. # smtpObj.starttls()
  36. # smtpObj.login(mail_user, mail_pwd)
  37. smtpObj.sendmail(sender, mail_receivers, message.as_string())
  38. smtpObj.quit()
  39. print("邮件发送成功")
  40. except Exception as e:
  41. print(e)
  42. # except smtplib.SMTPException:
  43. # print("Error: 无法发送邮件")

3.主要功能代码

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

  1. CREATE TABLE [dbo].[mssql_dblogsize](
  2. [id] [int] IDENTITY(1,1) NOT NULL,
  3. [createtime] [datetime] NULL,
  4. [vip] [nvarchar](100) NULL,
  5. [port] [nvarchar](100) NULL,
  6. [Environment] [nvarchar](200) NULL,
  7. [Dbname] [varchar](200) NULL,
  8. [Logical_Name] [varchar](200) NULL,
  9. [Physical_Name] [varchar](1500) NULL,
  10. [Size] [bigint] NULL,
  11. PRIMARY KEY CLUSTERED
  12. (
  13. [id] ASC
  14. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  15. ) ON [PRIMARY]
  16. GO
  17.  
  18. ALTER TABLE [dbo].[mssql_dblogsize] ADD DEFAULT (getdate()) FOR [createtime]
  19. GO

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

创建视图的脚本如下:

  1. CREATE view [dbo].[v_mssql_dblogsize]
  2. as
  3. SELECT [id]
  4. ,[createtime]
  5. ,[vip]
  6. ,[port]
  7. ,[Environment]
  8. ,[Dbname]
  9. ,[Logical_Name]
  10. ,[Physical_Name]
  11. ,Size/128/1024 as SizeGB
  12. FROM [dbo].[mssql_dblogsize]
  13. where size >50*128*1024
  14. and Physical_Name like '%ldf%'
  15. GO

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

collect_mssql_dblogsize_info.py

  1. # -*- coding: utf-8 -*-
  2.  
  3. import sys
  4. import os
  5. import configparser
  6. import pymssql
  7. import mssql_get_db_connect
  8. import mssql_exec_sql
  9. from datetime import datetime
  10.  
  11. def collect_mssql_dblogsize_info():
  12.  
  13. db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
  14. config = configparser.ConfigParser()
  15. config.read(db_ps_file, encoding="utf-8")
  16. m_db_host = config.get('sqlserver_qq', 'db_host')
  17. m_db_port = config.getint('sqlserver_qq', 'db_port')
  18.  
  19. # 获取需要遍历的DB列表
  20. exec_sql_1 = """
  21. SELECT IP, case Port when '1444,1433' then '1433' else Port end as Port, Environment
  22. FROM qqDB.dbo.QQDBServer
  23. where InUse =1 AND ServerType IN ('SQL')
  24. and IP=VIP ;
  25. """
  26. sql_rst_1 = mssql_exec_sql.mssql_exec_select_sql(m_db_host, m_db_port, exec_sql_1)
  27. for j in sql_rst_1:
  28. db_host_2 = j[0]
  29. db_port_2 = j[1]
  30. db_Environment = j[2]
  31. exec_sql_2 = """
  32. select '""" + db_host_2 + """' as vip, '""" + db_port_2 + """' as port, '""" + db_Environment + """' as Environment,DB_NAME(database_id) AS DatabaseName,
  33. Name AS Logical_Name,
  34. Physical_Name, size
  35. FROM master.sys.master_files;
  36. """
  37. try:
  38. sql_rst_2 = mssql_exec_sql.mssql_exec_select_sql(db_host_2, db_port_2, exec_sql_2)
  39. except Exception as e:
  40. print(e)
  41.  
  42. for k in sql_rst_2:
  43. exec_sql_3 = """
  44. insert into qqDB..mssql_dblogsize([vip], [port], [Environment], [Dbname], [Logical_Name], [Physical_Name], [Size])
  45. values('%s', '%s', '%s', '%s', '%s', '%s', '%s');
  46. """
  47. conn = mssql_get_db_connect.mssql_get_db_connect(m_db_host, m_db_port)
  48. with conn.cursor() as cursor_db:
  49. cursor_db.execute(exec_sql_3 % (k[0], k[1], k[2], k[3], k[4], k[5], k[6] ))
  50. conn.commit()
  51. collect_mssql_dblogsize_info()

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

  1. # -*- coding: utf-8 -*-
  2.  
  3. import sys
  4. import os
  5. import configparser
  6. import pymssql
  7. import mssql_get_db_connect
  8. import mssql_exec_sql
  9. import datetime
  10. import send_monitor_mail
  11. import pandas as pd
  12.  
  13. def mssql_alert_dblogsize():
  14. mail_subject = "SQL Server DB Log Size Greater than 50G, please check!!! "
  15. mail_receivers = "testDBAgrp@qtiantianq.com"
  16.  
  17. db_ps_file = os.path.join(sys.path[0], "qqmssqltest_db_server_conf.ini")
  18. config = configparser.ConfigParser()
  19. config.read(db_ps_file, encoding="utf-8")
  20. m_db_host = config.get('sqlserver_qq', 'db_host')
  21. m_db_port = config.getint('sqlserver_qq', 'db_port')
  22.  
  23. # 获取需要遍历的DB列表
  24.  
  25. exec_sql_4 = """
  26. SELECT [vip] as IP,[port],[Environment],[Dbname]
  27. ,[Logical_Name],[Physical_Name],[SizeGB],[createtime]
  28. FROM qqDB.[dbo].[v_mssql_dblogsize]
  29. order by VIP,Dbname;
  30. """
  31. sql_rst_4, col_name = mssql_exec_sql.mssql_exec_select_sql_include_colnames(m_db_host, m_db_port, exec_sql_4)
  32. # print(sql_rst_4)
  33.  
  34. if len(sql_rst_4):
  35. mail_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  36.  
  37. columns = []
  38. for i in range(len(col_name)):
  39. columns.append(col_name[i][0])
  40.  
  41. df = pd.DataFrame(columns=columns)
  42. for i in range(len(sql_rst_4)):
  43. df.loc[i] = list(sql_rst_4[i])
  44.  
  45. mail_body = df.to_html(index=False, justify="left").replace('<th>', '<th style = "color:red; text-align:left; background-color: yellow">')
  46. mail_html = "<html><body><h4>" + "Deal All : " + "<br><h4>" + "以下数据库的db log文件,已大于50G.请及时检查,谢谢! " + "<br><h4>" + mail_body + "</body></html>"
  47.  
  48. send_monitor_mail.send_monitor_mail(mail_subject=mail_subject, mail_body=mail_html, mail_receivers=mail_receivers)
  49.  
  50. 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. 1098 Insertion or Heap Sort——PAT甲级真题

    1098 Insertion or Heap Sort According to Wikipedia: Insertion sort iterates, consuming one input ele ...

  2. Django Admin后台管理功能使用+二次开发

    一  使用环境 开发系统: windows IDE: pycharm 数据库: msyql,navicat 编程语言: python3.7  (Windows x86-64 executable in ...

  3. 第47天学习打卡(HTML)

    什么是HTML HTML Hyper Text Markup Language(超文本标记语言) 超文本包括:文字,图片,音频,视频,动画等 HTML5,提供了一些新的元素和一些有趣的新特性,同时也建 ...

  4. xmake v2.5.2 发布, 支持自动拉取交叉工具链和依赖包集成

    xmake 是一个基于 Lua 的轻量级跨平台构建工具,使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,配置语法更加简洁直观,对新手非常友好,短时间内就能 ...

  5. pytorch(08)数据模型的读取(2)

    import numpy as np import torch import os import random from PIL import Image from torch.utils.data ...

  6. python3+tkinter实现的黑白棋,代码完整 100%能运行

    今天分享给大家的是采用Python3+tkinter制作而成的小项目--黑白棋 tkinter是Python内置的图形化模块,简单易用,一般的小型UI程序可以快速用它实现,具体的tkinter相关知识 ...

  7. 关于djangorestframework

    djangorestframework技术文档 restfrmework规范 开发模式 普通开发为前端和后端代码放在一起写 前后端分离为前后端交互统统为ajax进行交互 前后端分离 优点:分工明细,节 ...

  8. WBX24T2X CPEX国产化万兆交换板

      WBX24T2X是基于盛科CTC5160设计的国产化6U三层万兆CPEX交换板,提供24路千兆电口和2路万兆光口,采用龙芯 2K1000处理器.支持常规的L2/L3协议,支持Telnet.SNMP ...

  9. Maven配置ali镜像

    Maven目录,Conf文件夹下settings.xml 找到mirrors节点 添加配置 <mirror> <id>alimaven</id> <mirro ...

  10. php小结

    //函数定义常量:definedefine("PI",3.14); //使用const关键字const PII = 3; 特殊常量:双下划线开始+常量名+双下划线结束,称为魔术常量 ...