The Internet Computer Protocol offers a unique environment for building decentralized applications (dApps) that can scale efficiently. One of the critical decisions developers face when designing their dApps on ICP is the choice between monolithic and multi-canister architectures. This article explores these two approaches, their trade-offs, and how the right choice can affect scalability and performance.
Understanding Canisters in the ICP Blockchain
Canisters are the core computational units on the Internet Computer (ICP) blockchain. They are smart contracts that contain both code and state (data). Unlike traditional smart contracts, canisters are more powerful, flexible and fast, enabling developers to build complex, decentralized applications (dApps) and services.
How Canisters Store Data
Canisters manage their own memory, storing data in a structured and persistent way. Data is stored within the canister’s state and can include anything from user information to application logic. This data is secure and tamper-proof, as it is stored across the decentralized network of the Internet Computer. Read more here
Interacting with Canisters
Interactions with canisters are done through method calls. These methods can be invoked externally by users or other canisters (inter-canister calls). For example, when a user submits a transaction or request, it is sent to a canister, which processes the request based on its code and updates its state as needed. The canister then returns the result of the computation to the user.
Query calls | Update calls |
---|---|
Allow the user to query the current state of a canister or call a function that operates on the canister’s state without changing it. | Allow the user to change the state of the canister and have changes persisted. |
Are synchronous and answered immediately. | Are answered asynchronously. |
Can be made to any node that holds the canister; the result does not go through consensus. That is, there is an inherent tradeoff between security and performance: the reply from a single node is fast, but might be untrustworthy or inaccurate. | Must pass through consensus to return the result. Because consensus is required, changing the state of a canister, and returning the result can take time. There is an inherent tradeoff between security and performance: the result is trustworthy because two-thirds of the replicas in a subnet must agree on the result, but the call is slow. |
Do not allow changes to the state of the canister to be persisted, so essentially query calls are read-only operations. | The called canister can invoke functions exposed by other canisters |
Do not allow the called canister to invoke functions exposed by other canisters as inter-canister calls. (Note that this restriction is temporary and that canisters will be able to invoke functions exposed by other canisters when processing query calls in the future.) |
Canister Limitations
Before diving into the limitations, it’s important to first understand the two types of storage on the ICP blockchain:
Heap Memory
When developing projects on ICP, there are two primary forms of data storage that your canisters can utilize. The first type of storage is the canister’s heap memory, sometimes referred to as the canister’s main memory. Heap memory is temporary, and any data stored in a canister’s heap memory is cleared whenever the canister is stopped or upgraded.
Stable Memory
The second type of storage available to a canister is stable memory. Stable memory is a unique feature of ICP that defines a separate data store aside from a canister’s regular Wasm heap memory data storage. It is a secondary storage type that can be used to store data long-term, since all data stored in stable memory will persist across all canister processes.
For more detailed information, you can read about storage here.
Memory Limitations
Now that we know the types of memory in ICP, let’s explore their limitations. Each canister has a restricted amount of heap and stable memory it can use. Currently, a canister can hold up to 4 GiB of heap memory and 400 GiB of stable memory. However, note that these limits can change, so it’s advisable to check for updates on resource limits regularly. For more information you can read this article.
A key point to remember is that if your heap memory exceeds 2 GiB, you won’t be able to upgrade your canister. For more details, refer to this thread.
Monolithic Architecture vs Multi-Canister Architecture
Monolithic Architecture
Monolithic architecture is a traditional software design where an application is built as a single, indivisible unit. All components of the software are interconnected and run together as a single service. In the context of the Internet Computer Protocol (ICP), monolithic architecture refers to a single canister handling all services within an application.
- Performance: Since all services run within one canister, this approach is both fast and efficient on the front-end (web app) and back-end (canister).
- Risk: If the canister fails, the entire application goes down because everything is centralized in one place.
- Limitations: While this architecture is speedy and efficient, it lacks scalability and flexibility.
Multi-Canister Architecture
In contrast, multi-canister architecture involves creating separate canisters for different services, each operating independently.
- Resilience: If one canister fails, the other canisters remain unaffected, making this architecture more resilient.
- Scalability and Flexibility: Since services are separated, this architecture is more scalable and flexible.
- Performance Trade-Off: However, because services are divided across multiple canisters, this approach is generally slower and less efficient in ICP. For instance, retrieving data stored in two different canisters requires separate calls.
Fantasy Extreme Backend Architecture
Fantasy Extreme, a groundbreaking decentralized fantasy sports platform, offers an innovative opportunity to break down the barriers imposed by traditional fantasy sports. With global participation at its core, Fantasy Extreme allows users to create virtual teams, join multiple sports leagues, and enjoy endless matches and contests. Best of all, users receive instant rewards without the geographical limitations of conventional platforms.
In Fantasy Extreme, we have a complex architecture with multiple services working together to deliver a curated user experience. Because speed is crucial for our app, we opted for a monolithic architecture. Choosing a multi-canister approach would have significantly impacted the app’s speed, as inter-canister calls are currently not possible within query methods, which would degrade performance. Although the introduction of composite queries in Motoko version 0.9 (July 2023) allows inter-canister calls within query functions, performance could still suffer, not to mention the increased cost due to gas-fee, especially when multiple inter-canister calls are needed, potentially causing delays beyond one second.
Looking ahead, we plan to transition to a multi-canister architecture. While the initial focus was on maximizing speed and efficiency, future scalability is essential, particularly as we plan to expand into sports beyond football. Managing such a large volume of data within a single canister would be challenging, making the shift to a multi-canister architecture necessary for future growth.
Conclusion
The choice between monolithic and multi-canister architecture on the Internet Computer Protocol (ICP) depends on the specific needs of your decentralized application (dApp). Monolithic architecture offers speed and simplicity, making it an ideal solution for applications like Fantasy Extreme, where performance is critical, especially in environments requiring real-time interaction. However, as the application scales and complexity grows, transitioning to a multi-canister architecture becomes necessary to accommodate increased data and services.
Multi-canister architecture, with its scalability and resilience, is better suited for larger dApps that need to handle high volumes of data and independent services. The trade-off between performance and flexibility is an important consideration, but with advances such as composite queries, the performance gap between the two approaches may lessen over time.
Ultimately, developers should choose the architecture that best meets their immediate needs while planning for future scalability, as evolving from a monolithic to a multi-canister architecture can provide the foundation for long-term success on ICP.