PostgreSQL 通过SQL接口关闭、重启数据库-阿里云开发者社区

开发者社区> 德哥> 正文

PostgreSQL 通过SQL接口关闭、重启数据库

简介: PostgreSQL 通过SQL接口关闭、重启数据库
+关注继续查看

背景

如何通过SQL接口直接关闭数据库,或者重启数据库?

关闭和重启数据库是一个风险较大的操作,如果能通过SQL来关闭,重启数据库,当然是很难想象的,因为SQL通常是使用接口,而不是管理接口。当然并不是数据库做不到通过SQL管理数据库,而是这确实是风险较大且并不是数据库核心的能努力。

但是为了方便管理,数据库还是提供了很多管理函数(通过SQL调用)。例如:

https://www.postgresql.org/docs/11/functions-info.html

那么能不能通过SQL接口来关闭,或者重启数据库呢?(通常我们需要登陆到数据库所在的操作系统,执行pg_ctl来实现)

关闭数据库的底层实现

实际上关闭数据库是往postgres master进程(数据库启动时的父进程)发送信号,进程在收到信号后会进行相应的操作。可以通过看postmaster.c代码或通过man postgres得到这个信息:

man postgres

To terminate the postgres server normally, the signals SIGTERM, SIGINT, or SIGQUIT can be used.   
The first will wait for all clients to terminate before quitting,   
the second will forcefully disconnect all clients,   
and the third will quit immediately without proper shutdown, resulting in a recovery run during restart.   

如何获得postmaster进程pid呢?

直接读postmaster.pid文件即可得到:

postgres=# select * from pg_read_file('postmaster.pid');  
        pg_read_file          
----------------------------  
 30503                     +  
 /data01/digoal/pg_root8001+  
 1549031862                +  
 8001                      +  
 .                         +  
 0.0.0.0                   +  
   8001001  39288833       +  
 ready                     +  
   
(1 row)  

30503 为postmaster进程的PID。

关闭数据库就是往这个PID发送信号(SIGTERM 正常关闭, SIGINT 快速关闭, or SIGQUIT 暴力关闭)。

发送信号给数据库进程

src/backend/utils/adt/misc.c

1、发送给postmaster进程SIGHUP信号,用于reload conf。

/*  
 * Signal to reload the database configuration  
 *  
 * Permission checking for this function is managed through the normal  
 * GRANT system.  
 */  
Datum  
pg_reload_conf(PG_FUNCTION_ARGS)  
{  
        if (kill(PostmasterPid, SIGHUP))  
        {  
                ereport(WARNING,  
                                (errmsg("failed to send signal to postmaster: %m")));  
                PG_RETURN_BOOL(false);  
        }  
  
        PG_RETURN_BOOL(true);  
}  

2、发送给普通进程,用于cancel query或terminate session

/*  
 * Signal to terminate a backend process.  This is allowed if you are a member  
 * of the role whose process is being terminated.  
 *  
 * Note that only superusers can signal superuser-owned processes.  
 */  
Datum  
pg_terminate_backend(PG_FUNCTION_ARGS)  
{  
        int                     r = pg_signal_backend(PG_GETARG_INT32(0), SIGTERM);  
  
        if (r == SIGNAL_BACKEND_NOSUPERUSER)  
                ereport(ERROR,  
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),  
                                 (errmsg("must be a superuser to terminate superuser process"))));  
  
        if (r == SIGNAL_BACKEND_NOPERMISSION)  
                ereport(ERROR,  
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),  
                                 (errmsg("must be a member of the role whose process is being terminated or member of pg_signal_backend"))));  
  
        PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);  
}  
/*  
 * Signal to cancel a backend process.  This is allowed if you are a member of  
 * the role whose process is being canceled.  
 *  
 * Note that only superusers can signal superuser-owned processes.  
 */  
Datum  
pg_cancel_backend(PG_FUNCTION_ARGS)  
{  
        int                     r = pg_signal_backend(PG_GETARG_INT32(0), SIGINT);  
  
        if (r == SIGNAL_BACKEND_NOSUPERUSER)  
                ereport(ERROR,  
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),  
                                 (errmsg("must be a superuser to cancel superuser query"))));  
  
        if (r == SIGNAL_BACKEND_NOPERMISSION)  
                ereport(ERROR,  
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),  
                                 (errmsg("must be a member of the role whose query is being canceled or member of pg_signal_backend"))));  
  
        PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);  
}  

src/backend/utils/adt/misc.c

/*  
 * Send a signal to another backend.  
 *  
 * The signal is delivered if the user is either a superuser or the same  
 * role as the backend being signaled. For "dangerous" signals, an explicit  
 * check for superuser needs to be done prior to calling this function.  
 *  
 * Returns 0 on success, 1 on general failure, 2 on normal permission error  
 * and 3 if the caller needs to be a superuser.  
 *  
 * In the event of a general failure (return code 1), a warning message will  
 * be emitted. For permission errors, doing that is the responsibility of  
 * the caller.  
 */  
