Technically, you can name your exchanges, queues, and routing keys whatever you want, but it's critically important to choose good names. Not only will it make your system easier to understand, but it can also make it more flexible and powerful.
It's common for one "system" to all use the same exchange. Similar to how you might have a single "database" within a Postgres instance, you might just have a single "exchange" within a RabbitMQ instance. For example, I worked on a system that managed hundreds of thousands of social media messages per hour. We had a single exchange called social_posts, and it was the only exchange we used.
When I'm working with a direct key -> queue relationship, I'll often name the queue the same as the key, but add a word to describe the intended consumer. For example, if I have a routing key user.created, I might create a queue for my "email notifier" service called user.created.email_notifier.
If I have a queue that consumes all user events, I might name it user.all.billing_service.
If I have temporary queues, I might append a UUID to the queue name to ensure uniqueness. For example, maybe I have web servers that scale up and down based on traffic, and each server needs a copy of "comment created" events. I might name each server's queue one of:
comment.created.bb7a488b-b4e9-4b16-a697-51c20a09b87bcomment.created.8d0a9d3e-5244-460b-bacc-80ae2b802677comment.created.6814c13f-c33b-4ff7-a4f8-98c718fea980I'll often use auto-generated queue names like this with transient, auto-delete, and exclusive properties so they can be created and destroyed as the system restarts and scales.
This is the one that you really want to get right. Not only do you want the routing key names to be descriptive, but you also want them to be flexible for potential wildcard matching. I've found that often a noun.verb pattern works well. For example:
user.createduser.updatedcomment.createdcomment.deletedThis allows you to easily bind queues to all events of a certain type, or all events that affect a certain entity.