后台工作进程

后台工作进程

可以扩展Greenplum数据库以在单独的进程中运行用户提供的代码。 这些进程由postgres启动,停止和监视,这使得它们的生命周期与服务器的状态紧密相关。 这些进程可以选择连接到Greenplum数据库的共享内存区域并在内部连接到数据库; 它们还可以串行运行多个事务,就像常规的客户端连接服务器进程一样。 此外,通过链接到libpq,它们可以连接到服务器,并且行为类似于常规客户端应用程序。

Warning: 使用后台工作进程存在相当大的稳健性和安全性风险,因为使用C语言编写时,它们可以不受限制地访问数据。 希望启用包含后台工作进程的模块的管理员应该格外小心。 只允许经过仔细审核的模块运行后台工作进程。

通过在shared_preload_libraries服务器配置参数中包含模块名称,可以在启动Greenplum数据库时初始化后台工作程序。 希望运行后台工作程序的模块可以通过从_PG_init()调用RegisterBackgroundWorker(BackgroundWorker *worker)来注册它。 通过调用函数RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle),系统启动并运行后,也可以启动后台工作程序。 与只能在postmaster中调用的RegisterBackgroundWorker不同,必须从常规后端调用RegisterDynamicBackgroundWorker

因此定义了BackgroundWorker结构:

typedef void (*bgworker_main_type)(Datum main_arg);
typedef struct BackgroundWorker
{
    char        bgw_name[BGW_MAXLEN];
    int         bgw_flags;
    BgWorkerStartTime bgw_start_time;
    int         bgw_restart_time;       /* in seconds, or BGW_NEVER_RESTART */
    bgworker_main_type bgw_main;
    char        bgw_library_name[BGW_MAXLEN];   /* only if bgw_main is NULL */
    char        bgw_function_name[BGW_MAXLEN];  /* only if bgw_main is NULL */
    Datum       bgw_main_arg;
    int         bgw_notify_pid;
} BackgroundWorker;

bgw_name是一个在日志消息,进程列表和类似上下文中使用的字符串。

bgw_flags是一个按位或位掩码,表示模块想要的功能。 可能的值是BGWORKER_SHMEM_ACCESS(请求共享内存访问)和BGWORKER_BACKEND_DATABASE_CONNECTION(请求建立数据库连接的能力,以后可以通过它运行事务和查询)。 使用BGWORKER_BACKEND_DATABASE_CONNECTION连接到数据库的后台工作进程还必须使用BGWORKER_SHMEM_ACCESS附加共享内存,否则工作进程将启动失败。

bgw_start_timepostgres应该启动进程的服务器状态; 它可以是BgWorkerStart_PostmasterStart之一(一旦postgres完成自己的初始化就开始;请求它的进程不符合数据库连接的条件), BgWorkerStart_ConsistentState(一旦在热备份中达到一致状态就开始,允许进程连接到数据库并运行只读查询)和BgWorkerStart_RecoveryFinished(系统进入正常读写状态后立即启动)。 请注意,最后两个值在不是热备份的服务器中是等效的。 请注意,此设置仅指示何时启动进程; 当达到不同的状态时,它们不会停止。

bgw_restart_timepostgres在重新启动进程之前应该等待的时间间隔(以秒为单位),以防它崩溃。 它可以是任何正值,或BGW_NEVER_RESTART,表示在发生崩溃时不重启进程。

bgw_main是指向启动进程时要运行的函数的指针。 此函数必须采用Datum类型的单个参数并返回voidbgw_main_arg将作为唯一参数传递给它。 请注意,全局变量MyBgworkerEntry指向在注册时传递的BackgroundWorker结构的副本。 bgw_main可能为NULL; 在这种情况下,将使用bgw_library_namebgw_function_name来确定入口点。 这对postmaster启动后启动的后台工作进程很有用,其中postmaster没有加载必需的库。

bgw_library_name是库的名称,在该库中应该寻找后台工作程序的初始入口点。 除非bgw_main为NULL,否则它将被忽略。 但是如果bgw_main为NULL,则命名库将由工作进程动态加载,bgw_function_name将用于标识要调用的函数。

bgw_function_name是动态加载库中函数的名称,该库应该用作新后台工作程序的初始入口点。 除非bgw_main为NULL,否则它将被忽略。

bgw_notify_pid是一个Greenplum数据库后端进程的PID,postmaster应该在进程启动或退出时向其发送SIGUSR1。 对于在postmaster启动时注册的工作进程,或者注册工作进程的后端不希望等待工作进程启动时,应该为0。 否则,它应该初始化为MyProcPid

一旦运行,该进程可以通过调用BackgroundWorkerInitializeConnection(char *dbname, char *username)连接到数据库。 这允许进程使用SPI接口运行事务和查询。 如果dbname为NULL,则会话未连接到任何特定数据库,但可以访问共享目录。 如果username为NULL,则进程将以initdb期间创建的超级用户身份运行。 BackgroundWorkerInitializeConnection只能在每个后台进程中调用一次,无法切换数据库。

当控制到达bgw_main函数时,信号最初被阻止,并且必须被它解除阻塞; 这是为了允许进程在必要时自定义其信号处理程序。 通过调用BackgroundWorkerUnblockSignals可以在新进程中取消阻止信号,并通过调用BackgroundWorkerBlockSignals来阻止信号。

如果后台工作程序的bgw_restart_time配置为BGW_NEVER_RESTART, 或者退出时退出代码为0或由TerminateBackgroundWorker终止,则退出时将由postmaster自动取消注册。 否则,它将在通过bgw_restart_time配置的时间段之后重新启动,或者如果postmaster由于后端故障而重新初始化群集时立即重新启动。 需要暂时暂停执行的后端应该使用可中断的睡眠而不是退出; 这可以通过调用WaitLatch()来实现。 确保在调用该函数时设置WL_POSTMASTER_DEATH标志,并在postgres本身已终止的紧急情况下验证返回代码以提示退出。

当使用RegisterDynamicBackgroundWorker函数注册后台工作程序时,执行注册的后端可以获得有关工作进程状态的信息。 希望这样做的后端应该将BackgroundWorkerHandle *的地址作为RegisterDynamicBackgroundWorker的第二个参数传递。 如果工作程序已成功注册,则此指针将使用不透明句柄进行初始化, 该句柄随后可以传递给GetBackgroundWorkerPid(BackgroundWorkerHandle *, pid_t *)TerminateBackgroundWorker(BackgroundWorkerHandle *)GetBackgroundWorkerPid可用于轮询工作进程的状态:返回值BGWH_NOT_YET_STARTED表示工作进程尚未由postmaster启动; BGWH_STOPPED表示它已经启动但不再运行; 和BGWH_STARTED表示它当前正在运行。 在最后一种情况下,PID也将通过第二个参数返回。 TerminateBackgroundWorker使postmaster在运行时将SIGTERM发送给worker,并在它不运行时立即取消注册。

在某些情况下,注册后台工作进程的进程可能希望等待工作进程启动。 这可以通过将bgw_notify_pid初始化为MyProcPid, 然后将在注册时获得的BackgroundWorkerHandle *传递给WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle,pid_t *)函数来实现。 此函数将阻塞,直到postmaster尝试启动后台工作程序,或直到postmaster死亡。 如果后台运行器正在运行,则返回值将为BGWH_STARTED,并且PID将被写入提供的地址。 否则,返回值将为BGWH_STOPPEDBGWH_POSTMASTER_DIED

worker_spi模块包含一个工作示例,演示了一些有用的技术。

注册后台工作进程的最大数量受max-worker-processes限制。