#define SIGNAL_BACKEND_SUCCESS 0  
#define SIGNAL_BACKEND_ERROR 1  
#define SIGNAL_BACKEND_NOPERMISSION 2  
#define SIGNAL_BACKEND_NOSUPERUSER 3  
static int  
pg_signal_backend(int pid, int sig)  
{  
。。。  
        if (proc == NULL)  
        {  
                /*  
                 * This is just a warning so a loop-through-resultset will not abort  
                 * if one backend terminated on its own during the run.  
                 */  
                ereport(WARNING,  
                                (errmsg("PID %d is not a PostgreSQL server process", pid)));  
                return SIGNAL_BACKEND_ERROR;  
        }  
。。。  

PG内部并没有开放一个SQL接口来停库,所以我们需要自己写一个

vi pg_fast_stop.c  
  
  
#include <signal.h>   
#include "fmgr.h"    
#include "postgres.h"   
  
PG_MODULE_MAGIC;    
    
PG_FUNCTION_INFO_V1(pg_fast_stop);    
    
  
Datum  
pg_fast_stop(PG_FUNCTION_ARGS)  
{  
        if (kill(PostmasterPid, SIGINT))  
        {  
                ereport(WARNING,  
                                (errmsg("failed to send signal to postmaster: %m")));  
                PG_RETURN_BOOL(false);  
        }  
  
        PG_RETURN_BOOL(true);  
}  
gcc -O3 -Wall -Wextra -I /home/digoal/postgresql-11.1/src/include -g -fPIC -c ./pg_fast_stop.c -o pg_fast_stop.o  
gcc -O3 -Wall -Wextra -I /home/digoal/postgresql-11.1/src/include -g -shared pg_fast_stop.o -o libpg_fast_stop.so   
  
cp libpg_fast_stop.so $PGHOME/lib/  
psql   
  
create or replace function pg_fast_stop() returns int as '$libdir/libpg_fast_stop.so', 'pg_fast_stop' language C STRICT;    

试用:

postgres=# select pg_fast_stop();  
 pg_fast_stop
------------  
          1  
(1 row)  
  
数据库已关机  
  
postgres=# \dt  
FATAL:  terminating connection due to administrator command  
server closed the connection unexpectedly  
        This probably means the server terminated abnormally  
        before or while processing the request.  
The connection to the server was lost. Attempting reset: Failed.  
!> \q  

如何实现SQL接口重启数据库呢?

因为往POSTMASTER PID发送信号只能关闭数据库,无法重启数据库。那么怎么实现重启呢?

1、#restart_after_crash = on # reinitialize after backend crash?

利用普通用户进程被KILL -9来自动重启,这个是postmaster守护进程自动执行的重启动作。

2、利用plsh存储过程语言,直接调用pg数据库操作系统的pg_ctl命令来重启。

https://github.com/petere/plsh

参考

https://github.com/petere/plsh

https://www.postgresql.org/docs/11/functions-info.html

https://www.postgresql.org/docs/11/functions-admin.html

src/backend/utils/adt/misc.c

PostgreSQL 许愿链接

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.

9.9元购买3个月阿里云RDS PostgreSQL实例

PostgreSQL 解决方案集合

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Android TextView中文字通过SpannableString来设置超链接、颜色、字体等属性
在Android中,TextView是我们最常用的用来显示文本的控件。 <p>  一般情况下,TextView中的文本都是一个样式。那么如何对于TextView中各个部分的文本来设置字体,大小,颜色,样式,以及超级链接等属性呢?下面我们通过SpannableString的具体实例操作来演示一下。</p> <p><br></p> <p>   res-layout-main.xml</p
1243 0
sql server 2008 开启1433端口,开启远程连接
通常情况下只需要设置两处
1199 0
实践 —— 亲测从 RDS MySQL 通过数据集成导入 MaxCompute
作者尝试了从RDS 的MySQL数据库到MaxCompute的 ODPS 的数据同步过程,并导入成功。有需要的同学赶紧试起来吧~~~
2517 0
通过SQL Server 2008数据库复制实现数据库同步备份
原文 通过SQL Server 2008数据库复制实现数据库同步备份 SQL Server 2008数据库复制是通过发布/订阅的机制进行多台服务器之间的数据同步,我们把它用于数据库的同步备份。这里的同步备份指的是备份服务器与主服务器进行 实时数据同步,正常情况下只使用主数据库服务器,备份服务器只在主服务器出现故障时投入使用。
1492 0
iOS10 适配 ATS(app支持https通过App Store审核) 韩俊强的博客
一. HTTPS 其实HTTPS从最终的数据解析的角度,与HTTP没有任何的区别,HTTPS就是将HTTP协议数据包放到SSL/TSL层加密后,在TCP/IP层组成IP数据报去传输,以此保证传输数据的安全;而对于接收端,在SSL/TSL将接收的数据包解密之后,将数据传给HTTP协议层,就是普通的HTTP数据。
904 0
通过DBCC整理Sqlserver数据库表索引碎片
昨天检查了一张效率极慢的表,两年多没有维护,逻辑扫描碎片高达99.81%,于是开始对这个表进行重点跟踪和记录日志。今天用DBCC SHOWCONTIG WITH TABLERESULTS 命令检查了一下所有表的概况,然后参照着MSDN对字段的说明,发现问题比较严重。
944 0
SQLite C语言接口
数据表设计 create table tbl_emp( id integer primary key , name varchar(40), age smallint, birthday datetime); sqlite3是数据库连接对象,用来操作数...
695 0
OAF_JDBC系列2 - 通过JDBC连接SQLSERVER数据库DriverManager.getConnection
d          try{          Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");          String connectionSQLServer = "jdbc:sqlserver://gavinmysql.
722 0
+关注
德哥
公益是一辈子的事, I&#39;m digoal, just do it.
2153
文章
245
问答
来源圈子
更多
阿里云数据库:帮用户承担一切数据库风险,给您何止是安心!支持关系型数据库:MySQL、SQL Server、PostgreSQL、PPAS(完美兼容Oracle)、自研PB级数据存储的分布式数据库Petadata、自研金融级云数据库OceanBase支持NoSQL数据库:MongoDB、Redis、Memcache更有褚霸、丁奇、德哥、彭立勋、玄惭、叶翔等顶尖数据库专家服务。
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
《Nacos架构&原理》
立即下载
《看见新力量:二》电子书
立即下载
云上自动化运维(CloudOps)白皮书
立即下载