暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Postgres源码阅读(1)---守护进程和服务进程的前世今生

Magicio 2021-07-01
882

    PostgreSQL数据库采用C/S架构,系统会为每个客户端分配一个后台服务进程,也就是postgres进程。当客户端想要访问数据库的时候,就调用接口(libpq、ODBC、JDBC)把连接请求发送给守护进程Postmaster,Postmaster就会fork出一个新的服务进程postgres为用户服务,此后客户端和服务端就不再通过Postmaster而是直接与postgres进程通信。

    Postmaster总是监听用户连接请求并为用户分配服务进程postgres,而postgres则负责为客户执行各种操作。

    下面聊一下Postmaster监听请求并将请求转交给postgres的整个流程(读源码参考的《PostgreSQL数据库内核分析》这本书)。

    Postmaster进程:


    postgres进程:

  

    Postgres数据库启动后,Postmaster会调用ServerLoop函数来循环等待客户端的连接请求,该函数主体是个死循环,栈调用关系如下:

    #0  0x00007fe62b20af53 in __select_nocancel () from lib64/libc.so.6
    #1 0x00000000007070a7 in ServerLoop () at postmaster.c:1670
    #2 0x00000000007083d9 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x126e950) at postmaster.c:1379
    #3 0x00000000006740f4 in main (argc=3, argv=0x126e950) at main.c:228

        循环中会首先调用select系统函数等待客户端提出的连接请求:

      selres = select(nSockets, &rmask, NULL, NULL, &timeout);

          当select函数正常返回后,扫描ListenSocket数组中的每个监听套接字描述符,如果发现该套接字上有用户连接请求,将调用ConnCreate函数创建一个Port结构体,之后调用accept系统函数接受由该监听套接字所维护的用户连接请求。

          成功创建Port结构体后,调用BackendStartup函数,该函数会先创建出一个Backend结构体,之后通过调用fork_process生成postgres进程(fork_process会调用系统函数fork,fork被调用一次,返回两次,两次返回的区别是子进程的返回值是0,父进程的返回值则是新建子进程的进程ID,父进程会将子进程pid等postgres进程信息填充到Backend结构体,并将此结构添加到BackendList,这样Postmaster就可以通过BackendList来监控其子进程;子进程则会调用BackendInitializ来获取客户端的信息(客户端主机名,端口,用户名,数据库等)并填入Port中,之后调用BackendRun设置postgres运行时参数并进行初始化的工作,最后调用PostgresMain函数进入postgres的执行入口),自此与客户端的交互权由Postmaster转给postgres,然后关闭客户端与Postmaster的连接,释放Port结构体,检查辅助进程BgWriter、SysLogger等是否正常运行,完成后进行下一次循环。

        for (i = 0; i < MAXLISTEN; i++)
        {
        if (ListenSocket[i] == PGINVALID_SOCKET)
        break;
        if (FD_ISSET(ListenSocket[i], &rmask))
        {
        Port *port;
        port = ConnCreate(ListenSocket[i]);
        if (port)
        {
        BackendStartup(port);
                  /*
        * We no longer need the open socket or port structure
        * in this process
        */
                   StreamClose(port->sock);
        ConnFree(port);
        }
        }
        }

            父进程在fork之后的执行流程:

            /*
          * Everything's been successful, it's safe to add this backend to our list
          * of backends.
          */
          bn->pid = pid;
          bn->bkend_type = BACKEND_TYPE_NORMAL; /* Can change later to WALSND */
          dlist_push_head(&BackendList, &bn->elem);

              子进程在fork之后的执行流程:

              if (pid == 0)        /* child */
            {
            free(bn);
            /* Detangle from postmaster */
            InitPostmasterChild();
            /* Close the postmaster's sockets */
            ClosePostmasterPorts(false);
            /* Perform additional initialization and collect startup packet */
            BackendInitialize(port);
            /* And run the backend */
            BackendRun(port);
            }

                服务进程postgres启动后的栈调用关系:

              Thread 1 (Thread 0x7fe62c024740 (LWP 152)):
              #0 0x00007fe62b214463 in __epoll_wait_nocancel () from /lib64/libc.so.6
              #1 0x0000000000759ee9 in WaitEventSetWaitBlock (nevents=1, occurred_events=0x7ffe7f3ae770, cur_timeout=-1,
              set=0x129c728) at latch.c:1048
              #2 WaitEventSetWait (set=0x129c728, timeout=timeout@entry=-1,
              occurred_events=occurred_events@entry=0x7ffe7f3ae770, nevents=nevents@entry=1,
              wait_event_info=wait_event_info@entry=100663296) at latch.c:1000
              #3 0x00000000006659a8 in secure_read (port=0x12947c0, ptr=0xdb40e0 <PqRecvBuffer>, len=8192)
              at be-secure.c:173
              #4 0x000000000066f970 in pq_recvbuf () at pqcomm.c:963
              #5 0x00000000006703c0 in pq_getbyte () at pqcomm.c:1006
              #6 0x000000000077b122 in SocketBackend (inBuf=inBuf@entry=0x7ffe7f3ae910) at postgres.c:341
              #7 0x000000000077ca17 in ReadCommand (inBuf=inBuf@entry=0x7ffe7f3ae910) at postgres.c:514
              #8 0x000000000077f8cc in PostgresMain (argc=<optimized out>, argv=argv@entry=0x129c9f0,
              dbname=0x129c868 "postgres", username=<optimized out>) at postgres.c:4124
              #9 0x00000000007043ed in BackendRun (port=port@entry=0x12947c0) at postmaster.c:4361
              #10 0x0000000000706ec9 in BackendStartup (port=port@entry=0x12947c0) at postmaster.c:4033
              #11 0x000000000070715e in ServerLoop () at postmaster.c:1706
              #12 0x00000000007083d9 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x126e950) at postmaster.c:1379
              #13 0x00000000006740f4 in main (argc=3, argv=0x126e950) at main.c:228


              文章转载自Magicio,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论