First of all, it is a very good and fair question. You're right, you can achieve the same with mnesia + ram_copies + fragmentation, BUT performance won't ever be the same, mnesia is a heavy layer on top of ETS and DETS, if you want to write something, in case of fragmentation, you use transaction, and that takes time, and compared with ETS or Shards, latency is much much higher – even if you can use dirty_write is much higher. I did performance test some time ago, in order to compare this, and mesia_frag started to fail and crash pretty soon – probably after 3000-5000 ops/seg. I did some performances test with shards that you can check here: http://cabol.github.io/posts/2016/04/14/sharding-support-for... (BTW, I'll add mnesia_frag to that bench test). Besides I wrote some other test, which includes mnesia_frag here: https://github.com/cabol/shards_bench. Furthermore, you can do it out yourself using "https://github.com/basho/basho_bench" which is the tool that I've been using so far.
IMHO, they are similar libs/tools, which drives similar issues, but depending on the case, one tool can fits better to solve a set of problems than the other and viceverza. For example, the typical case, caching and/or distributed caching, here you want to be able not only to get the best performance, but also scale-out over the write-locks and contention, without compromise performance – as much as possible. In this case, ETS or Shards might be a better option. But suppose that you want to be able to handle RAM and Disk persistence transparently, you want to do it configurable, besides, be able to handle transaction, well, in that case, go for mnesia might be better option. But in general, if you always gonna have memory storage, might be better option go for ETS or in this case Shards, which add the ability to scale linearly over locks and contention issues.
Epidemic broadcast that you mention, usually happens when you have a fully connected topology and distribution model works with full replication. But the main advantage with riak_core is that you are able to set the replication factor and quorums, which enables you to setup different distribution models --like sharding or peer-to-peer replication + sharding (common case)-- and balance consistency/availability levels --please review CAP theorem (http://www.julianbrowne.com/article/viewer/brewers-cap-theor...).
In case of ErlBus, you can also set these parameters (replication factor and quorums), even the quorum of each operation (sub, pub, unsub, subscribers, etc.) can be set independently. So riak_core gives you the flexibility to choose the best distribution model depending on what you really need, and ErlBus inherits those features when you run it on top of riak_core.
So, you have to consider some variables to choose what distribution model to use:
1. Number of nodes
2. Network traffic (Messages/second)
3. Number of subscriptions (because both pg2 and gproc uses ETS tables)
Most of the cases is enough default ErlBus with PG2, but if you need a more flaxible and scalable distribution model, well, you probably should go for ErlBus with riak_core.
I really hope have answered your question, otherwise, you just let me know.
Good suggestion, I'll do that! Because there are significant differences between them, and the purpose of ErlBus isn't compete with RabbitMQ at all, they are different tools to drive different problems, so is very important highlight these differences. Thanks!!