📄 Page
1
Matthew A. Titmus Cloud Native Go Building Reliable Services in Unreliable Environments
📄 Page
2
ISBN: 978-1-098-15642-8 US $69.99 CAN $87.99 PROGR AMMING L ANGUAGES Learn how to use Go’s strengths to develop services that are scalable and resilient even in an unpredictable environment. With this book’s expanded second edition, Go developers will explore the composition and construction of cloud native applications, from lower-level Go features and mid-level patterns to high-level architectural considerations. Each chapter in this new edition builds on the lessons of the previous chapter, taking intermediate to advanced developers through Go to construct a simple but fully featured distributed key-value store. You’ll learn about Go generics, dependability and reliability, memory leaks, and message-oriented middleware. New chapters on security and distributed state delve into critical aspects of developing secure distributed cloud native applications. With this book you will: • Learn the features that make Go an ideal language for building cloud native software • Understand how Go solves the challenges of designing scalable distributed services • Design and implement a reliable cloud native service by leveraging Go’s lower-level features such as channels and goroutines • Apply patterns, abstractions, and tooling to effectively build and manage complex distributed systems • Overcome stumbling blocks when using Go to build and manage a cloud native service Cloud Native Go “Matthew does an excellent job in bringing together two independent but highly interdependent concepts: cloud native computing and use of the Go language. The merger creates a must-read for anyone working (or wanting to work) in the cloud native application space.” Lee Atchison, author of Architecting for Scale (O’Reilly) “Technical books can be hard to consume, but Matthew Titmus does an amazing job of telling a story that is easy to follow and includes working examples to help readers really understand the concepts being presented.” Celeste Stinger, Site Reliability Engineer, Limit Break Matthew Titmus is a seasoned veteran of the software development industry and an early advocate of both cloud native technologies in general and the Go language in particular. He helps companies migrate monolithic applications into a containerized, cloud native world, so they can transform the way services are developed, deployed, and managed.
📄 Page
3
Praise for Cloud Native Go Matthew does an excellent job in bringing together two independent but highly interdependent concepts: cloud native computing and use of the Go language. The merger creates a must-read for anyone working (or wanting to work) in the cloud native application space. —Lee Atchison Author, Architecting for Scale (O’Reilly) Technical books can be hard to consume, but Matthew Titmus does an amazing job of telling a story that is easy to follow and includes working examples to help readers really understand the concepts being presented. —Celeste Stinger Senior Site Reliability Engineer, Limit Break This is the first book I’ve come across that covers such a breadth and depth of modern cloud native practices in such a practical way. The patterns presented here have clear examples to solve real problems that are faced by engineers on a daily basis. —Alvaro Atienza Software Engineer, Aktos Matt’s expertise in the art and science of building reliable systems in a fundamentally unreliable world are clearly (and humorously) captured in the pages within. Join him as he introduces you to the fundamental building blocks and system designs that enable large-scale, reliable systems to be constructed from the ephemeral and unreliable components that comprise the underlying cloud infrastructure of today’s modern computing environment. —David Nicponski Former Principal Engineer, Robinhood
📄 Page
4
Over the past few years, two infrastructure trends have been happening: Go has been increasingly used for infrastructure, in addition to backend, and the infrastructure is moving to the cloud. This book summarizes the state of the art of the combination of the two. —Natalie Pistunovich Lead Developer Advocate, Aerospike I came in knowing next to nothing about Go and left feeling like an expert. I would go so far as to say that simply reading this book made me a better engineer. —James Quigley Staff Site Reliability Engineer, Oscar Health
📄 Page
5
Matthew A. Titmus Cloud Native Go Building Reliable Services in Unreliable Environments SECOND EDITION
📄 Page
6
978-1-098-15642-8 [LSI] Cloud Native Go by Matthew A. Titmus Copyright © 2025 Matthew A. Titmus. 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: Brian Guerin Development Editor: Melissa Potter Production Editor: Elizabeth Faerm Copyeditor: Stephanie English Proofreader: Piper Editorial Consulting, LLC Indexer: nSight, Inc. Interior Designer: David Futato Cover Designer: Karen Montgomery Illustrator: Kate Dullea October 2024: Second Edition Revision History for the Second Edition 2024-10-14: First Release See http://oreilly.com/catalog/errata.csp?isbn=9781098156428 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Cloud Native Go, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. The views expressed in this work are those of the author and do not represent the publisher’s views. While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author 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
For you, Dad. Your gentleness, wisdom, and humility are dearly missed. Also, you taught me to code, so any mistakes in this book are technically your fault.
📄 Page
8
(This page has no text content)
📄 Page
9
Table of Contents Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv Part I. Going Cloud Native 1. What Is a “Cloud Native” Application?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 The Story So Far 4 What Is Cloud Native? 6 Scalability 6 Loose Coupling 7 Resilience 8 Manageability 10 Observability 11 Why Is Cloud Native a Thing? 12 Summary 13 2. Why Go Rules the Cloud Native World. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 The Motivation Behind Go 15 Features for a Cloud Native World 16 Composition and Structural Typing 16 Comprehensibility 18 CSP-Style Concurrency 19 Fast Builds 20 Linguistic Stability 21 Memory Safety 21 Performance 22 vii
📄 Page
10
Static Linking 23 Static Typing 24 Summary 25 Part II. Cloud Native Go Constructs 3. Go Language Foundations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Basic Data Types 29 Booleans 30 Simple Numbers 30 Complex Numbers 31 Strings 31 Variables 32 Short Variable Declarations 33 Zero Values 33 The Blank Identifier 35 Constants 35 Container Types: Arrays, Slices, and Maps 36 Arrays 36 Slices 37 Maps 41 Pointers 43 Control Structures 44 Fun with for 45 The if Statement 47 The switch Statement 48 Error Handling 50 Creating an Error 50 Putting the Fun in Functions: Variadics and Closures 51 Functions 51 Variadic Functions 55 Anonymous Functions and Closures 56 Structs, Methods, and Interfaces 57 Structs 58 Methods 59 Interfaces 60 Composition with Type Embedding 62 Generics 64 The Before Times 64 viii | Table of Contents
📄 Page
11
Generic Functions 65 Generic Types 66 Type Constraints 67 Type Inference 67 The Good Stuff: Concurrency 68 Goroutines 68 Channels 69 Select 71 Summary 73 4. Cloud Native Patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 The Context Package 76 What Context Can Do for You 77 Creating Context 78 Defining Context Deadlines and Timeouts 78 Defining Request-Scoped Values 79 Using a Context 80 Layout of This Chapter 81 Stability Patterns 81 Circuit Breaker 82 Debounce 86 Retry 90 Throttle 93 Timeout 96 Concurrency Patterns 99 Fan-In 100 Fan-Out 102 Future 104 Sharding 108 Worker Pool 113 Chord 116 Summary 120 5. Building a Cloud Native Service. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Let’s Build a Service! 121 What’s a Key-Value Store? 122 Requirements 122 What Is Idempotence and Why Does It Matter? 122 The Eventual Goal 124 Generation 0: The Core Functionality 124 Table of Contents | ix
📄 Page
12
Your Super Simple API 125 Generation 1: The Monolith 126 Building an HTTP Server with net/http 126 Building an HTTP Server with gorilla/mux 128 Building a RESTful Service 131 Making Your Data Structure Concurrency-Safe 135 Generation 2: Persisting Resource State 138 What’s a Transaction Log? 139 Storing State in a Transaction Log File 140 Storing State in an External Database 152 Generation 3: Implementing Transport Layer Security 160 Transport Layer Security 160 Private Key and Certificate Files 161 Securing Your Web Service with HTTPS 162 Transport Layer Summary 164 Containerizing Your Key-Value Store 164 Docker (Absolute) Basics 165 Building Your Key-Value Store Container 172 Externalizing Container Data 176 Summary 177 Part III. The Cloud Native Attributes 6. Cloud Native Design Principles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 What’s the Point of Cloud Native? 182 It’s All About Dependability 182 What Is Dependability and Why Is It So Important? 183 Dependability: It’s Not Just for Ops Anymore 185 Achieving Dependability 186 Fault Prevention 188 Fault Tolerance 190 Fault Removal 190 Fault Forecasting 191 The Continuing Relevance of The Twelve-Factor App 192 I. Codebase 193 II. Dependencies 193 III. Configuration 194 IV. Backing Services 196 V. Build, Release, Run 197 x | Table of Contents
📄 Page
13
VI. Processes 198 VII. Data Isolation 198 VIII. Scalability 199 IX. Disposability 200 X. Development/Production Parity 200 XI. Logs 201 XII. Administrative Processes 202 Summary 203 7. Scalability. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 What Is Scalability? 206 Different Forms of Scaling 207 The Four Common Bottlenecks 208 State and Statelessness 209 Application State Versus Resource State 210 Advantages of Statelessness 210 Scaling Postponed: Efficiency 211 Efficient Caching Using an LRU Cache 212 Efficient Synchronization 215 Memory Leaks Can…fatal error: runtime: out of memory 220 On Efficiency 223 Service Architectures 223 The Monolith System Architecture 224 The Microservices System Architecture 225 Serverless Architectures 227 Summary 231 8. Loose Coupling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 Coupling 234 Coupling Takes Many Forms 235 Service Discovery 238 Messaging Protocols 239 Messaging Patterns 240 Request-Response Messaging 240 Publish-Subscribe Messaging 257 Loose Coupling Local Resources with Plug-ins 258 In-Process Plug-ins with the plugin Package 259 HashiCorp’s Go Plug-in System Over RPC 265 Hexagonal Architecture 272 The Architecture 273 Table of Contents | xi
📄 Page
14
Implementing a Hexagonal Service 274 Summary 281 9. Resilience. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 Keep on Ticking: Why Resilience Matters 284 What Does It Mean for a System to Fail? 285 Building for Resilience 286 Cascading Failures 287 Preventing Overload 288 Play It Again: Retrying Requests 293 Backoff Algorithms 294 Circuit Breaking 298 Timeouts 299 Idempotence 305 Service Redundancy 309 Designing for Redundancy 310 Autoscaling 312 Healthy Health Checks 313 What Does It Mean for a Service to Be “Healthy”? 314 Liveness and Readiness Probes 314 The Three Types of Health Checks 315 Failing Open 319 Graceful Shutdowns 320 Signals and Traps 320 Stop Incoming Requests 322 Clean Up Your Resources 323 Putting It Into Action 323 Summary 325 10. Manageability. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 What Is Manageability and Why Should I Care? 328 Configuring Your Application 330 Configuration Good Practice 330 Configuring with Environment Variables 331 Configuring with Command-Line Arguments 332 Configuring with Files 338 Viper: The Swiss Army Knife of Configuration Packages 353 Feature Management with Feature Flags 358 The Evolution of a Feature Flag 358 Generation 0: The Initial Implementation 359 xii | Table of Contents
📄 Page
15
Generation 1: The Hardcoded Feature Flag 359 Generation 2: The Configurable Flag 360 Generation 3: Dynamic Feature Flags 361 Summary 365 11. Observability. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 What Is Observability? 368 Why Do We Need Observability? 369 How Is Observability Different from “Traditional” Monitoring? 369 The “Three Pillars of Observability” 370 OpenTelemetry 371 The OpenTelemetry Components 372 Distributed Tracing 373 Distributed Tracing Concepts 374 Distributed Tracing with OpenTelemetry 376 Putting It All Together: Distributed Tracing 388 Metrics 395 Push Versus Pull Metric Collection 397 Metrics with OpenTelemetry 400 Putting It All Together: Metrics 409 Logging 412 Better Logging Practices 413 Logging with Go’s Standard log Package 416 Structured Logging with the log/slog Package 418 OpenTelemetry Logging 422 Summary 422 12. Security. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425 Go: Secure by Design 426 Common Vulnerabilities 427 Injection 427 Broken Access Control 429 Cryptographic Failures 431 Handling Untrusted Input 431 Input Validation 432 Input Sanitization 439 Output Encoding 441 Authentication 442 Password-Based Authentication 443 Token-Based Authentication 447 Table of Contents | xiii
📄 Page
16
Communication Security 454 Transport Layer Security 455 HTTP Over TLS 455 gRPC Over TLS 455 Cryptographic Practices 456 Hashing 457 Hashing Algorithms 458 Encryption 460 Cryptographic Randomness 468 Database Security 469 Connections 470 Parameterized Queries 471 Regular Expressions 472 How Go Regex Is Different 472 Syntax 473 Summary 473 13. Distributed State. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475 Distributed State Is Hard 476 Theoretical Foundations 477 The CAP Theorem 477 Consistency Models 479 Data Replication 481 Common Distributed Algorithms 483 Consensus Algorithms 484 Status Dissemination Techniques 488 Distributing Our Key-Value Store 489 Adding Some Raft 490 Defining the State Machine 490 The Apply Method 492 Setting Up the Raft Node 493 Defining the API 497 Putting It All Together 498 Future Directions 499 Summary 499 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 xiv | Table of Contents
📄 Page
17
1 Including CNCF Sandbox, Incubating, and Graduated code-based (nonspecification) projects, as of February 2024. Preface It’s a magical time to be a technologist. We have Docker to build containers, and Kubernetes to orchestrate them. Prome‐ theus lets us monitor them. Consul lets us discover them. Jaeger lets us trace the rela‐ tionships between them. These are just a few examples, but there are many, many more, all representative of a new generation of technologies: all of them are “cloud native,” and all of them are written in Go. The term cloud native feels ambiguous and buzzwordy, but it actually has a pretty specific definition. According to the Cloud Native Computing Foundation, a sub- foundation of the renowned Linux Foundation, a cloud native application is one that’s designed to be scalable in the face of a wildly changing load, resilient in the face of environmental uncertainty, and manageable in the face of ever-changing require‐ ments. In other words, a cloud native application is built for life in a cruel, uncertain universe. Incorporating lessons learned from years of building cloud-based software, Go was released by Google a little more than a decade ago as the first major language designed specifically for the development of cloud native software. This was largely because the common server languages in use at the time simply weren’t a great fit for writing the kinds of distributed, process-intensive applications that Google produces a lot of. Since that time, Go has emerged as the lingua franca of cloud native development, being used in everything from Docker to Harbor, Kubernetes to Consul, InfluxDB to CockroachDB. Ten out of fifteen of the Cloud Native Computing Foundation’s gradu‐ ated projects, and forty-two of sixty-two1 of its projects overall, are written mostly or entirely in Go. And more arrive every day. xv
📄 Page
18
What’s New in the Second Edition The Go language has advanced quite a bit since the first edition of Cloud Native Go. In the second edition, we build off of those advances not only to update and expand the original 11 chapters but to bring you 2 brand new chapters as well. The first of these is focused on secure coding practices, providing comprehensive guidelines to protect your applications from malicious (or even just careless) actors. The second explores the theory and practice of handling state in distributed systems. Finally, the second edition of Cloud Native Go incorporates reader feedback and addresses errata from the first edition, refining the content for clarity and accuracy. These improvements make this edition an invaluable resource for both new and experienced Go developers working in cloud native environments. Who Should Read This Book This book is directed at intermediate-to-advanced developers, particularly web appli‐ cation engineers and DevOps specialists/site reliability engineers. Many will have been using Go to build web services but may be unfamiliar with the subtleties of cloud native development—or even have a clear idea of what “cloud native” is—and have subsequently found their services to be difficult to manage, deploy, or observe. For these readers, this work will not only provide a solid foundation in how to build a cloud native service, but it will also show why these techniques matter at all, as well as offer concrete examples to understand this sometimes abstract topic. It’s expected that many readers may be more familiar with other languages but have been lured by Go’s reputation as the language of cloud native development. For these readers, this book will present best practices for adopting Go as their cloud native development language and help them solve their own cloud native management and deployment issues. Why I Wrote This Book The way that applications are designed, built, and deployed is changing. Demands of scale are forcing developers to spread their services’ efforts across legions of servers: the industry is going “cloud native.” But this introduces a host of new problems: how do you develop or deploy or manage a service running on ten servers? A hundred? A thousand? Unfortunately, the existing books in the “cloud native” space focus on abstract design principles and contain only rudimentary examples of how to do any of this, or none at all. This book seeks to fill a need in the marketplace for a practical demonstration of complex cloud native design principles. xvi | Preface
📄 Page
19
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. This element indicates a warning or caution. Using Code Examples Supplemental material (code examples, exercises, etc.) is available for download at https://github.com/cloud-native-go/examples. This book is here to help you get your job done. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing examples from O’Reilly Preface | xvii
📄 Page
20
books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission. We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Cloud Native Go by Matthew A. Titmus (O’Reilly). Copyright 2025 Matthew A. Titmus, 978-1-098-15642-8.” If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at permissions@oreilly.com. 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-889-8969 (in the United States or Canada) 707-827-7019 (international or local) 707-829-0104 (fax) support@oreilly.com https://www.oreilly.com/about/contact.html We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at https://oreil.ly/cloud-native-go-2e. For news and information about our books and courses, visit https://oreilly.com. Find us on LinkedIn: https://linkedin.com/company/oreilly-media. Watch us on YouTube: https://youtube.com/oreillymedia. xviii | Preface