Hi Isaac,
This is a great question.
Ribbon (client-side load balancing) provides a lot of avenues of doing much more intelligent load-balancing which ELBs do not do. We have developed algorithms like zone-awareness, zone-affinity which helps us in terms of resiliency in the wake of zone outages and other partial network partitions. This provides us enough benefits to not move all our mid-tier services behind ELBs inside VPC.
There are other reasons like,
-- Since, ribbon is integrated with eureka, it also becomes a powerful tool to control instance availability via external administrative tools. eg: for debugging purposes, if you wish to isolate an instance, you can set that instance as Out of service in eureka & ribbon will stop sending traffic to it. This is a pretty useful feature, which otherwise is hard to do with ELBs (you would have to manage the healthcheck of the instance to take it out of service)
-- Introducing an ELB, introduces an extra network hop without adding significant benefits otherwise.
-- In the future, we are looking at using binary protocols between our micro-services and having an ELB in between is again a hindrance (specifically in terms of handling application level back-pressure) without adding significant benefits.
Looking at the above scenarios, it is much more useful to keep the control with our clients in terms of how to balance load between different service instances and having an ELB, reduces that control.
Having said the above, having an ELB in front of micro-services greatly reduces the complexity and if the reasons above do not apply to your deployment, choosing to front all your micro-services with an ELB will be a good idea.