Here is my (albeit limited experience) advice:
1. Use PostgreSQL, or MySQL with InnodDB for row level locking
2. Huge tables should be sharded with the shard key being a prefix of the primary key.
If you need to access the same data via different indexes then denormalize and duplicate the index data in one or more "index" tables.
3. Do not use global locks. Generate random strings for unique ids (attempt INSERT and regenerate until it succeeds) instead of autoincrement.
4. Avoid JOINs across shards. If you use these, you won't be able to shard your app layer anymore.
5. For reads, feel free to put caches in front of the database, with the keys same as the PK. Invalidate the caches for rows being written to.
It's actually pretty easy to model. You have the fields for the data. Then you think by which index will it be requested? Shard by that.
Note that this will still lead you to a huge centralized datacenter!! Because your authentication happens at the webserver level and then you just have all the servers trust each other. While it is a nice horizontal architecture, it leads to crazy power imbalances like we have today. Consider instead making it a distributed architecture, where the shards turn into domains, and each user on each domain has to auth with every other domain. But your network can then be distributed without a single point of failure. What's more, local area networks will be able to host your app and be quick without the signal bouncing halfway around the world.