MySQL- reducing memory footprint
Good explanation.  Good idea.  I'll add my 2-cents...

"Sharding" would have a few merchants on one server (plus its replicas); a few other merchants on another shard, etc.

You are suggesting that it is practical to have all the data everywhere, but "shard" the accesses to minimize RAM requirements.

First let me make a strong suggestion.  Have all PRIMARY KEYs be composite, starting with the merchant_id.  This will cluster all the rows for a given merchant together.  This is in addition to having most of the indexes start with that same column.

If you currently have

PRIMARY KEY(id),   -- auto_increment
INDEX(merchant_id, ...)   -- a few of these


then change to

PRIMARY KEY(merchant_id, id)  -- for m_id for clustering; id for uniqueness
INDEX(id)   -- to keep auto_increment happy
INDEX(merchant_id, ...)   -- fewer of these


Reconsider the secondary indexes; you may not need as many, since the rows are already clustered by merchant_id.

Granted, inserting not-for-this-shard merchant rows will need to some blocks; but they will be transient and not cost too much room in innodb_buffer_pool_size.

If you are pseudo-sharding the slaves, then if a slave dies, all the other slaves are ready to take over for any Merchant's requests.  The only problem is that queries will be slow due to the lack of cached data.  I see the 'instant' failover as being more of a benefit than the 'slower' is a detriment.  Anyway, the caching will catch up pretty soon.

How much write traffic is there, versus read traffic?


A lot of write:  Then you need to shard the Masters (and Slaves).  But would this mean that you are still doing all the writes to all Masters?  This is clumsy?
Mostly read traffic:  (That's what I was commenting on above.)


Keep in mind that every Slave performs every write that happened on its Master.  Corollary:  You can't get write scaling without Sharding the Masters.

PK example

Using your specifics (from Comment):  You currently have an 8-byte id BIGINT?

PRIMARY KEY(id),   -- auto_increment, 0 extra bytes (clustered with data)
INDEX(account_id, timestamp)   -- INT + TIMESTAMP or DATETIME : 4+5 + 8 bytes


-->

PRIMARY KEY(account_id, timestamp, id),   -- 0 extra bytes
INDEX(id)   -- 8 + 4+5 bytes


That is the disk footprint will be virtually identical.  To elaborate:


The PK is "clustered" with the data; this makes the data ordered according to the PK.  Hence, the PK takes zero extra bytes on top of the data.  (OK, there is a small overhead for the non-leaf nodes of the BTree.)
Any secondary index has a copy of the PK in it.  (This is how it gets to the actual row.)
So, in this pair, the secondary index has exactly the same fields, with exactly the same total space, just rearranged.
Here's the feature I am after:  When looking up rows for one account, perhaps over a timestamp range, the data PK will now be used instead of using the secondary key, then jumping through id.  And all the desired rows will be adjacent to each other.  The result:  Such SELECTs will be faster (maybe 2x, but there are a lot of variables).


Back to the "old wives tale" that you should keep the PK "small".  Yeah, that is a general rule.  But I have just explained an exception.

If you have several more secondary keys on the same table, then the extra secondary keys will be bulkier.  But you want to skip on RAM, and don't need to worry about disk.  Again, what I suggest fits well.