天天看点

数据库平滑switchover的要素 - 会话资源漂移

postgresql , 中间件 , 连接池 , 平滑切换 , 会话设置 , 会话状态 , 绑定变量语句 , prepared statement

数据库迁移、切换是很普遍的一个话题,但是大多数的方案,对用户来说都是有感知的,所以用户的体验并不好。

例如用户使用了绑定变量语句,主备角色切换后绑定变量语句没有了,会导致调用报错。

我们需要维护主库的硬件,那么可以在中间件层面,将主备数据库的角色进行平滑调换,维护好硬件,再平滑的调换回来。

数据库主备切换时,如何做到会话级无感知?首先我们要了解会话中都有哪些内容,哪些内容是需要随角色切换一起迁移的。从而做到用户无感知。

(本文ha指中间件层级的ha,并非app直连数据库,vip切换的那种ha。)

简单的switchover过程举例:

等待所有会话的事务结束,会话都处于idle状态,冻结会话,不允许提交任何sql,然后进行角色切换,并将每个会话的资源状态平移。

会话中有些什么状态?通过discard这条sql就可以了解。

<a href="https://www.postgresql.org/docs/10/static/sql-discard.html">https://www.postgresql.org/docs/10/static/sql-discard.html</a>

discard all相当于执行如下

会话资源中目前可能包含如下(每个pg版本可能有些许差异):

sessoin角色、参数设置、绑定变量语句、游标、异步消息监听、ad锁、序列、临时表等。

下面介绍一下每种资源的查询方法,以及在新的主库上进行资源复原的方法。

超级用户可以将会话用户设置为其他用户,普通用户无权切换用户。

当前用户为postgres,设置session authorization为test

当pg_stat_activity.usename不等于session authorization时,需要通过如下方法复原它。

postgresql的一些参数是允许用户在会话、事务中进行设置的。如下context in ('user','superuser')时,用户可以在会话或事务中设置。

设置例子

使用绑定变量可以减少数据库的parser, plan开销,提高高并发的查询性能,同时避免sql注入。

不同的驱动,有不同的使用方法。

<a href="https://www.postgresql.org/docs/10/static/libpq-exec.html#libpq-exec-main">https://www.postgresql.org/docs/10/static/libpq-exec.html#libpq-exec-main</a>

使用绑定变量的例子

不同的驱动,复原方法不一样。

请根据pg_prepared_statements的内容进行复原。

如果我们使用了hold选项,那么游标不会随事务结束而关闭,因此在迁移会话时也需要注意是否有这类游标。

postgresql的异步消息,可以通过异步消息,推送事件。例子如下:

<a href="https://www.postgresql.org/docs/10/static/libpq-notify.html">https://www.postgresql.org/docs/10/static/libpq-notify.html</a>

<a href="https://www.postgresql.org/docs/10/static/libpq-example.html#libpq-example-2">https://www.postgresql.org/docs/10/static/libpq-example.html#libpq-example-2</a>

查询已经开启了哪些异步监听

advisory lock可以用于秒杀、解决高并发锁冲突问题、解决无空洞序列值问题等。

<a href="https://github.com/digoal/blog/blob/master/201705/20170507_02.md">《postgresql 使用advisory lock实现行级读写堵塞》</a>

<a href="https://github.com/digoal/blog/blob/master/201610/20161020_02.md">《postgresql 无缝自增id的实现 - by advisory lock》</a>

<a href="https://github.com/digoal/blog/blob/master/201610/20161018_01.md">《postgresql 使用advisory lock或skip locked消除行锁冲突, 提高几十倍并发更新效率》</a>

<a href="https://github.com/digoal/blog/blob/master/201611/20161117_01.md">《聊一聊双十一背后的技术 - 不一样的秒杀技术, 裸秒》</a>

advisory lock分为事务级锁和会话级锁,在会话迁移时,会话处于idle状态, 只需要关注会话级锁。

注意复原时,需要指定是否为shared lock。

序列使用后,会在会话中存储最后一次使用的序列的val,以及每个序列被使用后的最后一次获取的val。

序列虽然可以设置当前值,但是会影响全局,强烈建议不要这么做。

目前没有好的方法复原序列在会话中的lastval。

主备切换时,将会话资源状态进行平移,可以大幅提升客户端的体验,使得数据库硬件维护、迁移等工作也会变得更加轻松。

中间件需要维护客户端连接和数据库会话的映射关系,平移后映射关系同样需要保持一致。