应用数仓 ODBC 前,这些问题你需要先了解一下
本文分享自华为云社区《GaussDB(DWS) ODBC 问题定位指南》,作者: power_gouge 。
用户的应用程序,调用的 ODBC 的 API,其实是由驱动管理器提供的,这个驱动管理器在微软上就是 odbcad32(.exe/.dll),在 Linux 上就是 UnixODBC。再由它们来调用 ODBC 的具体驱动(Gauss、Oracle、TD……)。
所以一般问题基本会出在以下几个方面:
应用加载驱动管理器
驱动管理器加载驱动
驱动连接数据库
一个典型的用户应用程序如下:
问题处理
应用程序加载驱动管理器失败
Windows
Windows 由于操作系统实现机制的问题,ODBC 属于操作系统组件的一部分,除非操作系统损坏,一般不会出现应用程序加载驱动管理器失败;只会出现驱动管理器加载驱动失败。所以这里不再赘述。
Linux
Linux 上应用程序加载驱动管理器,是指的应用程序依赖于 UnixODBC 的相关动态库,启动时要将其加载到自己的进程空间中。加载出现问题多表现为在启动时找不到 libodbc.so.x/libodbcinst.so.x 等库。
解决此问题:
首先确认环境中是否安装了 UnixODBC。如果安装了,那么至少会有 isql/odbcinst 等工具可用。例如可使用 which isql 这样的命令来确定安装路径。相关的 lib 库一般会在 which isql 指定的 bin 目录的同级目录下,将其添加到 LD_LIBRARY_PATH 中重启应用程序便可。
export LD_LIBRARY_PATH=/where/unixodbc/installed/lib:$LD_LIBRARY_PATH
特别注意,此语句只影响当前 shell 会话中的后续命令,其他会话不受影响,特别是后台启动的进程。如果是后台进程,请与应用程序的开发人员确认其运行环境如果修正。
如果确认 LD_LIBRARY_PATH 已经生效(可以打开/proc/应用程序 pid/environ 文件确认),依然无法加载 libodbc.so.x/libodbcinst.so.x,那么可能是.1 或者.2 的库的问题。
历史原因,一般的开发环境中,UnixODBC 提供的库既可能叫 libodbc.so.1 也可能叫 libodbc.so.2。用户程序可能依赖了.2,但是环境中只有.1;也有可能是存在.2,但是依赖了.1。
解决此问题,只需要在 UnixODBC 的 lib 目录下,将不存在的版本建立成软链接,保证.1 与.2 都存在,这样出问题的机率便会小很多。特别注意,这里强烈建议是建立软链接,而不要拷贝物理文件,不然可能出现一个应用程序进程中,加载了两个导出函数完全相同的.so,这样可能会引起一些比较难定位的启动错误,后文中会讲到。
驱动管理器加载驱动失败
Windows
最常见 x86 与 x64 架构不同导致的加载失败;此问题的典型报错为:
在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配
此问题可能的原因:在 64 位程序中使用了 32 位驱动,或者相反。
在 64 位系统上:
C:\Windows\SysWOW64\odbcad32.exe:这是 32 位 ODBC 驱动管理器。
C:\Windows\System32\odbcad32.exe:这是 64 位 ODBC 驱动管理器。
使用不同架构的应用程序时,请使用不同的驱动管理器;同时安装不同的驱动类型。
32 位系统上只能跑 32 位程序,也无法安装 64 位驱动,所以基本不用区分。
如果是 64 位系统,那么它既支持 32 位程序,也支持 64 位程序;如果不能确定应用程序是 32 还是 64,可以使用以下办法:
ctrl + shift + esc 打开任务管理器
查看进程列表中某进程后边有没有*32 的字样(有就是 32 位,没有就是 64 位),如下图:\
Linux
环境中缺少 psqlodbcw.so 的库
一般这个问题的报错是
[UnixODBC][Driver Manager]Can't open lib 'xxx/xxx/psqlodbcw.so' : file not found.
可能的原因有:
odbcinst.ini 中配置的路径不正确,最简单的办法是 ls -l 一下这个报错的文件,看看这个是不是真的存在,同时具有执行权限。
依赖的库不存在,此时最简单的办法是 ldd 一下这个报错的文件,看看是不是真的缺少库,如果缺少库会出现如下问题:
要处理这个问题,需要将 unixodbc 的安装目录下的 lib,添加到 LD_LIBRARY_PATH 里,例如:
同时,在 UnixODBC 的安装的 lib 目录下,看看 libodbcinst.so.x 后边的后缀是.1 还是.2。如果是.2,那么请建立一个软链接,链接到.1,便可以解决此问题。
如果该目录下只有.1 的库,没有.2 的库,也建议建立一个.2 的软链接,防止应用程序依赖于.2,我们依赖于.1,引起冲突。
特别注意,当前会话的 LD_LIBRARY_PATH 不代表应用程序运行时也是同样的 LD_LIBRARY_PATH,必要的时候,与应用程序开发人员对齐。
如果是常驻进程,可以通过如下方法获取到当前进程的环境变量:
打印出来的结果可能比较乱,耐心看一下;如果内容有误,与应用程序开发人员对齐修改方法。
既有.2 又有.1 的库,导致重复加载
这种勤快的用户比较少见,但是一旦出现,很难定位,典型的报错信息是:
Driver's SQLAllocHandle on SQL_HANDLE_DBC failed
这种情况这时应用与驱动加载的是不同的物理文件,便会导致两套完全同名的函数列表,同时出现在同一个可见域里(UnixODBC 的 libodbc.so.*的函数导出列表完全一致),产生冲突,无法加载数据库驱动。
解决此问题的办法也比较简单,查看 LD_LIBRARY_PATH 中的第一个 unixodbc 的 lib 目录。在其目录下,缺少.2 或.1,建立对应的.2 或.1 的软链接便可。
连接问题
服务器不可达
典型报错:
connect to server failed: no such file or directory
此问题可能的原因:
配置了错误的/不可达的数据库地址,或者端口请检查数据源配置中的 Servername 及 Port 配置项,确认网络是通达的。
服务器监听不正确如果确认 Servername 及 Port 配置正确,请根据资料中 listen_addresses 参数的配置方法,确保数据库监听了合适的网卡及端口,特别是 Servername 中指定的网卡地址及 LVS 的虚拟 IP 地址。
修改完记得重启数据库,使监听生效。
防火墙及网闸、流控设备请确认防火墙设置,将数据库的通信端口添加到可信端口中。如果有网闸、流控设备,请确认一下相关的设置。此问题一般都是第三方商业产品导致,需要咨询服务/产品提供商相关的策略。
SSL 配置不正确
典型报错 1:
The password-stored method is not supported.
解决办法 1:
请将数据源配置中的的 sslmode 调整至 allow 及以上级别,允许使用 SSL 连接。
典型报错 2:
Server common name "xxxx" does not match host name "xxxxx"
此问题是由于 sslmode 中使用了全校验(verify-full),它不仅会校验证书,还会校验证书所在的域名/机器名是否与证书符合,不符合时将报出此问题。
解决办法 2:
重新让 CA 机构以新的域名/机器名签发证书;或者将 SSLMODE 调整至 verify-ca 选项或其以下级别(具体级别见产品资料中的说明)。
使用开源驱动连接问题
我们的数据库是支持低版本及开源驱动的(V1R7C10 及以后),所以可以放心使用。
但是偶尔一些从 V1R6C10 升级上来的数据库,接受开源驱动连接时,会碰到用户认证算法不支持的问题,典型报错如下:
authentication method 10 not supported.
此问题机理比较复杂,下面详细展开,先说解决办法:
请使用管理新账号新建一个数据库的用户,并给予其相关的访问权限,使用新用户连接数据库。
更改当前业务用户的密码,使用新密码连接数据库。
解释一下此问题发生的机理:
我们的数据库在连接时,是会让客户端将认证信息发过来的。但是发过来的信息不会是明文密码,这是不安全的;客户端发到数据库的认证信息一般是经过加盐后的密码哈希(md5/sha256 算法),迭代次数也非常多。
数据库本身也并不存储用户的明文密码,存储的是一个哈希值(所以密码要是丢了,就真的丢了,只能重置不能找回)。数据库在校验这个密码的时候,是比较哈希的,这就涉及到数据库中存储的哈希是使用的什么算法得到的哈希值,常见的是 sha256(高斯自研)及 MD5(开源)。
V1R7C00 及以前,数据库中只存储了 SHA256 的哈希,升级时我们也无法推导用户原有密码,所以升级后仍然只有 SHA256 的哈希;但是开源客户端只识别 MD5 的哈希,这就导致数据库无法认证;数据库也只会让客户端以 SHA256 的哈希来做认证,这时开源就不识别该认证请求,导致报出如上的错误。
在创建用户和修改用户密码时,我们的新版本会同时记录两份哈希,所以后续将会同时支持开源及自研的各个版本。
因数据源配置不正确,导致的连接错误
典型报错:
Data source name not found, and no default driver specified
可能原因:
数据源名称书写错误(或含有特殊符号)
不同的操作系统用户下,数据源可见性不一样;
Linux 上的数据源配置文件(odbc.ini)位置不正确
解决办法:
修正数据源名称.
Windows 下,请在当前用户下打开驱动管理器,查看数据源配置是否正确。请注意在 64 位系统上使用正确的数据源管理器:
C:\Windows\SysWOW64\odbcad32.exe:这是 32 位 ODBC 驱动管理器。
C:\Windows\System32\odbcad32.exe:这是 64 位 ODBC 驱动管理器。
Linux 下使用 odbcinst -j 命令,查看当前环境中配置文件的正确路径,输出一般如下:
其中 USER DATA SOURCES 就是用户数据源,优先生效;SYSTEM DATA SOURCES 是系统数据源,整个系统可用。请针对这些文件路径,
注意:有时用户数据源的配置文件可能是 $(HOME)/.odbc.ini
通信协议不匹配问题
典型报错:
unsupported frontend protocol 3.51: server supports 1.0 to 3.0
可能原因:
使用了新版本的数据库驱动连接老版本的数据库(V1R6C10);或者使用了我们的驱动,连接到了开源的数据库上。
解决办法:
请使用老版本的数据库驱动连接该数据库。
我们的数据库中,默认低版本客户端可以连接高版本数据库;使用高版本驱动连接低版本客户端,不在规格约束范围内。
这个规格也比较好理解:因为用户一般是对数据库集中管理,升级也是有计划的。但是客户端驱动可能嵌入到业务中的每一个角落,有时甚至是已经发布的装备中,升级相对比较困难。
如果是开源服务器:我们的数据库驱动不支持开源数据库,无法连接;请使用开源客户端连接。
其他常见疑问
与开源的区别?
增加了安全性,使用了 SHA256 算法做认证加密;同时调整密钥哈希加密次数
提升了批量性能(V1R7C10 2019-4-30 及以后版本)
是否可以增加新 API?
不可以。
还是基础知识里那张图,用户引用的 API 是由驱动管理器提供的,我们提供的 API 只可供驱动管理器使用;新增 API 无法穿过中间层为用户提供服务。
是否支持 COPY 接口?
Copy 是 PG 的特有语法及通信协议;而 ODBC 是微软提出的通用调用接口,所以无此特殊接口。
Linux 上的驱动管理器有哪些?
驱动管理器在 Linux 上并不是操作系统的一部分,它也是由其他开源组织开发的。所以并不是只有 UnixODBC 一种。但是目前使用最广泛的,其实只有 UnixODBC,多数据操作系统安装时基本都已经自带了 UnixODBC 的某个特定版本;除此之外,还有 iODBC 等,现在已经慢慢退出市场了。
UnixODBC 的版本有限制么?
有。我们支持 2.3.0 及以上版本。
UnixODBC 的.1 与.2 的库有什么区别?
没有什么区别。
这个与 UnixODBC 的历史有关,历史上有一段时间提供.1,后来做了一次大升级,动态库版本也跟着升级了,变成了.2。但是一大批存量业务受制无法运行,就又添加了.1 的支持。
.1 与.2 其实只是 UnixODBC 的 configure 配置的一部分,其函数导出,功能完全一致,不必纠结于此。
可以打印日志么?
可以。
一般建议打印驱动管理器的日志,此日志比较清晰,定位问题比较快。操作办法:
Windows 上:
打开驱动管理器,调整到跟踪页面,确定日志文件路径后,点击开始跟踪便可,如图:
Linux 上:
打开 odbcinst.ini 文件(可使用 odbcinst -j 来确定文件路径),添加以下章节:
重启业务便可。
注意:非必要时,请关闭日志,因为每个 API 都存在写盘,将会引起性能损失。
查询结果集过大,内存吃不消怎么办?
打开 UseDclareFetch 开关,它将会把查询包装成游标操作。对于不支持 Cursor with hold 的版本慎用。同时由于使用了服务器端的游标,游标的前后滚操作也会反馈给数据库,通信会有所增加,所以性能会有部分下降;可以通过调整 Fetch 参数来确定每次数据库向客户端反馈的数据量大小,来降低该性能影响。
Linux 下打开 UseDeclareFetch 的方法:
在数据源配置项中添加:
Windows 下打开 UseDeclareFetch 的方法:
其中的 Cache Size 选项,就是 Fetch 的大小。
有性能基线数据么?
创建连接的性能大体为 0.5s 内都算正常(一般 0.3s 左右)
数据插入的话
非批量版本(R7C10 以及前)大约为 400tps(SSD 的测试结果)
批量版本(R8C10 及以后)大约为 4000tps(SSD 服务器),由于数据库对象差异、网络、物理硬件等,基本 2000tps 以上都可以认为是正常
语句出错怎么排查?
运行过程中出错,ODBC 是不会打屏的。错误信息需要业务里获取错误信息(API 为:SQLGetDiagField/SQLGetDiagRec)。
如果用户的业务里有打印具体的错误信息,或者业务的错误信息不足以定位,请根据 3.7 中的描述,将 ODBC 的日志打印出来,在其中找 SQL_ERROR 相关信息。这里最好能和业务开发人员一起定位,因为 API 的调用序列是乱序的,由业务决定。
如果 ODBC 的日志仍然不足以定位支撑,请登录到连接的目标 CN 所在的机器,通过以下方法进入 CN 日志文件目录:
找到对应时间点的日志,观察其中是否有错误信息。
我们与 Oracle/MYSQL 的 ODBC 有什么关系
ODBC 是一套标准,每家数据库提供自己的驱动文件。就像大家都叫显卡,每个厂商也都提供自己的驱动,自己的驱动只能驱动自己的显卡;而显卡的接口标准是微软(ODBC 也是微软)制定的,只是大家不接触,不知道有这样一套标准而已。
我们的驱动文件叫 psqlodbcw.so/psqlodbcw.dll。
支持 GBK 么?
支持。
但是我们 ODBC 驱动默认使用 utf-8 编码。如果要调整,需要自行在会话开始时设置 client_encoding。
但是请注意,请不要在宽字节模式下使用 GBK,因为宽字节编码本身就是 UNICODE 的一部分(一般为 UCS2),此时使用 GBK 可能导致数据无法显示,SQL 查询结果不正确等问题。
如果出现此问题,请将 VS 中的解决方案字符集调整为“多字节”。
文章由博主 @归云原创
想了解 GuassDB(DWS)更多信息,欢迎微信搜索“GaussDB DWS”关注微信公众号,和您分享最新最全的 PB 级数仓黑科技,后台还可获取众多学习资料哦~
版权声明: 本文为 InfoQ 作者【华为云开发者社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/cf3cff51216b15dfc688e780e】。文章转载请联系作者。
评论