Architecting Cloud Native Applications
上QQ阅读APP看书,第一时间看更新

Context, problem, and forces

Cloud-native systems are composed of bounded isolated components, which are responsive, resilient, elastic, and message-driven. All inter-component communication is performed asynchronously via event streaming. Components publish events to downstream components and consume events from upstream components. We strive to limit synchronous communication to only the intra-component cloud-native databases and to the cloud-native streaming service. Yet, sooner or later, we have to implement synchronous communication at the boundaries of the system. At the boundaries, the system interacts with users via mobile apps and single page web applications and with external systems via Open APIs.

First and foremost, these public endpoints must be secured. We must form a perimeter at the boundaries of the system to govern access to the system. The perimeter minimizes the attack surface and controls the blast radius of an attack by providing a bulkhead, which absorbs unwanted traffic. These public endpoints must also be highly available. Yet, we strive to minimize synchronous communication, because implementing highly available synchronous communication is undifferentiated and cumbersome work, which distracts self-sufficient, full-stack teams from the value propositions of their specific components.

These cross-cutting concerns should be decoupled from the functionality of the system to facilitate responsiveness, resilience, elasticity, and global scalability. Intrusions should be stopped at the edge and not permeate the internal components where they will consume valuable resources and impact responsiveness. This reverse proxy layer should run on its own separately scalable infrastructure and support regional load-balancing and regional failover. In addition, this layer should provide caching at the edge to further attenuate load on the internal components and provide monitoring to help complete the overall performance picture. Finally, this capability should not be overly ambitious. It should be easy to use, a relatively dumb pipe that is focused on these responsibilities. There should be no incentive to code business logic in this layer.