
涉及到真实的数据库使用环境,不要以为永远不会发生数据库连接泄露的情况。只是尽量不要出现在生产环境就好。
近日,就遇到了一个最终再也连不上Hana Cloud的例子,新的任何试图连接数据库,都会报下边的错:
就是妥妥的连不上数据库了。直觉告诉我们,数据库的连接已经全部用尽了。
找来相关同事确认:
[3179]{-1}[-1/-1] 2023-06-15 10:05:45.179110 e SQLSession sm_session.cc(00181) : maximum number of external connections (2000) exceeded
在trace文件里头,还能看到上边这样的错。这里只能呵呵了,2000个连接基本上全被吃掉了。
只能找机会,而且是抢着机会,使用dbadmin用户进去看一眼,是哪些用户把连接吃光了。
先用下边的语句统计一下:
select user_name, count(*) count from m_connections where connection_id > 0 group by user_name order by count desc;
结果如下:
额的神,前边这四个用户基本上每个都是大户,基本上都占了差不多500个连接。
因为它们都是与Container关联的,刚好也是与多租户的每个租户(subaccount)相关联在一起。回想起,这四个租户,我们刚好做了一个加密的key的回收操作,相当于禁用这个subaccount。
大概率是在回收key以后,没有做回收连接的调用,导致连接越积越多(只是预测)。
先把这些连接断掉再说:
SELECT 'ALTER SYSTEM DISCONNECT SESSION ' || '''' || connection_id || ''';' from m_connections
where connection_id > 0 AND user_name IN ('user1', 'user2', 'user3', 'user4');
上边的SQL会生成大概差不多2000行的断开连接的SQL语句.
ALTER SYSTEM DISCONNECT SESSION '223525';
ALTER SYSTEM DISCONNECT SESSION '223586';
ALTER SYSTEM DISCONNECT SESSION '223589';
ALTER SYSTEM DISCONNECT SESSION '223593';
ALTER SYSTEM DISCONNECT SESSION '223587';
ALTER SYSTEM DISCONNECT SESSION '223591';
ALTER SYSTEM DISCONNECT SESSION '223588';
ALTER SYSTEM DISCONNECT SESSION '223626';
ALTER SYSTEM DISCONNECT SESSION '223553';
ALTER SYSTEM DISCONNECT SESSION '223578';
........
一次性执行,基本上那些连接就都被干掉了。
上述脚本可以整理成一个完整的存储过程来进行调用,这里只是为了阐述基本方法,有兴趣的请大家自试。
然后我们回过头来,去看看问题本身,后来发现果然是在发现tenant是revoke key状态时只是简单抛出异常,但是并没有释放连接,导致连接越积越多,可以瞬间导致连接耗尽。因为正常情况下,很少会有tenant被disable的这种操作,所以这种问题很少暴露出来。
待修复之后,再查询一下连接的情况,就都恢复正常了。
使用下述SQL统计语句:
select user_name, count(*) count from m_connections where connection_id > 0 group by user_name order by count desc;
select user_name, client_ip, count(*) count from m_connections where connection_id > 0 group by client_ip, user_name order by count desc;
结果如下:
当然为了保证更回安全和用户隔离,我们创建了内部支持用户专门用于上边的查询和统计:
CREATE USER <support_user> PASSWORD <password> NO FORCE_FIRST_PASSWORD_CHANGE;
GRANT SAP_INTERNAL_HANA_SUPPORT TO <support_user>;
基于上述情况,也发现了Multitenant情况下,Hana Cloud也许还可以做些微调,比如预留1到几个连接给dbadmin用户,用于极端情况下的应急。另外,在Container (面向tenant)初始化的时候,是否可以限制一下它的最大连接数,这样一个tenant的连接用完了,也不会影响到其它tenant的连接。上边的例子就是4个tenant就把系统中几乎所有的连接全部用完了。后续应该会有相关的改进。
当然,我们在应用端通过连接池来限制,理想情况下也是可以的,只是碰到极端情况,就不灵了。比如这个安例就是因为没有及时放回连接池导致的。

原文作者:数据库杂记;如有侵权,请联系管理员删除。