gpdb
gpdb copied to clipboard
V2 improvement of cancel/terminate mechanism between QD and QE
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