Hi Nick,
Your third option of "over-normalizing" the data is my least favorite.
For the first two, the decision on whether or not to split the message types into different datasources or not should be based on the use case. If you often query across message types then better to keep together. However if you usually only query one message type, and/or if your message types have different data retention periods, then it favors separating them out.
As far as loading them together into one datasource, Druid has a "nested column" datatype that can store JSON objects of arbitrary form, the object can be a different shape from one record to the next, each element is stored in columnar format and fully indexed for fast retrieval.
But you can also almost as easily store each attribute in a separate top-level column in the one datasource ... the number of columns just increases, but if you want that level of visibility in the schema, that may be your preference.