One of the core concepts of OTP (effectively the Erlang standard library) is the GenServer. A GenServer processes incoming messages, mutates state if appropriate and sends responses. The OTP machinery means that this "send a message and wait for a response" is just a straight function call with return value to the caller. OTP takes care of all the edge cases (like when the process at the other end goes away half way through). This means that your code is just a straight series of synchronous function calls, which may be sending messages underneath to do things or get data, but you don't have to care. It's a lovely system to work in, and makes complicated systems feel simple.
The elements communicating are in Erlang terminology 'processes' - but not OS processes, they are instead lightweight userspace schduled things - very lightweight to create. Erlang has built in distribution that allows you to connect multiple running machines, and then the same message passing works across network boundaries. You're still limited to the BEAM VM though. This is the 'full' microservice version of that.