一个权限配置错误引发的“血案”金仓数据库访问控制手记深夜的那通电话凌晨两点手机响了。值班同事声音发紧“大哥金仓核心交易库连不上了应用那边在报‘no sys_hba.conf entry’这是什么意思”我一边穿衣服一边让他把详细报错发过来。截图上的信息很明确FATAL: no sys_hba.conf entry for host 10.207.88.101这是个典型的访问控制配置遗漏问题。新上线的应用服务器IP没加到白名单里金仓数据库直接把连接请求拒了。加一行配置、重载、业务恢复前后不到五分钟。但这件事让我意识到很多DBA对金仓这套访问控制机制的理解还停留在“照着文档配一下”的阶段。一、用户和角色别把这两个概念搞混了先从一个常见的认知误区说起。刚接触金仓数据库的时候我一直没搞明白USER和ROLE到底有什么区别。后来才弄懂在金仓里用户就是能登录的角色。-- 这两条语句干的是同一件事CREATEUSERfin_appWITHPASSWORDapp123;CREATEROLE fin_appWITHLOGIN PASSWORDapp123;区别只有一个USER默认带LOGIN权限ROLE默认不带。这个设计其实挺巧妙的。你可以用ROLE定义一组权限比如“只读组”、“读写组”然后用USER创建具体的人再把权限组赋给用户。这样改权限的时候只需要改ROLE所有继承这个角色的用户自动跟着变。一个真实的权限设计案例去年做的一个金融系统权限结构是这么搭的-- 先建三个基础角色CREATEROLE read_only;-- 只能查CREATEROLE read_write;-- 能查能改CREATEROLE app_admin;-- 管理员-- 给角色授权GRANTSELECTONALLTABLESINSCHEMApublicTOread_only;GRANTINSERT,UPDATE,DELETEONALLTABLESINSCHEMApublicTOread_write;GRANTCREATE,DROPONALLTABLESINSCHEMApublicTOapp_admin;-- 创建用户并分配角色CREATEUSERfin_appWITHPASSWORDapp123;GRANTread_writeTOfin_app;CREATEUSERreport_userWITHPASSWORDreport456;GRANTread_onlyTOreport_user;CREATEUSERdba_zhangWITHPASSWORDdba789CREATEDB;GRANTapp_adminTOdba_zhang;这样做的好处很明显后来报表系统需要增加一个临时账号直接CREATE USER然后GRANT read_only就行不用再重新授权。权限收回来也方便一条REVOKE就完事。金仓特有的权限查看命令-- 看用户属于哪些角色组SELECTr.rolname,m.rolnameasmember_ofFROMsys_roles rJOINsys_auth_members amONr.oidam.memberJOINsys_roles mONam.roleidm.oid;-- 看某个表上谁有什么权限SELECTgrantee,privilege_typeFROMinformation_schema.role_table_grantsWHEREtable_nameaccounts;-- 列级权限只给特定字段金仓支持到列级别的精细控制GRANTSELECT(id,name)ONhr.employeesTOreport_user;-- salary字段没给报表用户查不到工资信息关于金仓超级用户的提醒金仓数据库的默认超级用户是system这个账号能绕过所有权限检查。有几个原则建议遵守应用程序连接绝对不能用超级用户日常运维也尽量使用普通管理员账户超级用户的密码要定期更换、严格保管二、连接控制谁才能进门说完“进来后能干什么”再说“谁才能进来”。金仓通过s altsys_hba.conf文件来控制客户端访问权限。2.1 文件格式长什么样# TYPE DATABASE USER ADDRESS METHOD host all all 192.168.1.0/24 scram-sha-256每行五个字段连接类型、数据库名、用户名、来源地址、认证方式。金仓支持的认证方式方式说明什么时候用trust不需要密码本地维护用生产环境千万别开scram-sha-256SCRAM加密认证生产环境首选金仓默认推荐md5MD5加密老系统兼容sm3国密SM3认证国密合规场景reject直接拒绝封IP用的2.2 那次差点出事的配置遗漏回到开头的那个案例。新上线的报销系统连不上金仓数据库报错说找不到对应的sys_hba.conf记录。登录服务器一看配置文件里只有老系统的IPhost all all 10.207.88.50/32 scram-sha-256 host all all 10.207.88.51/32 scram-sha-256新服务器10.207.88.101不在列表里。加上就好了host all all 10.207.88.101/32 scram-sha-256然后执行重载让金仓重新读取配置SELECTsys_reload_conf();业务恢复。事后我补了个检查清单每次新服务器上线必须确认DBA知道、网络通了、白名单加了。改了配置为什么不生效金仓的sys_hba.conf改了之后必须重载。两种方式-- SQL里执行SELECTsys_reload_conf();# 命令行执行sys_ctl reload-D$KINGBASE_DATA重载不会中断现有连接只对新连接生效。三、会话监控看看连接都在干什么连接进来了怎么知道它们在干什么金仓的sys_stat_activity视图就是干这个的。3.1 常用监控查询-- 看当前所有活跃的查询SELECTpid,usename,client_addr,state,queryFROMsys_stat_activityWHEREstateactive;state字段很关键active正在执行SQLidle闲着等新命令idle in transaction事务开了没提交——这个状态要警惕3.2 那次连接池被占满的事故有天下午业务高峰金仓数据库监控突然告警大量支付请求失败。DBA试着登录竟然连上了——因为金仓为超级用户保留了专用通道。这是superuser_reserved_connections参数的作用默认留了几个槽位给超级用户就是为了这种紧急情况。先看连接数SELECTcount(*)FROMsys_stat_activity;-- 300达到了金仓max_connections的上限再看会话状态分布SELECTstate,count(*)FROMsys_stat_activityGROUPBYstate;结果state数量idle in transaction285active12idle3285个连接挂着事务不提交也不回滚。这比单纯连接满更麻烦——它们可能还拿着锁会堵住别人的操作。查一下这些连接是谁的、挂了多久SELECTpid,usename,application_name,now()-xact_startasduration,queryFROMsys_stat_activityWHEREstateidle in transactionORDERBYdurationDESC;发现都来自一个第三方支付模块大部分事务已经挂起超过30分钟。联系开发排查发现那个模块在某个异常分支里忘了关闭事务。怎么处理先杀僵尸会话恢复业务SELECTsys_terminate_backend(pid)FROMsys_stat_activityWHEREstateidle in transactionANDnow()-state_changeinterval3 minutes;然后设置金仓的自动清理参数防止以后再发生ALTERSYSTEMSETidle_in_transaction_session_timeout10min;SELECTsys_reload_conf();这个参数的意思是事务空闲超过10分钟金仓自动把它终止掉。3.3 金仓杀会话的两种方式-- 温和版取消当前查询但不断开连接SELECTsys_cancel_backend(pid);-- 暴力版直接断开连接SELECTsys_terminate_backend(pid);一般先试温和版不行再用暴力版。四、max_connections这个参数在金仓里怎么调4.1 先看当前值-- 最常用SHOWmax_connections;-- 想看详细信息SELECTname,setting,context,pending_restartFROMsys_settingsWHEREnamemax_connections;context字段告诉你改完要不要重启postmaster必须重启sighup重载就行user会话里直接set金仓的max_connections是postmaster级别改完必须重启数据库。4.2 改之前先算算内存根据金仓官方文档每个连接大概消耗的内存连接本身约400字节锁空间每个连接默认64个锁每个锁约270字节加起来每个连接约17.3KB。500个连接就是8.6MB2000个连接约34.6MB。这个数字其实不大真正的内存大户是金仓的shared_buffers和work_mem。4.3 改的正确姿势-- 方法一ALTER SYSTEM金仓推荐ALTERSYSTEMSETmax_connections500;-- 方法二改配置文件-- vi $KINGBASE_DATA/kingbase.conf-- max_connections 500-- 改完必须重启金仓数据库sys_ctl restart-D $KINGBASE_DATA-- 验证SHOWmax_connections;一个金仓特有的坑ALTER SYSTEM会把配置写进kingbase.auto.conf这个文件的优先级比kingbase.conf高。如果你改了kingbase.conf发现不生效检查一下auto.conf是不是有相同的参数。4.4 什么时候该改什么时候不该改该改的情况业务增长连接数确实不够了压测验证过服务器资源扛得住不该改的情况连接被僵尸会话占满了——先清理会话别急着扩偶尔的并发峰值——应该用连接池缓冲不是无限扩容内存本来就不够——加了参数可能导致金仓起不来那次连接池占满的事故事后我们评估了一下300的连接数其实够用问题是285个被无效占用了。加了金仓的idle_in_transaction_session_timeout自动清理之后再也没出过问题。五、金仓运维中积累的几个小工具5.1 快速查看权限配置-- 所有可登录用户及其权限SELECTrolname,rolcanlogin,rolsuper,rolcreatedbFROMsys_authidWHERErolcanlogintrueORDERBYrolname;5.2 查看当前HBA规则SELECTtype,user_name,address,auth_methodFROMsys_hba_file_rulesORDERBYuser_name;5.3 监控连接数变化-- 每分钟记录一次连接数SELECTnow(),count(*)FROMsys_stat_activity;六、金仓数据库访问控制踩坑总结这些年用金仓数据库在这些方面踩过的坑总结几条1. 权限设计要从一开始就做等项目上线了再补权限开发已经把所有代码写成用超级用户连接改起来代价极大。接手新项目第一件事先把金仓的权限结构搭好。2. sys_hba.conf改了要重载这条看着简单但每次故障复盘都会发现有人忘了这步。金仓的SELECT sys_reload_conf()是常用命令建议写在配置文件的注释里。3. 监控idle in transaction这个状态是金仓连接池的隐形杀手。设置idle_in_transaction_session_timeout是性价比最高的防御手段。4. 超级用户的保留通道不能丢金仓的superuser_reserved_connections默认值通常是3别把它改成0。关键时刻能不能登录进去就靠这个参数了。5. 参数改之前先看context金仓的max_connections是postmaster级别的参数改了要重启。生产环境调整这类参数需要提前申请变更窗口。6. 优先级问题金仓的ALTER SYSTEM写的kingbase.auto.conf优先级高于kingbase.conf。改完不生效先检查这里。金仓数据库的访问控制体系说复杂也复杂说简单也简单。无非就是三件事谁可以进来、进来后能干什么、出了问题怎么处理。把这三点理清楚大部分问题都能迎刃而解。