Consistent hashing on a ring moves only about 1/N of keys when a node joins or leaves. Naive hash(key) % N reshuffles almost everything. Virtual nodes fix the load-imbalance problem a small number of physical nodes has on a ring.
Each key is owned by the next node clockwise from its hash position. Virtual nodes above 1 are not drawn individually here — the ring shows physical node ownership after virtual-node averaging.
Cassandra and DynamoDB both place partitions using a ring of hashed token ranges rather than hash(key) % N. That single design choice is what lets you add or remove a node without rehashing the entire dataset — see Cassandra for how tokens and vnodes map to replica placement, and DynamoDB for the same idea behind its partition key hashing.
hash(key) % N, changing N changes the modulus for almost every key — a cache cluster doing this on scale-out would face a near-total cache miss storm.num_tokens setting controls.