Architecture of Flower Simulation Engine

Hello everyone,
I am interested in the architecture of the flower simulation engine. I found this page in the docs but as I understand it talks about the deployment engine. Are there big differences between the two and are there any resources on that?
Thanks in advance!

1 Like

Hello @lukasb, there are some differences when comparing the Deployment runtime to the Simulation runtime. However, these differences are only “internal” in the sense that they don’t affect how a ClientApp or ServerApp are loaded and executed.

The main differences is that for simulations there’s no need for a full blow SuperLink and N SuperNodes.

  • About SuperLink: The Simulation runtime uses only the LinkState (which you can think of it as proxy service that enables the exchange of flwr.common.Message objects between ServerApp and ClientApps). The rest of the functionality that the SuperLink brings around it (e.g. authentication, gRPC connections, TLS, etc – these aren’t needed in simulation) isn’t needed for simulations. The ServerApp communicates in-memory with the LinkState.
  • About SuperNodes. In simulations we often want to test scenarios with many (hundreds, thousands) of nodes connected to a server. In “flower terms” this would mean many SuperNodes connected to a SuperLink. But if you recall from that Flower Architecture page and also this one about Flower Network Network Communication, the main job of a SuperNode is: (1) pull a Message from the LinkState; (2) instantiate a ClientApp and pass it that Message; (3) return to the LinkState the Message that the ClientApp returns. In Simulations we want this functionality but we don’t need other functionality that SuperNodes carry (e.g. authentication, gRPC connections, different isolation for ClientApps, etc). Therefore, just like it’s done for the server side, we can simplify things a bit in simulation and spawn N(no necessarily the number of SuperNodes you want to simulate) workers that implement the core functionality of a SuperNode (i.e. the (1)-(2)-(3) steps mentioned earlier). These processes are fairly simple and you can find them implemented here. We currently use Ray (see the RayBackend if you are curious) to have a simple resource-aware mechanism to run the ClientApps. But technically speaking Ray isn’t needed and the same could be achieved with vanilla ProcessPoolExecutor.

Happy to dive deeper in some parts of the above description if you are interested. Just let me know! The summary is that when writing ClientApps and ServerApps you don’t need to worry about whether it runs in simulation or not since the mechanism to communicate Messages and execute the *App is the same in both simulation and deployment.

Thanks that already helped me a lot!

1 Like