📄 Page
1
Design Patterns for Cloud Native Applications Patterns in Practice Using APIs, Data, Events, and Streams Kasun Indrasiri & Sriskandarajah Suhothayan
📄 Page
2
(This page has no text content)
📄 Page
3
Kasun Indrasiri and Sriskandarajah Suhothayan Design Patterns for Cloud Native Applications Patterns in Practice Using APIs, Data, Events, and Streams Boston Farnham Sebastopol TokyoBeijing
📄 Page
4
978-1-492-09071-7 [LSI] Design Patterns for Cloud Native Applications by Kasun Indrasiri and Sriskandarajah Suhothayan Copyright © 2021 Kasun Indrasiri and Sriskandarajah Suhothayan. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://oreilly.com). For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com. Acquisitions Editor: Jennifer Pollock Development Editor: Nicole Taché Production Editor: Deborah Baker Copyeditor: Sharon Wilkey Proofreader: Penelope Perkins Indexer: Potomac Indexing, LLC Interior Designer: David Futato Cover Designer: Karen Montgomery Illustrator: Kate Dullea June 2021: First Edition Revision History for the First Edition 2021-05-14: First Release See http://oreilly.com/catalog/errata.csp?isbn=9781492090717 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Design Patterns for Cloud Native Appli‐ cations, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. The views expressed in this work are those of the authors, and do not represent the publisher’s views. While the publisher and the authors have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the authors disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights.
📄 Page
5
Table of Contents Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix 1. Introduction to Cloud Native. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 What Is Cloud Native? 1 Designed as a Collection of Microservices 2 Use Containerization and Container Orchestration 6 Automate the Development Life Cycle 10 Dynamic Management 12 Methodology for Building Cloud Native Apps 13 Designing the Application 13 Developing the Application 14 Connectivity, Compositions, and APIs 16 Automating the Development, Release, and Deployment 18 Running in a Dynamic Environment 18 Control Plane for Dynamic Management 19 Observability and Monitoring 19 Design Patterns for Building Cloud Native Apps 19 Communication Patterns 20 Connectivity and Composition Patterns 21 Data Management Patterns 22 Event-Driven Architecture Patterns 22 Stream-Processing Patterns 22 API Management and Consumption Patterns 23 Reference Architecture for Cloud Native Apps 23 Summary 25 2. Communication Patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Synchronous Messaging Patterns 28 iii
📄 Page
6
Request-Response Pattern 28 Remote Procedure Calls Pattern 30 Summary of Synchronous Messaging Patterns 33 Asynchronous Messaging Patterns 34 Single-Receiver Pattern 34 Multiple-Receiver Pattern 36 Asynchronous Request-Reply Pattern 38 Summary of Asynchronous Messaging Patterns 40 Service Definition Patterns 41 Service Definitions in Synchronous Communication 41 Service Definition in Asynchronous Communication 43 Technologies to Implement Synchronous Messaging Patterns 46 RESTful Services 46 GraphQL 48 WebSocket 49 gRPC 50 Summary of Synchronous Messaging Technologies 51 Technologies to Implement Asynchronous Messaging Patterns 51 AMQP 51 Kafka 52 NATS 52 Testing 53 Security 54 Observability and Monitoring 54 DevOps 55 Summary 55 3. Connectivity and Composition Patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 Connectivity Patterns 57 Service Connectivity Pattern 58 Service Abstraction Pattern 61 Service Registry and Discovery Pattern 64 Resilient Connectivity Pattern 68 Sidecar Pattern 73 Service Mesh Pattern 77 Sidecarless Service Mesh Pattern 81 Technologies for Implementing Service Connectivity Patterns 84 Summary of Connectivity Patterns 85 Service Composition Patterns 86 Service Orchestration Pattern 86 Service Choreography Pattern 89 Saga Pattern 92 iv | Table of Contents
📄 Page
7
Technologies for Implementing Service Composition Patterns 96 Summary of Service Composition Patterns 97 Summary 97 4. Data Management Patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 Data Architecture 99 Types and Forms of Data 101 Data Stores 102 Relational Databases 102 NoSQL Databases 103 Filesystem Storage 106 Data Store Summary 106 Data Management 107 Centralized Data Management 107 Decentralized Data Management 107 Hybrid Data Management 108 Data Management Summary 109 Data Composition Patterns 110 Data Service Pattern 111 Composite Data Services Pattern 114 Client-Side Mashup Pattern 115 Summary of Data Composition Patterns 117 Data Scaling Patterns 118 Data Sharding Pattern 118 Command and Query Responsibility Segregation Pattern 124 Summary of Data Scaling Patterns 126 Performance Optimization Patterns 127 Materialized View Pattern 128 Data Locality Pattern 130 Caching Pattern 133 Static Content Hosting Pattern 139 Summary of Performance Optimization Patterns 141 Reliability Patterns 142 Transaction Pattern 143 Summary of Transaction Reliability Pattern 146 Security: Vault Key Pattern 146 How it works 146 Summary of the Vault Key Pattern 148 Technologies for Implementing Data Management Patterns 148 Relational Database Management Systems 148 Apache Cassandra 149 Apache HBase 150 Table of Contents | v
📄 Page
8
MongoDB 150 Redis 151 Amazon DynamoDB 151 Apache HDFS 152 Amazon S3 152 Azure Cosmos DB 152 Google Cloud Spanner 153 Summary of Technologies 153 Testing 154 Security 155 Observability and Monitoring 156 DevOps 157 Summary 159 5. Event-Driven Architecture Patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 Event-Driven Architecture 162 Exactly Once Processing 163 Message Broker Categories 163 CloudEvents 164 Event Schema 164 Event-Delivery Patterns 164 Producer-Consumer Pattern 165 Publisher-Subscriber Pattern 168 Fire and Forget Pattern 171 Store and Forward Pattern 173 Polling Pattern 174 Request Callback Pattern 176 Summary of Event-Delivery Patterns 179 State Management Patterns 181 Event Sourcing Pattern 181 Summary of State Management Pattern 185 Orchestration Patterns 185 Mediator Pattern 185 Pipe and Filter Pattern 188 Priority Queue Pattern 190 Summary of Orchestration Patterns 192 Technologies for Event-Driven Architecture 193 Apache ActiveMQ 193 RabbitMQ 194 Amazon SQS 194 Amazon SNS 195 Azure Event Grid 195 vi | Table of Contents
📄 Page
9
Azure Service Bus Queues 195 Google Cloud Pub/Sub 196 Summary of Message Broker Technologies 196 Testing 197 Security 199 Observability and Monitoring 199 DevOps 200 Summary 201 6. Stream-Processing Patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 What Is a Stream? 203 What Is Stream Processing? 203 Streaming Data Processing Patterns 204 Transformation Pattern 204 Filters and Thresholds Pattern 207 Windowed Aggregation Pattern 209 Stream Join Pattern 214 Temporal Event Ordering Pattern 218 Machine Learner Pattern 221 Summary of Streaming Data Processing Patterns 224 Scaling and Performance Optimization Patterns 225 Sequential Convoy Pattern 225 Buffered Event Ordering Pattern 230 Course Correction Pattern 233 Watermark Pattern 235 Summary of Scaling and Performance Optimization Patterns 239 Reliability Patterns 240 Replay Pattern 240 Periodic Snapshot State Persistence Pattern 243 Two-Node Failover Pattern 248 Summary of Reliability Patterns 250 Technologies 251 Esper 251 Siddhi 252 ksqlDB 252 Apache Spark 252 Apache Flink 253 Amazon Kinesis 253 Azure Stream Analytics 253 Google Dataflow 254 Summary of Stream-Processing Technologies 254 Testing 255 Table of Contents | vii
📄 Page
10
Security 256 Observability and Monitoring 256 DevOps 257 Summary 258 7. API Management and Consumption Patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 API Management Patterns 259 API Gateway Pattern 260 API Microgateway Pattern 265 Service Mesh Sidecar as an API Gateway Pattern 268 Technologies for Implementing API Management Patterns 269 Summary of API Management Patterns 269 API Consumption Patterns 270 Direct Frontend-to-Microservices Communication Pattern 270 Frontends Consuming Services Through API Gateway Pattern 272 Backend for Frontends Pattern 273 Summary of API Consumption Patterns 275 Summary 276 8. Cloud Native Patterns in Practice. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 Building an Online Retail System 277 Product Catalog 277 Order Management 278 Order Tracking and Prediction 278 Product Recommendations 278 Customer and Partner Management 279 Building the High-Level Architecture 279 Building External APIs 280 Connecting Services 282 Performing Data Management 283 Using Event-Driven Architecture 284 Using Stream Processing 286 Implementing Dynamic Management in a Cloud Environment 287 Summary 288 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 viii | Table of Contents
📄 Page
11
Preface Cloud Native architecture is all about building software applications as a collection of independent, loosely coupled, business capability–oriented services (microservices) that can run on dynamic environments (public, private, hybrid, multicloud) in an automated, scalable, resilient, manageable, and observable way. Writing applications to work natively on the cloud is increasingly common due to the agility, reliability, affordability, and scalability it provides. In current cloud native architecture, the focus is mostly on deployment and operational aspects of applica‐ tions. However, when building cloud native applications, we can’t apply conventional application development patterns and techniques. This book addresses this issue by defining proven solutions as patterns based on APIs, data, events, and streams. It aims to help architects and developers incrementally design, develop, and deploy cloud native applications that are optimal for their use cases, and that can be man‐ aged and maintained with minimal cost, time, and effort. There is a wide range of design patterns that architects and developers can apply when building cloud native applications. In this book, we mainly focus on the devel‐ opment patterns that must be applied when building the business logic of cloud native applications, when connecting them, and when enabling external parties to consume them. Depending on the nature of your application, and the patterns you use to build it, the cross-cutting capabilities such as deployment, scaling, security, and observability may be implemented differently. For that reason, we spend some time discussing the trade-offs and ramifications of using the various patterns. We organize these patterns into seven key areas: communication, connectivity, composition, data, events, stream processing, and API management and consumption. The chapters in the book are organized as follows: Chapter 1, Introduction to Cloud Native This chapter helps you understand what cloud native is by exploring the key characteristics of cloud native applications. We focus on the importance of using design patterns for building cloud native applications. ix
📄 Page
12
Chapter 2, Communication Patterns This gives you a broad understanding of the communication patterns and imple‐ mentation technologies that you can use to build cloud native applications. We mainly focus here on foundational communication patterns for synchronous and asynchronous communication. Chapter 3, Connectivity and Composition Patterns Here we explore a wide range of patterns that build connectivity between micro‐ services as well as with other existing systems in a cloud native application. We also look at creating business functionalities by integrating services using Service Composition patterns. Chapter 4, Data Management Patterns In this chapter we look at patterns for managing data in cloud native applica‐ tions. We focus on the selection of data stores, and how data can be integrated with cloud native applications via data composition, while supporting scalability and reliability and optimizing for performance. Chapter 5, Event-Driven Architecture Patterns We cover the design patterns for building event-driven architectures using cloud native applications. Here, we focus on basic event delivery, event sourcing, and how events can be orchestrated among various asynchronous cloud native appli‐ cations. Chapter 6, Stream-Processing Patterns This chapter explores patterns for processing event streams at scale by both state‐ ful and stateless cloud native applications. We also look at patterns for building reliability into real-time applications, so that they can preserve their in-memory states across failures. Chapter 7, API Management and Consumption Patterns This chapter explores some of the most commonly used patterns in API manage‐ ment. We also cover a few API Consumption patterns, which are essential in building frontend applications such as a web application, mobile application, or desktop application on top of the managed APIs. Chapter 8, Cloud Native Patterns in Practice This final chapter shows you how to apply various cloud native patterns when building different aspects of a real-world cloud native application. x | Preface
📄 Page
13
Conventions Used in This Book The following typographical conventions are used in this book: This element signifies a tip or suggestion. This element signifies a general note. This element indicates a warning or caution. O’Reilly Online Learning For more than 40 years, O’Reilly Media has provided technol‐ ogy and business training, knowledge, and insight to help companies succeed. Our unique network of experts and innovators share their knowledge and expertise through books, articles, and our online learning platform. O’Reilly’s online learning platform gives you on-demand access to live training courses, in-depth learning paths, interactive coding environments, and a vast collection of text and video from O’Reilly and 200+ other publishers. For more information, visit http://oreilly.com. How to Contact Us Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-998-9938 (in the United States or Canada) 707-829-0515 (international or local) Preface | xi
📄 Page
14
707-829-0104 (fax) You can access the web page for this book, where we list errata and any additional information, at https://oreil.ly/Design_Patterns_for_CloudNative_Apps. Email bookquestions@oreilly.com to comment or ask technical questions about this book. For news and information about our books and courses, visit http://oreilly.com. Find us on Facebook: http://facebook.com/oreilly Follow us on Twitter: http://twitter.com/oreillymedia Watch us on YouTube: http://youtube.com/oreillymedia Acknowledgments With gratitude, we thank the cloud native community in general, and special thanks to our present and previous employers, and the colleagues, customers, friends, and tech enthusiasts whom we have met at conferences and meetups, who gave us experi‐ ence with and exposure to cloud native technologies. Our grateful thanks go to the tech reviewers of the book, Josh Armitage, Hibri Mar‐ zook, and Shayon Mukherjee. We would also like to thank our Development Editor Nicole Taché for her guidance in bringing the book into its current shape, and our Acquisitions Editor Jennifer Pollock for all her support, which led to the acceptance our proposal. Last but not least, we thank the entire crew who worked on publishing this book. Kasun would like to thank his wife Imesha and daughter Methuki for their support and patience during the time spent writing this book. He is also grateful for his parents, sister, and his relatives who have been behind him all the way. Suho would like to thank his wife, Sinthuja, for seeding the idea of writing a book on design patterns, for reading the draft scripts, and for sharing her knowledge on data management patterns. Most importantly, he would like to thank Sinthuja for rear‐ ranging all her plans to accommodate his work on the book. Thank you so much! xii | Preface
📄 Page
15
CHAPTER 1 Introduction to Cloud Native The software development landscape is constantly changing and evolving through modern architectural paradigms and technologies. From time to time, software archi‐ tecture goes through a fundamental shift with the emergence of breakthrough tech‐ nologies and approaches. One such breakthrough is cloud native architecture. It is such a major shift in the context of software application development, one that changes the way we build, ship, and manage software applications. Cloud native architecture has become an enabler of agility, speed, safety, and adaptability for soft‐ ware applications. This chapter helps you understand what cloud native is by exploring the key charac‐ teristics of cloud native applications. We’ll also introduce a development methodol‐ ogy that you can use throughout the life cycle of cloud native applications. Then we’ll focus on the importance of using design patterns for developing cloud native applica‐ tions. Let’s begin our discussion by defining cloud native. What Is Cloud Native? So, what’s the formal definition of cloud native? The sad news is, there’s no such defi‐ nition. Cloud native means different things to different people. The closest general definition is from the Cloud Native Computing Foundation (CNCF), an organization dedicated to building sustainable ecosystems and fostering communities to support the growth and health of open source, cloud native applications. CNCF serves as the vendor-neutral home for many of the fastest-growing open source projects that can be used in building cloud native applications. 1
📄 Page
16
Cloud Native Definition from CNCF Cloud native technologies empower organizations to build and run scalable applications in modern, dynamic environments such as public, private, and hybrid clouds. Containers, service meshes, microservices, immutable infrastructure, and declarative APIs exemplify this approach. These techniques enable loosely coupled systems that are resilient, manageable, and observable. Combined with robust automation, they allow engineers to make high-impact changes frequently and predictably with minimal toil. For the purposes of this book, we take a bottom-up approach to defining cloud native. We look at all the characteristics of cloud native applications, across the board, by going through every stage in the life cycle of a cloud native application—including design, development, packaging, deployment, and governance. Based on those char‐ acteristics, we’ve come up with the following definition: Cloud native is building software applications as a collection of independent, loosely coupled, business-capability-oriented services (microservices) that can run on dynamic environments (public, private, hybrid, multicloud) in an automated, scalable, resilient, manageable, and observable way. Exploring these characteristics further helps us understand cloud native applications. Let’s look more closely at the characteristics in our definition. Designed as a Collection of Microservices A cloud native application is designed as a collection of loosely coupled and inde‐ pendent services that are serving a well-defined business capability. These are known as microservices. Microservices are the foundational architectural principle that is essential to building cloud native applications. It’s virtually impossible to build a proper cloud native application without knowing the basics of microservices architecture. Microservices architecture is a style of building software applications. Before the advent of microservices architecture, we used to build software applications as mono‐ lithic applications catering to various complex business scenarios. These monolithic applications are inherently complex, hard to scale, expensive to maintain, and hinder the agility of development teams. Monolithic applications communicate with one another by using proprietary communication protocols and often share a single database. 2 | Chapter 1: Introduction to Cloud Native
📄 Page
17
1 Source: Microservices for the Enterprise by Kasun Indrasiri and Prabath Siriwardena (Apress). 2 Source: Chapter 2 of Microservices for the Enterprise. Microservices architecture is about building a software application as a collection of independent, autonomous (developed, deployed, and scaled independently), business-capability-oriented and loosely coupled services.1 Service-oriented architecture (SOA) emerged as a better architectural style to address the limitations of the monolithic application architecture. SOA is built around the concept of modularity and building a software application as a collection of services to serve a specific business capability. The realizations of SOA, such as web services, were implemented using complex standards and message formats, and introduced centralized monolithic components into the architecture. In a typical SOA-based design, software applications are built using a set of coarse- grained services, such as web services, that often leverage open standards and a cen‐ tral monolithic integration layer known as the enterprise service bus (ESB). An API management layer can be used on top of this architecture so you can expose the capa‐ bilities as managed APIs. Figure 1-1 shows a simple online retail application designed using SOA. All the busi‐ ness capabilities are created at the services layer as coarse-grained services that run on a monolithic application server runtime. Those services and the rest of the systems are integrated using an ESB. Then an API gateway is placed as the front door to the SOA implementation, where you control and manage your business capabilities. This approach has worked for many enterprises, and a lot of enterprise software applications are still built using SOA. However, its inherent complexities and limita‐ tions hinder the agility of developing software applications. Most implementations of SOA result in a lack of independently scalable applications, inter-application depen‐ dencies that hinder independent application development and deployment, reliability issues of being a centralized application, and constraints on using diverse technolo‐ gies for the application. Microservices architecture, on the other hand, eliminates the limitations of SOA implementations by introducing more fine-grained and business-oriented services while eliminating centralized components such as ESB. In microservices architecture, a software application is designed as a collection of autonomous and business- capability-oriented services that are developed, deployed, and often managed inde‐ pendently by different teams. The granularity of the service is determined by the application of concepts such as the bounded context in the Driven Design paradigm.2 What Is Cloud Native? | 3
📄 Page
18
Figure 1-1. An online retail application scenario built using an SOA/ESB with API management We can transform our earlier SOA/ESB-based online retail application to microservi‐ ces, as shown in Figure 1-2. The main idea here is to introduce microservices for each business capability that we identify during the design phase, as we apply the concepts of domain-driven design (explained later in this chapter) and eliminate the central‐ ized integration at the ESB layer. Monolithic-to-microservice transformation techniques are dis‐ cussed in detail in Building Microservices by Sam Newman (O’Reilly). 4 | Chapter 1: Introduction to Cloud Native
📄 Page
19
3 You can find more information in “Smart Endpoints and Dumb Pipes” by Martin Fowler. Figure 1-2. An online retail application built using microservices architecture Rather than using an ESB layer to integrate the services, microservices themselves create the compositions through lightweight interservice communication that’s required to build the business capability offered by the microservice. Therefore, these microservices are called smart endpoints that are connected via dumb pipes, which refers to the lightweight interservice communication techniques.3 Microservices may connect to other existing systems and in some cases may expose a simplified interface (often known as a facade) for those systems as well. The microservices don’t share databases, and external parties can access the data only via the service interface. Each microservice needs to implement the business logic as well as the interservice communication features that include resiliency, security, and so on. As cloud native applications are designed as a collection of microservices, almost every concept that you apply in microservices relates to the cloud native context as well. Therefore, we discuss most of the patterns and fundamentals of microservices architecture throughout the book. What Is Cloud Native? | 5
📄 Page
20
Use Containerization and Container Orchestration Just as microservices are important in the phase of designing and developing cloud native applications, containers are important in the packaging and running of cloud native applications. When developing cloud native applications, the microservices that we build are packaged into container images and executed on top of a container host. Let’s dig deeper to understand what this really means. What are containers? A container is a running process that is isolated from the host operating system and other processes in the system. A container interacts with its own private filesystem, which is provided by a container image. The container image is a binary that is formed by packaging everything that’s needed to run an application: application code, its dependencies, and runtime. These container images are immutable and often stored in a repository known as a container registry. To execute a container, you can create a running process out of the container image, which is known as a container instance. The container instance runs on top of the container runtime engine. Figure 1-3 compares the execution of three microservice runtimes on virtual machines (VMs) versus on a container runtime engine. Running microservices as containers is drastically different from the conventional VM execution that runs a full-blown guest operating system with virtual access to host resources through a component known as a hypervisor. Since containers run on top of a container run‐ time, they share the kernel of the host machine, processor, and memory with other containers. Hence, running microservices on containers is a lightweight, discrete pro‐ cess compared to running them on top of a VM. For example, an application that runs on a VM and takes several minutes to load may take only a few seconds to load in containers. The process of converting microservices or applications to run on top of containers is known as containerization. Docker has become the de facto platform for building, running, and sharing containerized applications. Containerization makes your microservices portable and guarantees execution con‐ sistency across multiple environments. Containers are a key driving force to make microservices independent and autonomous as they are self-sufficient and encapsula‐ ted, allowing you to replace or upgrade one without disrupting others, while utilizing the resources better than VMs. They also eliminate additional runtime preconfigura‐ tion, and are much more lightweight compared to VMs. 6 | Chapter 1: Introduction to Cloud Native