今天遇到一用户,他们想通过创建并设置"CONNECT PROC"去记录每个连接进来的应用程序名。 db cfg里面有个参数叫"CONNECT PROC", 它可以设置成一个存储过程,设置后, 每次数据库连接进来都会调用这个存储过程一次:
$ db2 get db cfg for sample | grep -i proc
Connect procedure (CONNECT_PROC) =
该用户定义了一个储存过程, 改过程通过下面的语句获取application_name并把相关记录插入某表:
SET APPLNAME = (SELECT APPLICATION_NAME FROM TABLE(MON_GET_CONNECTION(CAST(NULL AS BIGINT), -1)) WHERE APPLICATION_ID = APPLICATION_ID());
但是,部署好测试过程中遇到了问题。当并发连接数增大时, 应用端遇到了错误:
[IBM][CLI Driver] SQL10003C 沒有足夠系統資源以處理要求。無法處理該要求。 SQLSTATE=57011
db2diag.log 显示DB2_FMP_COMM_HEAPSZ不足:
2017-12-19-14.03.06.045770+480 I170388355A724 LEVEL: Error
PID : 22085702 TID : 808045 PROC : db2sysc 0
INSTANCE: db2inst1 NODE : 000 DB : SAMPLE
APPHDL : 0-19931 APPID: 10.37.249.39.54514.171219060305
AUTHID : DB2INST1
EDUID : 808045 EDUNAME: db2agent (SAMPLE) 0
FUNCTION: DB2 UDB, routine_infrastructure, sqlerGetFMPIPC, probe:50
MESSAGE : Insufficient memory available for IPC communication with the db2fmp
process. Use the DB2_FMP_COMM_HEAPSZ registry variable to adjust the
amount of memory available for fenced routines.
DATA #1 : Hexdump, 4 bytes
0x0A0000032F7F03D0 : 8B0F 003B ...;
因为所需DB2_FMP_COMM_HEAPSZ的大小跟db2fmp进程数+线程数成正比, 这样看起来明显是db2fmp进程数或者线程数超了。本来想到此为止, 直接建议他增大DB2_FMP_COMM_HEAPSZ, 但发现当时除了"CONNECT PROC"过程导致了db2fmp进程, 还有另外一个 SYSFUN.APPLICATION_ID也导致了大量的db2fmp进程:
$ db2pd -fmpexechistory | grep -i '2017-12-20'
Database Partition 0 -- Active -- Up 351 days 08:03:49 -- Date 2017-12-20-18.22.40.356660
65675 2017-12-20-18.22.40.284797
65675 2017-12-20-18.22.40.327882
65675 2017-12-20-18.22.40.334186
65675 2017-12-20-18.22.40.235727
65675 2017-12-20-18.22.40.300479
...$ db2 "select substr(routineschema,1,10) routineschema, substr(routinename,1,20) routinename from sysibm.sysroutines where routine_id=65690"
ROUTINESCHEMA ROUTINENAME
------------- --------------------
SYSFUN APPLICATION_ID
1 record(s) selected.
了解到mon_get_xxx都不通过db2fmp执行,于是建议用户修改"CONNECT PROC"过程里面的那句如下:
SET APPLNAME = (SELECT APPLICATION_NAME FROM TABLE(MON_GET_CONNECTION(MON_GET_APPLICATION_HANDLE(), -1)) T);
结果他说遇到下面的错误:
$ db2 "SELECT APPLICATION_NAME FROM TABLE(MON_GET_CONNECTION(MON_GET_APPLICATION_HANDLE(), -1)) T"
SQL0440N No authorized routine named "MON_GET_APPLICATION_HANDLE" of type
"FUNCTION" having compatible arguments was found. SQLSTATE=42884
他是V97 FP7, 我原以为V97 FP7不支持MON_GET_APPLICATION_HANDLE(9.7的信息中心确实找不到这个表方法的介绍),但是我自己刷了个相同版本后,发现是支持的:
$ db2 "SELECT APPLICATION_NAME FROM TABLE(MON_GET_CONNECTION(MON_GET_APPLICATION_HANDLE(), -1)) T"
APPLICATION_NAME
------------------
db2bp
1 record(s) selected.
这就奇怪了,他的环境为什么就不支持,是不是system catalog等东西没有升级过来(比如没有跑db2updv97之类的)? 于是,啰嗦这么久,终于进入正题, 通过什么方法可以查到用户是否执行了db2updv97/db2updv105之类的呢?
答案是通过查询sysibm.sysversions:
$ db2 "select VERSIONNUMBER, VERSION_TIMESTAMP, SUBSTR(AUTHID,1,10) AUTHID, VERSIONBUILDLEVEL from sysibm.sysversions"
VERSIONNUMBER VERSION_TIMESTAMP AUTHID VERSIONBUILDLEVEL
------------- -------------------------- ---------- ------------------------------
8020900 2010-02-10-23.54.17.807764 DB2INST1 -
9010700 2010-02-15-04.41.13.035065 SYSIBM -
9071000 2017-04-15-02.05.51.172872 SYSIBM s141015
3 record(s) selected.
通过上面可以看到,这个用户2017-04-15从v9.1升级到了V9.7 FP1, 应该是跑了"db2 upgrade database ...", 否则库连不上。V9.7 FP1应该是不支持MON_GET_APPLICATION_HANDLE, 后来装了FP7的补丁,没有执行db2updv97,所以系统编目信息都没有更新,所以 不能调MON_GET_APPLICATION_HANDLE。
于是使用实例用户执行db2updv97,之后再看sysibm.sysversions,发现多了一行记录:
$ db2 "select VERSIONNUMBER, VERSION_TIMESTAMP, SUBSTR(AUTHID,1,10) AUTHID, VERSIONBUILDLEVEL from sysibm.sysversions"
VERSIONNUMBER VERSION_TIMESTAMP AUTHID VERSIONBUILDLEVEL
------------- -------------------------- ---------- ------------------------------
8020900 2010-02-10-23.54.17.807764 DB2INST1 -
9010700 2010-02-15-04.41.13.035065 SYSIBM -
9071000 2017-04-15-02.05.51.172872 SYSIBM s141015
9070700 2017-12-21-08.48.35.572164 DB2INST1 s121002
4 record(s) selected.
再次测试发现db2fmp进程数量下降到了DB2_FMP_COMM_HEAPSZ可支持的范围, 问题解决了。