In YugabyteDB, read replicas are specialized nodes designed to handle read-heavy workloads by offloading read operations from the primary cluster. They are typically deployed in geographically distributed locations to serve low-latency reads closer to the user or application.
Read replicas serve as a read-only extension of the primary data in the universe.
While applications can send write requests to read replicas, these requests are internally redirected to the source of truth—the primary cluster. This redirection is possible because read replicas have full awareness of the universe’s topology.
For your use case, instead of allowing the read replica to redirect writes, you may prefer to have it reject write requests entirely.
default_transaction_read_only
. Here’s a quick example using yugabyted:
[root@cloud-server-0 yb2]# yugabyted start --advertise_address=127.0.0.1 --base_dir=~/yb01 --cloud_location aws.us-east-1.us-east-1a > start_primary.log
[root@cloud-server-0 yb2]# yugabyted start --read_replica --cloud_location aws.us-west-2.us-west-2a --advertise_address=127.0.0.2 --base_dir=~/yb02 --join=127.0.0.1 --tserver_flags="ysql_pg_conf_csv={default_transaction_read_only=true}" > start_read_replica.log
[root@cloud-server-0 yb2]# ysqlsh -h 127.0.0.1 -c "SELECT host, node_type, region FROM yb_servers() ORDER BY host;"
host | node_type | region
-----------+--------------+-----------
127.0.0.1 | primary | us-east-1
127.0.0.2 | read_replica | us-west-2
(2 rows)
[root@cloud-server-0 yb2]# ysqlsh -h 127.0.0.1 -c "CREATE TABLE test(c1 INT PRIMARY KEY, c2 TEXT);"
CREATE TABLE
[root@cloud-server-0 yb2]# ysqlsh -h 127.0.0.1 -c "INSERT INTO test (c1, c2) VALUES (1, 'A'), (2, 'B'), (3, 'C');"
INSERT 0 3
[root@cloud-server-0 yb2]# ysqlsh -h 127.0.0.1 -c "SELECT * FROM test;"
c1 | c2
----+----
1 | A
2 | B
3 | C
(3 rows)
[root@cloud-server-0 yb2]# ysqlsh -h 127.0.0.2 -c "INSERT INTO test (c1, c2) VALUES (4, 'D'), (5, 'E'), (6, 'F');"
ERROR: cannot execute INSERT in a read-only transaction
Note that while we can read data while connected to the read replica (127.0.0.2), but we could not write data.
The key is to set default_transaction_read_only=true
using the ysql_pg_conf_csv
TServer gFlag specifically on the read replica cluster, without applying it to the primary cluster.
If you are using YugabyteDB Anywhere, you can also set gFlags independently for the read replica clusters.
Keep in mind that in our example above that setting default_transaction_read_only=true
is applied at the Universe level, meaning every connection will default to this setting.
However, individual sessions can override this parameter and set it back to false
.
While the title of this tip is “Ensure a Read Replica Cluster is Strictly Read-Only,” this approach only changes the default behavior of the read replicas rather than enforcing strict read-only access.
Here’s a quick example of overriding default_transaction_read_only
at the session level, which allows for INSERT
operations:
[root@cloud-server-0 yb2]# ysqlsh -h 127.0.0.2 -c "SET default_transaction_read_only=OFF;" -c "INSERT INTO test (c1, c2) VALUES (4, 'D'), (5, 'E'), (6, 'F');"
SET
INSERT 0 3
Have Fun!