Kingbase+sqlsugar 携手助力医疗国产化替换 【人大金仓 .NET ORM】

1. 案例

成某三甲医预约系统, 该项目在2024年初进行上线测试,在正常运行了两天后,业务系统报错:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (currently 15 seconds)。金仓开发人员跟进分析,具体排查步骤如下:

1.1 是否是高并发导致的问题

首先是对业务系统进行了梳理,用户业务系统图如下:

通过对用户现场业务系统的分析,错误是业务系统报出的,业务系统处理第三方消息平台发送的请求,第三方消息平台收集签到机和其它设备发送的请求。业务系统高峰期时,同时请求的请求可以达到10条左右。并发量并不大,排除并发量导致的连接池爆池;

1.2 查询服务器端的连接数

金仓数据库系统表:sys_stat_activity中,记录了每个连接的信息,可以通过如下的语句来查询具体业务的连接数:

select state,query from pg_stat_activity where application_name='ksql';

通过加入定时命令,每隔1秒钟都会查询一下对应业务开启的数据库连接数。在业务量最大时,查询到的连接数达到了800个。并且大多数连接的状态为:Idle in transcation,意味着有大量连接开启了事务,但没有任何操作。是因为连接数池上限过小的问题吗?继续将连接池的上限修改,修改为所允许的最大值。结果连接数依旧可以达到连接上限1200。上述现象不符合驱动kdbndp连接池的循环使用机制。这里需要介绍一下金仓驱动kdbndp的连接池机制:

1.2.1 Kdbndp连接池-连接池状态

连接池有三个计数器:

Idle:空闲连接计数器

Busy:正在使用连接计数器

Waiting:等待获取连接对象计数器

1.2.2 连接池中无连接-申请连接流程

1.2.3 连接池已经存在连接-申请连接流程

1.2.4 连接池释放连接---应用退出

1.2.5 连接池释放连接---连接空闲达到设置时间(默认5分钟)

1.2.6 连接池满-处理流程

1.2.7 连接池参数介绍

Pooling:

是否开启连接池,true:开发连接池,false:关闭连接池,默认值:true

Minimum Pool Size

连接池保持最小连接数,默认值:0

Maximum Pool Size

连接池可以创建连接额最大数,默认值:100

Connection Idle Lifetime

空闲连接空闲时间达到的时间值,到达该时间值时,可以回收该连接,默认值:300(秒)

Connection Pruning Interval

空闲连接回收之前等待时间,默认值:10(秒)

从连接池设计的机制来看,一般连接使用结束之后,是释放回到连接池中;而现场问题中存在大量创建物理连接,将连接池撑爆的现象存在。而且大量物理连接的状态为:Idle in transcation,至此,我们找到了导致连接池爆池的原因。

1.3 分析Idle in transcation

Idle in transcation:当数据连接处于"Idle in transcation"状态时,意味着连接已经开启了事物,但没有任何操作(如提交或回滚)来结束这个事务。我们将KingbaseES+sugar框架的结构图梳理出来,进一步的定位问题,结果图如下:

业务流程访问数据库的数据经过了如下步骤:

1> 定义实体数据模型,实体模型模型是编写程序的依据;

2>业务系统调用SqlSugar接口,创建对象时,业务代码编写人员可以指定使用SqlSugar的模式,推荐使用的是单例模式SqlSugarScope,该模式是线程安全的。在创建对象的时候,指定访问的数据库是哪一家的,DbType。Kdbndp中有一个参数DbModeType,指定使用哪种数据库模式,两者有异曲同工之妙;这个时候,我们也指定了我们访问的数据库,访问数据库使用的连接参数等信息;

3>还是调用SqlSugar接口,SqlSugar会将对应接口的操作,映射、翻译为对应的sql语句,调用Kdbndp的执行接口,将语句发送到服务器端;

4>服务器端执行之后,执行结果又通过Kdbndp的功能接口,回到SqlSugar,根据映射关系,将结果存放至模型对象中,业务系统通过获取模型对象中的数据,完成业务数据展示的处理流程。

上述流程中,步骤二中,创建单例模式的访问对象,这个引起了sugar开发人员和金仓开发人员的关注。在SqlSugar创建单例模式时,整个的创建使用流程如下:

在创建单实例模式中,开始了事务,在使用结束之后,需要提交事务,使用commit接口CommitTran(),提交事务,释放Kdbndp连接对象;如果只是将sqlsugar单实例的对象释放,不使用提交事务接口完成释放的话,KdbndpConnection连接不会被释放,这样就导致了数据库中连接处于:Idle in transcation的现象;再次调用创建单实例模式对象,采用同样的流程,连接数开始逐渐的累加起来,直到出现爆池的错误。

分析之后,梳理用户的业务代码,果然是在开启事物之后,调用完成退出时没有做commit操作,导致Kdbndp连接无法回到连接池,无法循环使用连接池中连接而导致爆池。

调整业务代码,在释放sqlsugar单实例对象时,做事务提交退出操作。修改之后,连接池中的物理连接保持在20个左右,不再出现爆池的错误。循环使用连接池的连接,导致服务器端相关资源消耗下降至原来的1/60。每次任务的提交速度提升了200ms。

现场问题解决了,此过程中,了解了kingbase+sugar的一些基础,在进一步使用中您会发现,

SqlSugar和人大金仓优点:

1、 功能更新的及时性,因为两家公司深入合作,彼此产品有新功能的退出,能在第一时间互相沟通,及时发布;

2、 屏蔽差异化,采用该方案,可以在金仓的多个模式(pg、oracle、mysql)上开发,不用关注模式会带来额外的配置;

3、 开发的高效性,采用ORM框架,缩短了开发周期,屏蔽了差异化,业务迁移和开发的成本都会降低;

4、 实时的技术支持,以在多个项目中得到验证,双方的高效合作,为用户的定制开发、问题定位提供及时的技术支持。