*** a/doc/src/sgml/high-availability.sgml --- b/doc/src/sgml/high-availability.sgml *************** *** 1084,1091 **** primary_slot_name = 'node_a_slot' In the case that synchronous_commit is set to remote_apply, the standby sends reply messages when the commit record is replayed, making the transaction visible. ! If the standby is chosen as a synchronous standby, from a priority ! list of synchronous_standby_names on the primary, the reply messages from that standby will be considered along with those from other synchronous standbys to decide when to release transactions waiting for confirmation that the commit record has been received. These parameters --- 1084,1091 ---- In the case that synchronous_commit is set to remote_apply, the standby sends reply messages when the commit record is replayed, making the transaction visible. ! If the standby is chosen as a synchronous standby, according to the setting ! of synchronous_standby_names on the primary, the reply messages from that standby will be considered along with those from other synchronous standbys to decide when to release transactions waiting for confirmation that the commit record has been received. These parameters *************** *** 1228,1233 **** synchronous_standby_names = 'FIRST 2 (s1, s2, s3)' --- 1228,1247 ---- the rate of generation of WAL data. + + A quorum-based synchronous replication is basically more efficient than + a priority-based one when you specify multiple standbys in + synchronous_standby_names and want to replicate + the transactions to some of them synchronously. In this case, + the transactions in a priority-based synchronous replication must wait for + reply from the slowest standby in synchronous standbys chosen based on + their priorities, and which may increase the transaction latencies. + On the other hand, using a quorum-based synchronous replication may + improve those latencies because it makes the transactions wait only for + replies from the requested number of faster standbys in all the listed + standbys, i.e., such slow standby doesn't block the transactions. + + *************** *** 1246,1254 **** synchronous_standby_names = 'FIRST 2 (s1, s2, s3)' The best solution for high availability is to ensure you keep as many synchronous standbys as requested. This can be achieved by naming multiple potential synchronous standbys using synchronous_standby_names. ! The standbys whose names appear earlier in the list will be used as ! synchronous standbys. Standbys listed after these will take over ! the role of synchronous standby if one of current ones should fail. --- 1260,1279 ---- The best solution for high availability is to ensure you keep as many synchronous standbys as requested. This can be achieved by naming multiple potential synchronous standbys using synchronous_standby_names. ! ! ! ! In a priority-based synchronous replication, the standbys whose names ! appear earlier in the list will be used as synchronous standbys. ! Standbys listed after these will take over the role of synchronous standby ! if one of current ones should fail. ! ! ! ! In a quorum-based synchronous replication, all the standbys appearing ! in the list will be used as candidates for synchronous standbys. ! Even if one of them should fail, the other standbys will keep performing ! the role of candidates of synchronous standby. *** a/src/backend/replication/syncrep.c --- b/src/backend/replication/syncrep.c *************** *** 53,58 **** --- 53,62 ---- * in the list. All the standbys appearing in the list are considered as * candidates for quorum synchronous standbys. * + * If neither FIRST nor ANY is specified, FIRST is used as the method. + * This is for backward compatibility with 9.6 or before where only a + * priority-based sync replication was supported. + * * Before the standbys chosen from synchronous_standby_names can * become the synchronous standbys they must have caught up with * the primary; that may take some time. Once caught up, *************** *** 629,634 **** SyncRepGetNthLatestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, --- 633,639 ---- i++; } + /* Sort each array in descending order */ qsort(write_array, len, sizeof(XLogRecPtr), cmp_lsn); qsort(flush_array, len, sizeof(XLogRecPtr), cmp_lsn); qsort(apply_array, len, sizeof(XLogRecPtr), cmp_lsn);