We all know that when using a cluster based on Galera (Codership) such as Percona XtraDB Cluster (PXC), it is recommended to deploy an odd number of nodes. 
The generic answer to this recommendation is that otherwise the risk of having an inconsistent cluster (like split-brain) is higher. (see Get started with Percona XtraDB Cluster – Percona XtraDB Cluster )
As a reminder, when split-brain occurs, a cluster will stop accepting queries, which is what a safe solution should do while waiting for the DBA to review and decide which of the two nodes is the leader. I do not even want to describe the infamous wsrep_provider_options=”pc.ignore_sb = yes”, which has been the cause of many, many nights spent trying to reconcile the corrupted datasets. If you have it, remove it.
However, in Galera, we also have the setting wsrep_provider_options=”pc.weight=N”. With it, we can define a specific weight in the quorum calculation for each node.
The question naturally arises: if we can assign a different weight to each node, why can’t we have an even number of nodes and assign them different weights?
The answer to the question is simple, yes, we can.
What is not simple is to identify who should have a different weight and how to distribute it.
To understand the problem, we need to review how the quorum is calculated (I have touched on the topic long ago here TusaCentral – Geographic replication and quorum Calculation in MySQL/Galera) and what a View is.
In Percona XtraDB Cluster (PXC) and Galera, a View (or cluster view) is the agreed-upon membership of the cluster at any specific moment in time. It represents the exact list of nodes that are currently connected, synchronized, and actively communicating with each other.
Whenever a node joins the cluster, leaves gracefully, or drops out due to a network failure, the remaining connected nodes negotiate a new View and assign it a unique View ID.
Its relationship to the Primary Component (PC) is based on quorum:
Essentially, a View defines who is currently connected to each other, while the Primary Component is the specific View that has enough members to safely keep the database running.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
2026-11-10T13:45:01.498927Z 0 [Note] [MY-000000] [Galera] Node 49d8df08-bad6 state primary 2026-11-10T13:45:01.500967Z 0 [Note] [MY-000000] [Galera] Current view of cluster as seen by this node view (view_id(PRIM,49d8df08-bad6,93) memb { 49d8df08-bad6,2 5ce1a9aa-8e06,2 8458c8f0-9b8f,2 } joined {} left {} partitioned { 85a6e937-b8c4,2} ) |
The formula for calculating the quorum is:
Σ p·w < 2·(Σ m·w + Σ l·w)
Where:
p = members of the last PRIMARY view
l = members that left gracefully (LEFT)
m = members of the component being evaluated
w = pc.weight (0–255).
In short, the total weight of the previous Primary view must be less than twice the weight of the members of the new component plus the weight of the members that left gracefully. To be clear, a crashed / unreachable node (DOWN or in another partition) still counts in Σ p·w, so it pushes the threshold up.
A graceful leave (LEFT), instead, is credited to the new component. Also, any node that was not in the last PC is dropped from calculation, so a node that has just joined or rejoined contributes nothing to this check.
Look for the function:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
bool gcomm::pc::Proto::have_quorum(const View& view, const View& pc_view) const { // Compare only against members and left which were part of the pc_view. gcomm::NodeList memb_intersection( node_list_intersection(view.members(), pc_view.members())); gcomm::NodeList left_intersection( node_list_intersection(view.left(), pc_view.members())); if (have_weights(...)) return (weighted_sum(memb_intersection, instances_) * 2 + weighted_sum(left_intersection, instances_) > weighted_sum(pc_view.members(), instances_)); else return (memb_intersection.size()*2 + left_intersection.size() > pc_view.members().size()); } |
(repo https://github.com/percona/galera/tree/a6b54d887d58bae43ae3f46f5696195329405b7e)
Now let’s assume that we have a cluster of 4 nodes, there are many possible combinations where things will work and where instead they will hit us badly.
The most common is the split-brain scenario:
To prevent this, we may decide to use one node with different weight:
Here we go, problem solved… really?
No, because changing weights may cause other issues, for example if we calculate the weights wrongly with respect to the number of nodes:
In this case one single node could bring down the whole cluster.
Of course, if we perform standard operations, or crashes happen in cascade and the cluster has time to rebuild the Primary Component, all will work well:
The problem is that:
The real question is not if we can do it but whether it is worth it: does using an odd number of nodes help or not?
The answer is partly.
Odd nodes get rid of the exact-tie case in the simple situation. They don’t completely stop the cluster losing PRIMARY state.
What matters is the parity of the total weight, not the node count.
A tie happens when present = partitioned, which means the counted weight (Σw(PC) − Left) splits exactly in half.
That is only possible when the counted weight is even. So:
Where odd nodes still lose PRIMARY:
In practice: aim for an odd total weight in the PC and use a third site or an arbitrator for multi-DC setups. Even then, a cluster that has already shrunk can become even again, so the last-two-nodes tie can’t be designed away.
Only pc.ignore_sb or a manual bootstrap gets past it. But you do not want to go there.
Given this, and given that what counts is NOT the number of nodes but the balance in the weight calculation, is using weights the right way to compensate?
Well, this may be my personal opinion, but in my experience, weights make the cluster harder to manage, and the stability they add is narrow.
A weight-2 node acts like two nodes that always fail together. Four nodes weighted 2,1,1,1 behave like a 5-node cluster where two of the nodes share one box.
We trade a split-brain tie for a single point of fate:
The set of survivable failures shifts rather than grows. We still tolerate only one arbitrary failure plus some specific splits.
What weights add to day-to-day operations:
Simple to most complex for the same goal:
Weights don’t make the cluster generally more stable, and they add operational complexity. They make sense as a deliberate tiebreaker, not as a fix for even node counts.
I stand by the evergreen KISS motto: Keep It Simple and Straightforward.
Having a PXC cluster with more than 3 nodes makes sense in very few cases, and only to scale reads or if you plan to kill 2 nodes at the same time on a cluster of 5.
Given the significant complications the increase of nodes or the use of weight brings, I do not really see why someone in a healthy state of mind should look for trouble.
Just because it can be done, it doesn’t mean “do it”, especially if the gain is minimal and the complexity increases.
Do yourself a favor: keep your cluster to the minimum, to what is really needed and do not try to stretch it. You will save yourself from spending miserable nights doing cluster recovery or worse data reconciliation.
Great MySQL to everyone.
Resources
RELATED POSTS