📄 Page
1
(This page has no text content)
📄 Page
2
(This page has no text content)
📄 Page
3
Praise for Reactive Systems in Java Convinced Reactive is right for your project? This is the book that will take your project from Reactive in theory to Reactive in production. Make sure every member of your team reads this book. —K. Scott Morrison, CTO Clement and Ken wrote, by far, the most up-to-date book on reactive systems that is interwoven with theories and practical code examples. It is a must-read for anyone who wants to get a deep understanding of reactive systems, event-driven architecture, and asynchronous messaging in today’s complex cloud native environments. —Mary Grygleski, Senior Developer Advocate, IBM As someone new to reactive programming and Quarkus, I found this book fascinating and extremely helpful. Its hands-on approach and illustrative examples were ideal for getting up to speed quickly. —Chris Mayfield, Associate Professor, James Madison University If you know where to look, reactive computer systems have been around for decades, but it’s in recent times, with the advent of serverless and event-driven architectures, that we’ve really seen them elevated to the point where most application developers need to be aware of them. For Java developers, this book is the perfect way to find out what a reactive system is, how to reason about it, and how to build them in a reliable and scalable manner using the most popular Kubernetes-native framework out there, Quarkus. The added advantage is that the authors speak from years of real-world product experience. —Mark Little, VP Engineering, Red Hat
📄 Page
4
(This page has no text content)
📄 Page
5
Clement Escoffier and Ken Finnigan Reactive Systems in Java Resilient, Event-Driven Architecture with Quarkus Boston Farnham Sebastopol TokyoBeijing
📄 Page
6
978-1-492-09172-1 [LSI] Reactive Systems in Java by Clement Escoffier and Ken Finnigan Copyright © 2022 Clement Escoffier and Ken Finnigan. 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: Suzanne McQuade Development Editor: Jill Leonard Production Editor: Caitlin Ghegan Copyeditor: Sharon Wilkey Proofreader: Kim Cofer Indexer: WordCo Indexing Services, Inc. Interior Designer: David Futato Cover Designer: Karen Montgomery Illustrator: Kate Dullea November 2021: First Edition Revision History for the First Edition 2021-11-09: First Release See http://oreilly.com/catalog/errata.csp?isbn=9781492091721 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Reactive Systems in Java, 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
7
To Déborah, Flore, and Néo, who left us too early. To Erin, Lorcán, and Daire.
📄 Page
8
(This page has no text content)
📄 Page
9
Table of Contents Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii Part I. Reactive and Quarkus Introduction 1. Reactive in a Nutshell. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 What Do We Mean by Reactive? 3 Reactive Software Is Not New 4 The Reactive Landscape 5 Why Are Reactive Architectures So Well-Suited for Cloud Native Applications? 7 Reactive Is Not a Silver Bullet 8 2. Introduction to Quarkus. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Java on the Cloud 9 Thorntail Example 13 Quarkus Example 15 The Quarkus Way 18 Create Your First Quarkus Application 21 Kubernetes with Quarkus in 10 Minutes 28 Going Native 34 Summary 38 Part II. Reactive and Event-Driven Applications 3. The Dark Side of Distributed Systems. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 What’s a Distributed System? 43 vii
📄 Page
10
The New Kids on the Block: Cloud Native and Kubernetes Native Applications 46 The Dark Side of Distributed Systems 51 Fallacies of Distributed Computing in a Kubernetes World 52 A Question of Timing: The Synchronous Communication Drawback 54 Summary 60 4. Design Principles of Reactive Systems. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Reactive Systems 101 61 Commands and Events 63 Commands 63 Events 64 Messages 64 Commands Versus Events: An Example 65 Destinations and Space Decoupling 68 Time Decoupling 70 The Role of Nonblocking Input/Output 71 Blocking Network I/O, Threads, and Concurrency 71 How Does Nonblocking I/O Work? 74 Reactor Pattern and Event Loop 77 Anatomy of Reactive Applications 79 Summary 82 5. Reactive Programming: Taming the Asynchronicity. . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Asynchronous Code and Patterns 83 Using Futures 89 Project Loom: Virtual Threads and Carrier Threads 91 Reactive Programming 93 Streams 94 Operators 96 Reactive Programming Libraries 100 Reactive Streams and the Need for Flow Control 100 Buffering Items 101 Dropping Items 102 What Is Backpressure? 103 Introducing Reactive Streams 103 Be Warned: It’s a Trap! 105 Backpressure in Distributed Systems 106 Summary 106 viii | Table of Contents
📄 Page
11
Part III. Building Reactive Applications and Systems with Quarkus 6. Quarkus: Reactive Engine. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 The Imperative Model 112 The Reactive Model 115 Unification of Reactive and Imperative 116 A Reactive Engine 120 A Reactive Programming Model 120 Event-Driven Architecture with Quarkus 121 Summary 122 7. Mutiny: An Event-Driven Reactive Programming API. . . . . . . . . . . . . . . . . . . . . . . . . . 123 Why Another Reactive Programming Library? 123 What Makes Mutiny Unique? 124 Mutiny Usage in Quarkus 125 Uni and Multi 126 Mutiny and Flow Control 128 Observing Events 129 Transforming Events 130 Chaining Asynchronous Actions 131 Recovering from Failure 133 Combining and Joining Items 134 Selecting Items 136 Collecting Items 137 Summary 138 8. HTTP with Reactive in Mind. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 The Journey of an HTTP Request 140 Say Hello to RESTEasy Reactive! 141 What’s the Benefit? 144 Asynchronous Endpoints Returning Uni 146 Dealing with Failure and Customizing the Response 148 Streaming Data 151 Raw Streaming 152 Streaming JSON Array 153 Using Server-Sent-Events 155 Reactive Score 157 Summary 158 9. Accessing Data Reactively. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 The Problem with Data Access 159 Nonblocking Interactions with Relational Databases 161 Table of Contents | ix
📄 Page
12
Using a Reactive ORM: Hibernate Reactive 162 What About NoSQL? 166 Interacting with Redis 166 Data-Related Events and Change Data Capture 170 Using Debezium to Capture Change 172 Summary 175 Part IV. Connecting the Dots 10. Reactive Messaging: The Connective Tissue. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 From Reactive Applications to Reactive Systems 179 Channels and Messages 180 Producing Messages 181 Consuming Messages 184 Processing Messages 186 Acknowledgments 187 Connectors 189 Building Message-Based Applications 189 Message and Acknowledgment 191 Failures and Negative Acknowledgment 193 Stream Manipulation 193 Blocking Processing 195 Retrying Processing 195 Putting Everything Together 196 Summary 200 11. The Event Bus: The Backbone. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 Kafka or AMQP: Picking the Right Tool 201 Building Reactive Systems with Kafka 202 Apache Kafka 202 Point-to-Point Communication 208 Publish/Subscribe 209 Elasticity Patterns 209 Dealing with Failures 210 Backpressure and Performance Considerations 212 Kafka on Kubernetes 213 Building Reactive Systems with AMQP 216 AMQP 1.0 217 Point-to-Point Communication 217 Publish/Subscribe 219 Elasticity Patterns 220 x | Table of Contents
📄 Page
13
Acknowledgment and Redelivery 220 Credit-Flow Backpressure Protocol 221 AMQP on Kubernetes 221 Summary 223 12. Reactive REST Client: Connecting with HTTP Endpoints. . . . . . . . . . . . . . . . . . . . . . . . 225 Interacting with an HTTP Endpoint 225 The REST Client Reactive 228 Mapping HTTP APIs to Java Interfaces 229 Invoking the Service 231 Blocking and Nonblocking 232 Handling Failures 233 Fallback 234 Retries 236 Time-out 236 Bulkheads and Circuit Breaker 236 Building API Gateways with the RESTEasy Reactive Client 238 Using the REST Client in Messaging Applications 243 Summary 248 13. Observing Reactive and Event-Driven Architectures. . . . . . . . . . . . . . . . . . . . . . . . . . . 249 Why Is Observability Important? 249 Health with Messaging 250 Metrics with Messaging 256 Distributed Tracing with Messaging 260 Summary 264 Conclusion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 Table of Contents | xi
📄 Page
14
(This page has no text content)
📄 Page
15
Preface In the IT world, the limits of today are the gateways of tomorrow. In the last 50 years, the IT world has continuously evolved, tirelessly, always pushing the limits. These changes are due to not only technical progress, but also us, the consumers. As con‐ sumers, we continue to demand more and more from the software we interact with every day. In addition, our way of interacting with software has entirely changed. We can’t live without mobile applications and devices and now accept receiving notifica‐ tions all day long. The Internet of Things (IoT) is an emerging market promising many more innovations, increasing the number of events and data processed uninter‐ ruptedly. The cloud and Kubernetes have not only changed our usage but also radi‐ cally transformed the way we design, develop, deploy, and maintain applications. But don’t be mistaken; all these revolutions come with a price. While they have enabled new uses and applications, they have also introduced massive complexity. Most software systems today are distributed systems. And distributed systems are hard to design, build, and operate, especially on the scale we need to implement these new modern applications. We need to handle failures, asynchronous communication, an ever-changing topology, the dynamic availability of resources, and so on. While the cloud promises unlimited resources, money is a limiting factor, and increasing the deployment density, meaning running more on fewer resources, becomes a strin‐ gent concern. So, what about Reactive? It is not a library you use in your code or a magic frame‐ work. Reactive is a set of principles, tools, methodologies, and frameworks that lead to building better distributed systems. How much better? It depends on the system, but applications following the Reactive principles embrace distributed systems’ chal‐ lenges and focus on elasticity, resilience, and responsiveness, as explained in The Reactive Manifesto. In this book, we use the noun Reactive, with an uppercase R, to aggregate all the vari‐ ous facets of the reactive landscape, such as reactive programming, reactive systems, reactive streams, and so on. With this book, you’ll learn how Reactive will help us xiii
📄 Page
16
face these new concerns and how it fits in cloud environments. After reading this book, you will be able to build reactive systems—resilient, adaptable, event-driven distributed systems. Who Should Read This Book? This book targets intermediate and advanced Java developers. It would be best if you were reasonably comfortable with Java; however, prior knowledge of reactive pro‐ gramming or even Reactive in general are not required. Many concepts in this book relate to distributed systems, but you do not need to be familiar with them either. Reactive systems often rely on message brokers such as Apache Kafka or Advanced Message Queuing Protocol (AMQP). This book introduces the basic knowledge you need to understand how such brokers help in designing and implementing reactive systems. Three distinct groups can benefit from this book: • Developers who are building cloud native applications or distributed systems • Architects seeking to understand the role of reactive and event-driven architectures • Curious developers who have heard about Reactive and want a better under‐ standing of it With this book, you will start a journey toward understanding, designing, building, and implementing reactive architectures. You will not only learn how it helps to build better distributed systems and cloud applications, but also see how you can use reac‐ tive patterns to improve existing systems. What About Quarkus? Attentive readers would have noticed the mention of Quarkus in the subtitle of this book. But, so far, we haven’t mentioned it. Quarkus is a Java stack tailored for the cloud. It uses build-time techniques to reduce the amount of memory used by the application and provide a fast startup time. But Quarkus is also a reactive stack. At its core, a reactive engine enables the creation of concurrent and resilient applications. Quarkus also provides all the features you need to build distributed systems that can adapt to fluctuating loads and inevitable failures. Throughout this book, we use Quarkus to demonstrate the benefits of the reactive approach and introduce various patterns and best practices. Don’t panic if you don’t xiv | Preface
📄 Page
17
have prior knowledge or experience with it. We will accompany you on the journey, guiding you at every step. This book focuses on creating reactive applications and systems that leverage Quar‐ kus capabilities and provides all the knowledge required to build such systems. We do not cover the complete Quarkus ecosystem, as this book concentrates on the Quarkus components that help in the construction of reactive systems. Navigating This Book If you are just discovering Reactive and want to know more about it, reading this book from cover to cover will leave you with an understanding of Reactive and how it can help you. If you are a seasoned reactive developer interested in Quarkus and its reactive features, you may want to skip the first part of this book and jump to the chapters that interest you the most. Part I is a brief introduction, setting the context: • Chapter 1 provides a brief overview of the reactive landscape, including its bene‐ fits and drawbacks. • Chapter 2 presents Quarkus and its build-time approach to reducing startup time and memory usage. Part II covers Reactive in general: • Chapter 3 explains the complexities of distributed systems and the misconcep‐ tions; these are the reasons for being reactive. • Chapter 4 presents the characteristics of reactive systems. • Chapter 5 covers the various forms of asynchronous development models, with a focus on reactive programming. Part III explains how to build reactive applications with Quarkus: • Chapter 6 discusses the reactive engine and bridging imperative and reactive pro‐ gramming. • Chapter 7 is a deep dive on SmallRye Mutiny, the reactive programming library used in Quarkus. • Chapter 8 explains HTTP request characteristics and how we can be reactive with HTTP. • Chapter 9 explains how you can use Quarkus to build highly concurrent and effi‐ cient applications interacting with a database. Preface | xv
📄 Page
18
The final part, Part IV, connects the dots and presents how you can build reactive sys‐ tems with Quarkus: • Chapter 10 dives into the integration of Quarkus applications with messaging technologies, an essential ingredient of reactive systems. • Chapter 11 focuses on the integration with Apache Kafka and AMQP, and how to build reactive systems with them. • Chapter 12 explores the various ways to consume HTTP endpoints from a Quar‐ kus application and how to enforce resilience and responsiveness. • Chapter 13 covers observability concerns in reactive systems, such as self- healing, tracing, and monitoring. Getting You Ready Throughout this book, you will see many examples of code. These examples illustrate the concepts covered in this book. Some are basic and run in an IDE, and others require a couple of prerequisites. We cover these examples, one by one, throughout this book. Now, maybe you’re not one for suspense. Or, more likely, maybe you’re already tired of hearing us blather on at length and just want to see this working. If that’s the case, simply point your browser to https://github.com/cescoffier/reactive-systems-in-java and feel free to kick the tires a bit. You can retrieve the code with Git using git clone https:// github.com/cescoffier/reactive-systems-in-java.git. Alternatively, you can download a ZIP file and unzip it. The code is organized by chapter. For example, the code related to Chapter 2 is avail‐ able in the chapter-2 directory (Table P-1). Depending on the chapter, the code may be split into multiple modules. For examples that are available in the code repository, the code snippet title in the book indicates the location of the file in the repository. Table P-1. Code location per chapter Chapter Title Path Chapter 2 Introduction to Quarkus https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-2 Chapter 3 The Dark Side of Distributed Systems https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-3 Chapter 4 Design Principles of Reactive Systems https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-4 Chapter 5 Reactive Programming: Taming the Asynchronicity https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-5 Chapter 7 Mutiny: An Event-Driven Reactive Programming API https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-7 xvi | Preface
📄 Page
19
Chapter Title Path Chapter 8 HTTP with Reactive in Mind https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-8 Chapter 9 Accessing Data Reactively https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-9 Chapter 10 Reactive Messaging: The Connective Tissue https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-10 Chapter 11 The Event Bus: The Backbone https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-11 Chapter 12 Reactive REST Client: Connecting with HTTP Endpoints https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-12 Chapter 13 Observing Reactive and Event- Driven Architectures https://github.com/cescoffier/reactive-systems-in-java/tree/master/chapter-13 The examples from the code repository use Java 11, so be sure to have a suitable Java Development Kit (JDK) installed on your machine. They also use Apache Maven as the build tool. You don’t have to install Maven, as the repository uses the Maven Wrapper (provisioning Maven automatically). However, if you prefer installing it, download it from the Apache Maven Project website, and follow the instructions on the Installing Apache Maven page. To build the code, run mvn verify from the root of the project. Maven is going to download a set of artifacts, so be sure to have an internet connection. This book covers Quarkus, a Kubernetes-native Java stack. You don’t need to install anything to use Quarkus, as long as you have Java and Maven. It will download every‐ thing else automatically. You will need Docker. Docker is used to create containers for our applications. Install Docker by following the instructions at the Get Docker page. Finally, several chapters illustrate the deployment of our reactive applications in Kubernetes. To deploy to Kubernetes, you first need kubectl, a command-line tool to interact with Kubernetes. Install it by following the instructions from the Kubernetes Install Tools page. Unless you have a Kubernetes cluster handy, we also recommend minikube be installed on your machine, to provide a Kubernetes environment. Fol‐ low the instructions at the minikube website to install it. Why do we need all these tools? You will see in this book that being reactive adds constraints to your application but also to your infrastructure. Kubernetes provides the primitives we need to deploy applications, create replicas, and keep our system on track. On the other side, Quarkus provides the set of features we need to implement reactive applications, including nonblocking I/O, reactive programming, reactive APIs, and messaging capabilities. Quarkus also provides integration with Kubernetes for easing the deployment and configuration of applications. Table P-2 lists the tools we are going to use in the book. Preface | xvii
📄 Page
20
Table P-2. Tools used in this book Tool Website Description Java 11 https://adoptopenjdk.net Java Virtual Machine (JVM) and Java Development Kit (JDK) Apache Maven https://maven.apache.org/download.cgi Build automation tool, based on the project object model (POM) Quarkus https://quarkus.io A Kubernetes-native stack that optimizes Java for containers Docker https://www.docker.com/get-started Container creation and execution Kubernetes https://kubernetes.io A container orchestration platform, also known as K8s minikube https://minikube.sigs.k8s.io/docs/start A local distribution of Kubernetes GraalVM https://www.graalvm.org Provides, among others tools, a compiler to create native executables from Java code Node.js https://nodejs.org/en A JavaScript runtime engine Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program ele‐ ments such as variable or function names, databases, data types, environment variables, statements, and keywords. Constant width bold Shows commands or other text that should be typed literally by the user. Constant width italic Shows text that should be replaced with user-supplied values or by values deter‐ mined by context. This element signifies a tip or suggestion. This element signifies a general note. xviii | Preface