The multiform read-write separation
When people discuss read-write separation at the system level, they tend to imply CQRS which dedicates a pair of services, one each for handling read and write requests. However, there are other ways to subdivide a system, and each of them can be used with read-write separation:
Replicas#
We can deploy read-only replicas of the system’s database for nearly unlimited scalability of read traffic without introducing distributed transactions or the need to resolve write conflicts. This is because all the writes go to the same database replica. However, the system still suffers from replication lag between the write and read replicas.

Layers#
It is common to cache a subset of the system’s state in one of its upper layers so that the majority of read requests are answered without the need to access the rest of the system’s components.
A Response Cache saves responses to the latest client queries (read requests) and reuses them to reply to matching incoming requests. It cannot help with commands (write request) because a command will change something inside the system, and additionally even the cache itself must be updated after a command passes through it.

Control software usually involves an integrated model for the system it controls. Its algorithms make decisions based on the embedded model without querying the real hardware. And once a decision is made, it is then enacted in the hardware.

Services#
One or two of the system’s layers may serve commands and queries with functionally different components.
Command Query Response Segregation (CQRS) processes the commands and queries in separate modules or services. That can be beneficial because one of the main concerns with commands is keeping the edited record’s data self-consistent while queries often focus on aggregating multiple records. These two activities have very little in common and even differ in the optimal representation of the data they process, therefore they are easy to separate.

Online Transaction Processing (OLTP) and Online Analytical Processing (OLAP), being the names for command- and query-optimized databases, respectively, bring read-write separation to the data layer. The pair of OLTP and OLAP databases used by a (sub)system may differ in their schema, engine, and even type (SQL vs NoSQL). Replication lag applies here as well.

CQRS and the OLAP/OLTP separation or read-only database replicas often go together:

Time division#
Surprisingly, some systems rely on read and write separation along the time axis. In simple terms, it’s like using a system-wide readers-writer lock.
In (Re)Actor-with-Extractors, the entire system (e.g. a computer game engine) undergoes alternating read and write phases, allowing for efficient lock-free simulation of multiple interacting objects.

Multiversion Concurrency Control (MVCC) assigns each database request to a data snapshot: queries operate on the current snapshot while a command requires a new snapshot to be allocated for future changes. That resolves the architectural forces conflict between long-running queries and real-time updates at the cost of the queries returning stale data.

Interleaving subsystems#
A Data Mesh builds a graph of analytical datastores, called Data Product Quanta (DPQ), which exists in parallel to and is co-located with the system it extracts data from. That almost completely decouples the transactional and analytical data flows.

Summary#
CQRS is far from being the only way to separate read and write requests at the system level. Many other architectural patterns, from the ubiquitous Response Cache to much less well known (Re)Actor-with-Extractors and Data Mesh, apply the same principle in ingenious ways.