将数据库连接池统计数据发送到collectd
项目描述
将Python应用程序使用的SQLAlchemy连接和事务指标的统计数据发送到collectd服务。
sqlalchemy-collectd通过数据库URL调用作为SQLAlchemy插件工作,因此可以用于任何接受任意连接URL的SQLAlchemy应用程序(1.1或更高版本)。插件使用setuptools入口点加载,无需更改应用程序的代码。没有对数据库后端或驱动程序的依赖。
sqlalchemy-collectd旨在为具有数据库集群、代理服务器、大量客户端应用程序、多进程应用程序和容器等任何数量拓扑复杂技术的庞大、多主机/多进程环境中的应用程序端数据库指标提供统一视图。
什么是collectd?
collectd是一个易于运行的统计收集守护进程。它作为各种性能和其他指标的运行时统计数据的收集器和重新广播器。一旦一组统计信息进入collectd,它们几乎可以广播到任何地方,包括RRD数据库和前端、指标报告应用程序如Graphite和Grafana,以及其他collectd服务器。
架构概述
sqlalchemy-collectd 从 Python 应用程序内部收集其统计信息,并通过 UDP 将实时指标发送到 collectd 服务。为此,它的客户端部分以 SQLAlchemy 引擎插件 的形式加载到进程内,该插件连接到 sqlalchemy.engine.Engine 对象以及其内部的连接池。每个进程内运行的背景线程会定期通过 UDP 发送统计快照。
在 collectd 端,一个 Python 插件监听相同的 UDP 端口,汇总来自任意数量 Python 进程和主机的统计信息,并将其作为一系列按主机和程序统计信息发送到 collectd 引擎本身。
此架构的关键目标之一是允许使用多个进程的 Python 程序(例如,通过 Python multiprocessing 或简单的 fork)报告每个子进程内每个引擎/连接池的 统一 信息,以及跟踪从许多主机运行的同一种应用程序的多个实例(当然,它还可以同时跟踪任意数量的应用程序和主机)。拥有完整的客户端/服务器模型使得 collectd 服务本身不仅可以位于与应用程序相同的宿主机上,还可以位于网络上的任何其他宿主机上。
网络模型本身利用了 collectd 的自身二进制协议;虽然这并非严格必要,但这是因为最初的计划是使用 collectd 的“网络”插件作为接收器,然而在观察到 collectd 的“聚合”插件限制后,这被替换为一个完整的 Python 插件,它以更直接的方式完成所有所需操作。
这与使用数据库监控有何不同?
当运行 MySQL 或 Postgresql 等数据库时,有许多方法可以查看数据库的活动;您可以列出关于连接、事务、正在使用的线程/进程的统计信息,并且在大多数情况下,您可以将这些服务器端统计信息与 collectd 集成起来,以实时观察趋势。
然而,虽然从服务器收集统计信息可以提供对活动的洞察,包括能够查看源主机以及每个客户端访问的特定数据库,但在大规模环境中,要获得关于每个主机上每个进程如何使用其数据库连接的统一、实时图景是非常困难的,特别是在应用程序和数据库之间存在间接层(如 HAProxy、ProxySQL 或 PGBouncer 这样的代理服务器)的情况下,以及当数据库和/或应用程序被容器化并且可能跳过额外的网络翻译层时。这种分析需要能够将数据库报告的数据库连接与源主机和每个主机上的单个进程相关联。
以 SQLAlchemy 为导向的应用程序通常也使用进程局部连接池,并且能够看到这些池的利用情况是很有价值的,这包括能够看到有多少空闲连接以及应用程序需要多频繁地创建新连接来响应请求。这些信息仍然可以从数据库本身(例如连接空闲时间)中获得,但尤其是在存在间接层的情况下,从应用程序本身获取您关心的性能指标(例如,应用程序的性能如何)更为简单,因为它们可以提供关于其正在做什么的确切信息,而无需从数据库服务器和网络状态中逆向工程。
当然,这假设应用程序是使用 SQLAlchemy 的 Python 应用程序。这当然是应该的! :)
安装
要使用 SQLAlchemy-collectd,您需要具备
SQLAlchemy-collectd 以 Python 库的形式与 SQLAlchemy 一起安装,适用于所有运行 SQLAlchemy 应用程序的所有 Python 环境。
collectd 服务本身位于网络中的某个位置。
collectd-python 插件,可能根据发行版作为单独的包提供。
SQLAlchemy-collectd 以 Python 库的形式与 collectd 服务器本身一起安装,可以是系统 Python 的一部分,collectd-python 默认访问,或者 SQLAlchemy-collectd 应用程序可以被提取到任何可以设置为 collectd 的附加系统路径的任意位置。
不使用包管理器,可以通过 pip 使用以下命令安装 SQLAlchemy-collectd:
pip install sqlalchemy-collectd
配置
配置包括客户端配置和服务器端配置,两者都很简单。
客户端
SQLAlchemy 应用程序使用数据库连接 URL,通常从某种配置系统中加载。无论这个 URL 在您的目标应用程序中是什么,基本添加 ?plugin=collectd 到它(如果已经有其他查询参数,则使用 &plugin=collectd)。例如:
mysql+pymysql://user:password@databasehost/dbname?charset=utf8&plugin=collectd
使用上面的 URL,sqlalchemy-collectd 插件将尝试向监听 localhost 端口 25827 的 collectd 服务器发送消息(注意这比默认的 collectd 网络插件端口 25826 高一个)。
目标主机
要将统计信息发送到不同主机上的 collectd,请添加 collectd_host(目前仅支持 ipv4)和可选的 collectd_port。
mysql+pymysql://user:password@databasehost/dbname?charset=utf8&plugin=collectd&collectd_host=172.18.5.2&collectd_port=25827
程序名称
另一个重要的配置是“程序名称”——这是 sqlalchemy-collectd 在统计信息中报告的应用程序名称。在特定主机上的特定“程序名称”内,统计信息是 跨所有进程 聚集的,无论父进程如何。
默认情况下,“程序名称”来自 sys.argv[0],但这并不总是希望的;例如,如果您在 mod_wsgi 中运行,这可能会返回 httpd,这比大多数人希望的更模糊。此外,单个应用程序可能为了不同的目的创建连接到多个数据库,可能希望将这些报告分离到不同的部分。要设置此程序名称,请添加 collectd_program_name。
mysql+pymysql://user:password@databasehost/dbname?charset=utf8&plugin=collectd&collectd_program_name=nova_api&collectd_host=172.18.5.2
使用上述 URL,单个主机上使用此 URL 的所有 Python 进程将根据名称 nova_api 聚集其连接使用统计信息。
启动
配置 URL 后,大多数应用程序可能需要重新启动才能使更改生效。
该插件将为每个启动并连接到数据库的独立进程透明地启动一个后台线程(别担心,如果您使用 gevent、eventlet、asyncio、gunicorn 等,这些线程是您的朋友)。
服务器
sqlalchemy-collectd 使用 Python 插件,因此假设系统已安装 sqlalchemy-collectd,在 collectd.conf 或 collectd.d/sqlalchemy.conf 文件中:
LoadPlugin python <Plugin python> LogTraces true Import "sqlalchemy_collectd.server.plugin" <Module "sqlalchemy_collectd.server.plugin"> # ipv4 only for the moment listen "0.0.0.0" 25827 # set to "debug" to show messages received loglevel "info" </Module> </Plugin>
如上所示,插件将在默认网络接口的 25827 端口上监听 UDP。它还可以配置为在“localhost”或主机上的任何其他 IP 地址(目前仅支持 ipv4)上监听。
自定义模块路径
要引用提取到任意文件位置的 sqlalchemy-collectd,请添加 ModulePath。
LoadPlugin python <Plugin python> ModulePath "/path/to/sqlalchemy-collectd/" LogTraces true Import "sqlalchemy_collectd.server.plugin" <Module "sqlalchemy_collectd.server.plugin"> # ipv4 only for the moment listen "0.0.0.0" 25827 # set to "debug" to show messages received loglevel "info" </Module> </Plugin>
有关 Python 插件系统的更多信息,请参阅 collectd-python。
通常需要重新启动 collectd 服务器才能使配置更改生效。
TODO
ipv6 支持
安全层(例如,网络数据包签名/加密)
统计信息
现在 sqlalchemy-collectd 运行起来了,我们可以看到哪些统计信息?
假设我们已为应用程序 neutron 和 nova 启用了插件,我们将在像 Grafana 这样的工具中看到的命名空间将如下所示
hostname sqlalchemy-host count-checkedin count-checkedout count-connections count-detached count-numpools count-numprocs derive-checkouts derive-connects derive-disconnects derive-invalidated derive-commits derive-rollbacks derive-transactions sqlalchemy-neutron count-checkedin count-checkedout count-connections count-detached ... everything else sqlalchemy-nova count-checkedin count-checkedout count-connections count-detached ... everything else
在上文中,我们首先看到所有统计信息都是按主机名分组的。在这其中,有一个固定的 插件实例 被称为“host”,显示为 sqlalchemy-host。这代表了整个主机的聚合统计信息,也就是说,统计信息考虑了在此特定主机上使用 sqlalchemy-collectd 的所有应用程序(使用 sqlalchemy-collectd)的所有数据库连接。
接下来,我们可以看到有个别 program_name 的分组,对于 nova 和 neutron,我们得到针对该名称的特定统计信息。
这些统计信息被标记为 count-<name> 或 derive-<name>,这对应于预提供的 collectd 类型 count 和 derive(见下文“collectd 类型”以了解命名的原因)。标记为 count 的统计信息是整数,表示资源的当前计数或活动
count-checkedin - 当前连接到连接池的连接数
count-checkedout - 当前从连接池中借出的连接数,例如,应用程序正在使用这些连接与数据库通信。
count-connections - 此时数据库的连接总数,已借出、已检查入、已断开或软失效。
count-detached - 总断开连接数;这意味着它们已经通过 .detach() 方法从引擎/池断开,但仍作为数据库连接使用。
count-numpools - 正在使用的连接池数量。一个 SQLAlchemy Engine 恰好有一个连接池。如果一个应用程序在进程中使用两个不同的数据库 URL 并创建两个不同的 Engine 对象,那么你将有两个池。如果该应用程序在十个子进程中产生,那么你将使用 20 或 22 个池,具体取决于父进程如何使用数据库。使用 count-numpools 确保这个数字是你所期望的。一个编写不佳的应用程序,如果为每个请求都创建一个新的 Engine,那么这里的数字将会非常大(以及一个不断变化的数字),这是一个明显的红旗,表明该应用程序需要修复。
count-numprocs - 向此组贡献连接统计信息的 Python 进程总数,例如父进程和子进程。如果你每个进程有一个 Engine,这个数字将与 count-numpools 相匹配。
count-numpools 和 count-numprocs 的值提供了查看总连接和借出的上下文。如果连接池配置为最多允许 20 个连接,并且主机上有 10 个连接池,现在你可以有最多 200 个连接到数据库。
标记为 derive 的统计信息是表示活动 速率 的浮点数。sqlalchemy-collectd 将这些数字作为特定时间戳之前发生的事件总数发送到 collectd 服务器;collectd 然后将其与之前的值进行比较以确定速率。速率的报告方式(例如每秒的次数等)取决于所使用的报告工具。
derive-checkouts - 正在被检查出的连接的速率。
derive-connects - 连接到数据库的新连接的速率
derive-disconnects - 正在关闭的数据库连接的速率
derive-invalidated - 明确被无效化的连接的速率,例如,遇到连接错误导致程序使连接无效。应用程序可能立即尝试重新连接,也可能不立即尝试重新连接,这取决于该功能的使用方式。有关此内容的详细信息,请参阅下面的“无效连接”部分。
derive-commits - (待实施:尚未实现)调用 transaction.commit() 的速率。此值可以用来估算TPS,即每秒事务数,但是请注意,这仅限于在调用Engine级别的begin() / commit()方法时显式使用SQLAlchemy的事务。当使用带有 Session 的SQLAlchemy ORM时,此速率应追踪调用 Session.commit() 的速率。
derive-rollbacks - (待实施:尚未实现)调用 transaction.rollback() 的速率。
derive-transactions - (待实施:尚未实现)事务的整体速率。这应该等于提交和回滚速率的总和,但是可能更高,如果应用程序还丢弃了未调用 .commit() 或 .rollback() 的交易和/或 Session 对象。
无效连接
derive-invalidated 状态记录了无效化的速率。
所谓无效化,意味着调用了连接上的 .invalidated() 方法,这标志着该连接将不再可用,并在下一次使用时进行刷新(软无效化)或更常见的是立即关闭(硬无效化)。通常,当一个连接被无效化时,应用程序要么在预先ping数据库并尝试重新连接,要么在数据库被切断时正在执行操作,在这种情况下,根据应用程序的设计,它可能或可能不会再次尝试操作。
无效化通常对应于报告了无法与数据库通信问题的连接,并因此抛出了错误。因此,“无效化”的速率应被视为大致的“错误”率 - 这里每个计数通常对应于应用程序遇到的连接错误,它通过使连接无效来响应,这导致立即或最终重新连接。
对于大多数无效化场景,整个连接池会使用“新鲜度”时间戳一次性无效化;任何早于此时间戳的连接都会在下次使用时刷新。这是为了适应假设数据库已重新启动,因此所有连接都需要重新连接。这些已 隐式 无效化的连接 不包括 在此计数中。
Collectd 类型
这些有趣的名字 count- 和 derive- 是 collectd 提供的 类型 的一种体现。collectd 有一个固定的“类型”列表,它在一个名为 types.db 的文件中列出。服务器不接受不在该文件或单独配置的自定义类型文件中的类型名称,因为每个类型都附有一个模板,说明它携带的值类型。令人烦恼的是,collectd 不允许我们在常规的 .conf 文件中添加这些名称,这会使我们很容易添加自己的自定义名称;相反,它要求它们在完全独立的文件中列出,并且必须在 conf 文件中显式地通过绝对路径引用,更糟糕的是,当使用此选项时,我们必须取消注释默认 types.db 文件的路径,否则它将无法找到它。在“非常漂亮的名字”和“不需要设置三个独立的配置文件”之间进行选择,我们选择了后者 :)
connmon 模式
作为一个附加功能,现在 connmon UX 已集成到 SQLAlchemy-collectd 中。这是一个控制台应用程序,显示连接当前状态的“top”显示。
使用上述配置,我们可以添加一个针对 connmon 服务器插件的插件配置
LoadPlugin python <Plugin python> LogTraces true Import "sqlalchemy_collectd.server.plugin" <Module "sqlalchemy_collectd.server.plugin"> # ipv4 only for the moment listen "0.0.0.0" 25827 # set to "debug" to show messages received loglevel "info" </Module> Import "sqlalchemy_collectd.connmon.plugin" <Module "sqlalchemy_collectd.connmon.plugin"> monitor "localhost" 25828 # set to "debug" to show messaging #loglevel "debug" </Module> </Plugin>
现在我们可以在 localhost 的 25828 端口上运行“connmon”
connmon --port 25828
connmon 插件和命令行工具自 0.6 版本起独立于“服务器”插件运行,可以单独配置,无需服务器插件。它现在不仅从本地服务器插件(如果存在)消耗 sqlalchemy-collectd 事件,还从任何其他将消息转发到服务器的 sqlalchemy-collectd 消息中消耗,通常是通过“网络”插件。
connmon 的屏幕截图
SQLAlchemy 项目
SQLAlchemy-collectd 是 SQLAlchemy 项目的组成部分,并遵循核心项目相同的规范和约定。
开发 / 错误报告 / 拉取请求
请参阅 SQLAlchemy 社区指南 以获取有关编码和参与此项目的指南。
行为准则
首先,SQLAlchemy 对用户和开发者之间礼貌、周到和建设性的沟通非常重视。请参阅我们的当前 行为准则。
许可协议
SQLAlchemy-collectd 在 MIT 许可协议 下分发。
项目详情
下载文件
下载适合您平台的文件。如果您不确定要选择哪个,请了解更多关于 安装包 的信息。