gpdb icon indicating copy to clipboard operation
gpdb copied to clipboard

V2 improvement of cancel/terminate mechanism between QD and QE

Open charliettxx opened this issue 11 months ago • 5 comments

Background

Currently, the Query Dispatcher (QD) endeavors to terminate all Query Executor (QE) processes within gangs upon receiving cancellation requests such as pg_cancel_backend()/pg_terminate_backend() from the frontend.

The process should proceed as follows:

  • Upon receiving the cancellation signal from the frontend, QD handles it within the interrupt exception and subsequently dispatches a cancellation request packet to each QE process within the slice/gang.
  • For instance, if we have 3 segments and 3 slices, the total number of QE processes would be 3x3 = 9. Accordingly, QD should dispatch cancel requests to segments 3x3 = 9 times.
  • Upon reception of the cancel request packet, the QE postmaster forks a new backend process to manage it. The forked process then invokes kill() to terminate the respective QE process.

However, overhead arises at this point. It is unnecessary to dispatch the cancel packet to each QE process within the same segment, as forking too many processes could lead to performance degradation, particularly in high-load environments.

What's we improve

1. Terminate all backends with same session ID in one packet

For a single segment, we only need to send the cancel packet once to terminate all backends with the same session ID. Therefore, we send a CancelMppRequestPacket containing the session ID to the QE. The QE then parses the packet and calls GetSessionQEPids() to retrieve all relevant backend process IDs (PIDs), ultimately terminating them.

2. Async sending packet to all segments

To handle multiple segments efficiently, we employ an asynchronous approach for sending packets. Given the possibility of numerous segments needing communication, if one segment is busy and prevents sending, it can result in a hang while attempting to send packets to other segments. Thus, we adopt asynchronous packet transmission to segments.

Presently, we utilize nonblock_cancel() for sending packets and configure the socket as non-blocking before returning. We utilize select() to await responses from all segments in the signalQEs(). (Note: We set the select timeout to 6 seconds and repeat the process a maximum of 10 times. If a response takes over 1 minute, an error will be raised.)

Previous PR is https://github.com/greenplum-db/gpdb/pull/17125 and there are some discussions there.

Here are some reminders before you submit the pull request

  • [x] Add tests for the change
  • [ ] Document changes
  • [ ] Communicate in the mailing list if needed
  • [ ] Pass make installcheck
  • [ ] Review a PR in return to support the community

charliettxx avatar Mar 12 '24 08:03 charliettxx