i am new to the ops side of devops and was hoping for some clarification. Specifically, if in a microservice based project you have multiple jars and each jar gets deployed in a VM on the same hardware, how are you not limiting throughput? if a server only has a fixed amount of processing power and multiple services are competing for those resources, it seems like you are loosing performance. can someone explain how this works?
I'll ignore your usage of the word "VM" here, since you have "Docker" in the title and "container" in the tags.
One would indeed not deploy each microservice in their own VM, which would be an incredible waste of resources.
But Docker is different. It is no VM. There is no virtualization. There is no extra layer between the processes running inside the Docker container and the host kernel. There is no significant overhead in the form of RAM usage. It is more or less the same as just running the process without a container.
Docker is based on the concept of namespaces. Modern Linux kernels have namespaces for all their internal data structures (from user IDs to network interfaces to process tables). All aspects regarding accessing kernel ressources/hardware/networking etc. are exactly the same, no matter whether a process runs inside a Docker container or on the host itself. That's the beauty of it, that's also why a docker container spins up very quickly with almost no overhead, and why the actual runtime also has no appreciable overhead.
There is one single difference, which is the filesystem; and this is not due to virtualization of any kind, but due to the "onion" style of layering many filesystems on top of each other. There are options when building images to avoid this, i.e. pack many layers into one, which would alleviate such problems (and conversely, you can mount unionfs-style filesystems in pure Linux as well, and those will have exactly the same performance overhead).
But incidentally his overhead is mostly negligible because something like your standard microservice will load once, and then just run. If you use storage in a container, you usually don't write it into the container itself (though you can), but in a separate volume mounted when spinning up the container; and those are like normal Linux mounts, i.e. they have no performance penalty.
TL;DR: Docker has in the most cases no relevant performance penalty at all; namespacing instead of virtualization is the reason why.