我有一个lua脚本,运行在RHEL7主机上,它被写入以连接到MS SQL Server数据库(使用FreeTDS/unixODBC)并检索值。该脚本通常工作正常,但是,如果目标服务器脱机/不可用,它将挂起(大约 6 分 20 秒),然后最终超时并返回错误。我想要的是将这个超时减少到几秒钟......
我觉得这应该很容易做到,但我似乎无法弄清楚如何指定/强制实施与 SQL Server 的连接超时。
在/etc/freetds.conf 中有一个超时配置(见下文),但这似乎没有效果。
该脚本通常从nginx(openresty)调用,这是我想保持低超时的主要原因,但是独立运行脚本时观察到相同的挂起/超时行为。
谁能帮我解决这个问题?我在下面包含了相关配置文件的脚本和内容。
更新: 在进一步测试期间,我注意到一些值得一提的事情 - 如果我将测试脚本指向同一子网之外的未使用的 IP 地址,则尝试进行 SQL Server 连接时的超时为 ~6 分 21 秒(如前所述)。但是,如果我将其指向同一子网中未使用的IP地址,则超时始终为~9秒。我不是网络专家,但这表明我实际上在这里看到的 2 次超时受网络/传输层的影响 - 也许我的本地网络交换机只是将数据包丢弃到未知子网?
这并不能解决我最初的问题,但认为值得一提作为更新......
获取值.lua:
local odbc = require "odbc"
local keyvalue = "some_value"
local retval = ""
CNN_DRV = {
{Driver='{FreeTDS}'};
{Server='10.10.60.100,1433'};
{Database='databasename'};
{Uid='sqlusername'};
{Pwd='sqlpassword'};
};
dbassert = odbc.assert
env,err = odbc.environment()
local cnn, err = env:driverconnect(CNN_DRV)
stmt,err = cnn:prepare("{?= call dbo.GetRetValForKeyValue(?)}")
ret = stmt:vbind_param_ulong(1, ret, odbc.PARAM_OUTPUT)
val = stmt:vbind_param_char(2, keyvalue)
dbassert(stmt:execute())
stmt:foreach(function(f1)
if tonumber(f1)
then
retval = string.format("%d", f1)
else
retval = ''
end
end
)
print(retval)
/etc/odbcinst.ini:
[FreeTDS]
Description = FreeTDS TDS driver (for Sybase/MS SQL)
Driver = /usr/lib64/libtdsodbc.so.0
Setup = /usr/lib64/libtdsS.so.2
/etc/freetds.conf:
# Global settings are overridden by those in a database
# server specific section
[global]
# TDS protocol version
; tds version = 4.2
# Whether to write a TDSDUMP file for diagnostic purposes
# (setting this to /tmp is insecure on a multi-user system)
; dump file = /tmp/freetds.log
; debug flags = 0xffff
# Command and connection timeouts
; timeout = 10
; connect timeout = 10
# If you get out-of-memory errors, it may mean that your client
# is trying to allocate a huge buffer for a TEXT field.
# Try setting 'text size' to a more reasonable limit
text size = 64512
在执行连接之前,您可以尝试为连接对象设置SQL_ATTR_LOGIN_TIMEOUT
。
与等待的秒数对应的 SQLUINTEGER 值 以便在返回到应用程序之前完成登录请求。 默认值取决于驱动程序。如果 ValuePtr 为 0,则超时为 禁用,连接尝试将无限期等待。
local env, err = odbc.environment()
local cnn = env:connection()
cnn:setlogintimeout(10)
local ok, err = cnn:driverconnect(CNN_DRV)
更新
还存在SQL_ATTR_CONNECTION_TIMEOUT
属性(但对于 ODBC 3.0)
与等待的秒数对应的 SQLUINTEGER 值 对于在返回到 应用。驱动程序应返回 SQLSTATE HYT00 (超时已过期) 在未关联的情况下可能超时的任何时候 使用查询执行或登录。
如果 ValuePtr 等于 0(默认值),则没有超时。
我不暴露它,但你可以试试这个。(还可以签出头文件中SQL_ATTR_CONNECTION_TIMEOUT的值)。
local SQL_ATTR_CONNECTION_TIMEOUT = 113
cnn:setuintattr(SQL_ATTR_CONNECTION_TIMEOUT, 10)
我在树莓派3上遇到了类似的问题(使用FreeTDS 1.2.3/unixODBC)。连接工作没有问题,但我无法让超时工作(如果我强制 SQL 服务器脱机)。我跟踪了代码并意识到freetds.conf中的超时参数从未到达freeTDS库,因此等待数据包(在packet.c中)的函数永远挂在那里。
我的解决方案是使用以下更改修改 freeTDS 库,以便在读取 odbc 时.ini超时值被馈送到 freeTDS 库。我不确定这是否是解决此问题的正确方法,或者我是否缺少某些内容,但我在网上找不到任何东西。
odbc.h (在 odbc 参数列表中添加了超时)
#define ODBC_PARAM_LIST
ODBC_PARAM(Servername)
ODBC_PARAM(Server)
ODBC_PARAM(DSN)
ODBC_PARAM(UID)
ODBC_PARAM(PWD)
ODBC_PARAM(Address)
ODBC_PARAM(Port)
ODBC_PARAM(TDS_Version)
ODBC_PARAM(Language)
ODBC_PARAM(Database)
ODBC_PARAM(TextSize)
ODBC_PARAM(PacketSize)
ODBC_PARAM(ClientCharset)
ODBC_PARAM(DumpFile)
ODBC_PARAM(DumpFileAppend)
ODBC_PARAM(DebugFlags)
ODBC_PARAM(Encryption)
ODBC_PARAM(Trusted_Connection)
ODBC_PARAM(APP)
ODBC_PARAM(WSID)
ODBC_PARAM(UseNTLMv2)
ODBC_PARAM(MARS_Connection)
ODBC_PARAM(REALM)
ODBC_PARAM(ServerSPN)
ODBC_PARAM(AttachDbFilename)
ODBC_PARAM(ApplicationIntent)
ODBC_PARAM(Timeout)
connectparams.c (在函数中添加了超时属性,并在获取DSN信息时读取它
int
ODBCINSTGetProperties(HODBCINSTPROPERTY hLastProperty)
{
....
hLastProperty = definePropertyString(hLastProperty, odbc_param_Timeout, "10", "The timeout for connection and queries.");
return 1;
}
/**
* Read connection information from given DSN
* @param DSN DSN name
* @param login where to store connection info
* @return 1 if success 0 otherwhise
*/
int
odbc_get_dsn_info(TDS_ERRS *errs, const char *DSN, TDSLOGIN * login)
{
....
if (myGetPrivateProfileString(DSN, odbc_param_Timeout, tmp) > 0)
tds_parse_conf_section(TDS_STR_TIMEOUT, tmp, login);
return 1;
}
ODBC.ini
[TestServer]
Driver=FreeTDS
Database=MyDatabase
Port=1433
Server=<<ip address>>
timeout=10