Table of Contents
Cloud Native Patterns - Designing change-tolerant software by Cornelia Davis
Return to Cloud Native Development - Programming in the Containerized Cloud, Cloud Native Topics, Cloud Native Patterns
by Cornelia Davis
Patterns used in cloud-native applications
The cloud native patterns that follow are listed roughly in the order in which they are introduced in the book:
- Request/Response — A protocol for communication between services where a client makes a request of a remote service and in most cases expects a response. This may be done synchronously or asynchronously and is most often done over HTTP.
- Event-driven — A protocol where entities in a distributed system communicate events, and these events are the means by which the services in a cloud-native application are kept up to date.
- CQRS (Command Query Responsibility Segregation) — A pattern whereby the query processing (read) for a domain entity is separate from the command processing (write).
- Multiple service instances — Deployment of more than one instance of apps/services to support resilience, scalability, and cloud-native operational practices.
- Horizontal scaling — The creation of additional application instances to increase capacity for a service.
- Stateless services — Apps/services that do not store state in memory or on local disk that is needed for subsequent invocations of the service.
- Stateful services — Services such as databases and message queues designed to persist state. Used to provide persistent data for stateless services.
- App configuration through environment variables — Using env variables to inject values into applications on startup.
- Configuration service — A (stateful) service that is used to deliver configuration values to multiple app instances to ensure consistent operations.
- Configuration as code — Managing configurations through files that are versioned and checked into source control.
- Zero-downtime upgrades — A means of upgrading all app/service instances while the app remains fully functional.
- Rolling upgrades — A technique whereby an app is upgraded with zero downtime by upgrading subsets of all instances incrementally, in batches.
- Blue/green upgrades — A technique whereby an app is upgraded by deploying a full set of new app instances and then switching over to those in one fell swoop.
- Application health checks — Implementing an endpoint that can be called to assess the health of an app.
- Liveness probes — The periodic calling of application health endpoints and the re-creation of app instances when the health check fails.
- Server-side load balancing — A means of routing requests across multiple app instances where the client makes the requests to a single entity—the load balancer.
- Client-side load balancing — A means of routing requests across multiple app instances where the client is aware of and controls routing to the multiple instances of a service.
- Service discovery — The means by which a client will find the address or addresses for a service it will invoke.
- Retry — A technique whereby a client repeats a service request when it has received no response.
- Safe service — A service that may be invoked zero or more times, yielding the same outcome.
- Idempotent service — A service that may be invoked once or more than once, yielding the same outcome.
- Fallbacks — Application logic that is executed when a request to a downstream service fails to generate a result.
- Circuit-breaker — A technique used to stop requests to a failing service instance and then allow them through when the service resumes normal operations.
- API gateways — A service proxy used for many things, including access control, auditing, routing and much more.
- Sidecars — An approach to service proxying where the proxy sits right next to the service.
- Service mesh — The network of and control plane for sidecars.
- Distributed tracing — A means by which a thread of execution through a series of related but distributed services can be traced for troubleshooting purposes.
- Event sourcing — A pattern where the source of truth in the software is an event log from which materialized views serve the needs of service instances.
Table of Contents
Copyright
Brief Table of Contents
Table of Contents
Foreword
Preface
Acknowledgments
About this book
About the author
About the cover illustration
Part 1. The cloud-native context
Chapter 1. You keep using that word: Defining “cloud-native”
1.1. Today’s application requirements
1.2. Introducing cloud-native software
1.3. Cloud-native and world peace
Summary
Chapter 2. Running cloud-native applications in production
2.1. The obstacles
2.2. The enablers
Summary
Chapter 3. The platform for cloud-native software
3.1. The cloud(-native) platform evolution
3.2. Core tenets of the cloud-native platform
3.3. Who does what?
3.4. More cloud-native platform capabilities
Summary
Part 2. Cloud-native patterns
Chapter 4. Event-driven microservices: It’s not just request/response
4.1. We’re (usually) taught imperative programming
4.2. Reintroducing event-driven computing
4.3. My global cookbook
4.4. Introducing Command Query Responsibility Segregation
4.5. Different styles, similar challenges
Summary
Chapter 5. App redundancy: Scale-out and statelessness
5.1. Cloud-native apps have many instances deployed
5.2. Stateful apps in the cloud
5.3. HTTP sessions and sticky sessions
5.4. Stateful services and stateless apps
Summary
Chapter 6. Application configuration: Not just environment variables
6.1. Why are we even talking about config?
6.2. The app’s configuration layer
6.3. Injecting system/environment values
6.4. Injecting application configuration
Summary
Chapter 7. The application lifecycle: Accounting for constant change
7.1. Having empathy for operations
7.2. Single-app lifecycle, multiple-instance lifecycles
7.3. Coordinating across different app lifecycles
7.4. Let’s see this in action: Credential rotation and app lifecycle
7.5. Dealing with ephemeral runtime environments
7.6. Visibility of app lifecycle state
7.7. Serverless
Summary
Chapter 8. Accessing apps: Services, routing, and service discovery
8.1. The service abstraction
8.2. Dynamic routing
8.3. Service discovery
Summary
Chapter 9. Interaction redundancy: Retries and other control loops
9.1. Request retries
9.2. Fallback logic
9.3. Control loops
Summary
Chapter 10. Fronting services: Circuit breakers and API gateways
10.1. Circuit breakers
10.2. API gateways
10.3. The service mesh
Summary
Chapter 11. Troubleshooting: Finding the needle in the haystack
11.1. Application logging
11.2. Application metrics
11.3. Distributed tracing
Summary
Chapter 12. Cloud-native data: Breaking the data monolith
12.1. Every microservice needs a cache
12.2. Moving from request/response to event driven
12.3. The event log
12.4. Event sourcing
12.5. We’re just scratching the surface
Summary
Patterns used in cloud-native applications
- Index
- List of Figures
- List of Tables
- List of Listings
List of Figures
Chapter 1. You keep using that word: Defining “cloud-native”
Figure 1.1. AWS partitions the services it offers into regions and availability zones. Regions map to geographic areas, and AZs provide further redundancy and isolation within a single region.
Figure 1.2. Applications deployed onto AWS may be deployed into a single AZ (IMDb), or in multiple AZs (Nest) but only a single region, or in multiple AZs and multiple regions (Netflix). This provides different resiliency profiles.
Figure 1.3. If applications are properly architected and deployed, digital solutions can survive even a broad outage, such as of an entire region.
Figure 1.4. User requirements for software drive development toward cloud-native architectural and management tenets.
Figure 1.5. Architectural and management tenets lead to the core characteristics of cloud-native software: it’s highly distributed and must operate in a constantly changing environment even as the software is constantly evolving.
Figure 1.6. Familiar elements of a basic software architecture
Figure 1.7. Cloud-native software takes familiar concepts and adds extreme distribution, with redundancy everywhere, and constant change.
Figure 1.8. Key entities in the model for cloud-native software: apps, data, and interactions
Figure 1.9. The online banking software is a composition of apps and data services. Many types of interaction protocols are in play.
Figure 1.10. What appears to a user as a single experience with Wizard’s Bank is realized by independently developed and managed software assets.
Figure 1.11. A decomposed and loosely coupled data fabric requires techniques for cohesive data management.
Figure 1.12. Dispensing funds without access to the source of record is ill-advised.
Figure 1.13. Applying some cloud-native patterns, such as redundancy and properly distributed deployments, brings benefit even in software that isn’t fully cloud-native.
Chapter 2. Running cloud-native applications in production
Figure 2.1. Factors that contribute to the difficulty in deploying software and keeping it running well in production
Figure 2.2. Testing two apps in sequence is straightforward when all tests pass.
Figure 2.3. A failing test immediately complicates the process for preproduction testing.
Figure 2.4. Explicit attention to these four factors develops a system of efficiency, predictability, and stability.
Figure 2.5. Every dev/test cycle doesn’t result in a ship; instead, every cycle results in software that’s ready to ship. Shipping then becomes a business decision.
Figure 2.6. A traditional software delivery lifecycle front-loads a lot of development work and a long testing cycle before creating the artifacts that can then be released into production.
Figure 2.7. Continuous delivery is concerned with allowing business drivers, not IT readiness, to determine when software is shipped.
Figure 2.8. When the development schedule slips, you need to decide between two unpalatable options.
Figure 2.9. Shorter iterations designed for continuous delivery allow for an agile release process while maintaining software quality.
Figure 2.10. Even when environment-specific values are organized into property files, including property files in the deployable artifact, you’ll have different artifacts throughout the SDLC.
Figure 2.11. The desired outcome is to be able to consistently establish apps running in standardized environments. Note that the app is the same across all environments; the runtime environment is standardized within an SDLC stage.
Figure 2.12. The assembly of standardized base images, controlled environment configurations, and single deployable artifacts is automated.
Figure 2.13. Data tells you how parallel deployments of multiple versions of your apps are operating. You use that data to program control flows to those apps, supporting safe rollouts of new software in production.
Figure 2.14. The desired state of your deployed software
Figure 2.15. When the actual state doesn’t match the desired state, the eventually consistent system initiates actions to bring them back into alignment.
Chapter 3. The platform for cloud-native software
Figure 3.1. Infrastructure-as-a-service (IaaS) offerings from major cloud platform providers
Figure 3.2. Accessing application logs in an infrastructure-centric environment is tedious.
Figure 3.3. Accessing application logs in an app-centric environment is simple.
Figure 3.4. The cloud-native platform abstracts infrastructure concerns, allowing teams to focus on their applications instead of these lower-level concerns.
Figure 3.5. A host usually has multiple containers running on it. These containers share the OS kernel from the host. But each container has its own root operating filesystem, runtime environment, and application code.
Figure 3.6. When studying the capabilities of a cloud-native platform, at times we’ll think of the container as a black box within which your application runs. A bit later, we’ll drill into the details of what’s running in the container.
Figure 3.7. Management of workloads across availability zones is handled by the cloud-native platform.
Figure 3.8. The state of applications running on the platform is managed by continually comparing the desired state to the actual state and then executing corrective actions when necessary.
Figure 3.9. The recommendations service finds the favorites service via DNS lookup and routing.
Figure 3.10. The recommendations service directly accesses the favorites service via IP address; the routing function is distributed.
Figure 3.11. The configuration service of the cloud-native platform provides important configuration capabilities for microservice-based application deployments.
Figure 3.12. The cloud-native platform presents a contract that allows consumers to deploy and manage their software without being exposed to low-level infrastructure details. Nonfunctional requirements such as performance guarantees are realized via SLAs that are achieved via specific platform configurations.
Figure 3.13. The right abstractions support the formation of autonomous platform and application teams. Each is responsible for deployment, monitoring, scaling, and upgrading their respective products.
Figure 3.14. Code commits generate deployable artifacts that are deployed into a dev environment that looks similar to production, but has development versions of services such as databases and message queues (depicted by the symbols on the right).
Figure 3.15. The same deployable artifact is deployed into a staging environment, where it’s bound to services (depicted by the symbols on the right) that more closely match those that exist in production.
Figure 3.16. The same artifact is deployed into similar environments throughout the SDLC and must absorb the unavoidable differences across the environments.
Figure 3.17. The platform must include a mechanism that allows the contract between app and runtime environment and bound services to serve the needs of the SDLC.
Figure 3.18. Control functions that are on the critical path for every release of every app reduce the number of deployments that can be performed.
Figure 3.19. By deploying to a platform that implements controls, you can reduce to mere minutes the time between having an app ready for deployment and performing that deployment.
Figure 3.20. The assembly of standardized base images, controlled environment configurations, and single deployable artifacts is automated.
Figure 3.21. The structure of the container image clearly separates the concerns of the app team from those of the platform team.
Figure 3.22. The right platform enables app teams to operate independently from platform teams.
Figure 3.23. True multitenancy in the compute tier shares resources in the control plane, as well as in the compute layer (the Linux host and kernel) while using containers to achieve resource isolation.
Chapter 4. Event-driven microservices: It’s not just request/response
Figure 4.1. Diagram appearing in a presentation from Scott Mansfield of Netflix shows a single request to retrieve the homepage for a user results in a significant fan-out of requests to downstream microservices.
Figure 4.2. Contrast the base primitive of request/response to event-driven invocation styles.
Figure 4.3. The Abundant Sunshine website will display a list of posts made by my favorite food bloggers. The aggregation is a composition of the network of people I follow and posts made by those individuals.
Figure 4.4. Rendering a portion of the web page depends on a series of coordinated requests and responses.
Figure 4.5. Users, the connections between them, and the posts each has recently made
Figure 4.6. The composite result generated by the Connections’ Posts microservice is produced by making calls to the Connections and Posts microservices and aggregating results.
Figure 4.7. Events are the means through which related microservices are connected.
Figure 4.8. When a request is received, the Connections’ Posts service can generate a result without depending on other services in the system.
Figure 4.9. The Posts service not only persists the new post that was created, but also delivers an event reporting that this post has been created.
Figure 4.10. Microservices can implement both request/response and event-driven patterns. Events are primarily used to loosely couple microservices.
Figure 4.11. Rendering the web page now only requires execution of the Connections’ Posts microservice. Through event handling, it already has all of the data it needs to satisfy the request, so no downstream requests and responses are required.
Figure 4.12. The Connections service generates an event when a new connection has been recorded.
Figure 4.13. The Posts service generates an event when a new post has been recorded.
Figure 4.14. The event handler for the Connections’ Posts service processes events as they occur.
Figure 4.15. The Connections’ Posts service generates and delivers a response when a request is received. This is completely independent from the operations of the other microservices in our solution.
Figure 4.16. Separating the write logic from the read logic allows you to support different models for these different concerns. This leads to more elegant, maintainable code.
Figure 4.17. The retry is a key pattern used in request/response microservice architectures to compensate for network partitions. In event-driven systems, the use of an event store is a key technique that compensates for network instability.
Chapter 5. App redundancy: Scale-out and statelessness
Figure 5.1. Given the same input, the result produced by an app instance must be the same, regardless of whether there are one, two, or one hundred instances of the app.
Figure 5.2. The cloud-native app must ensure consistent results in spite of possible differences in other contextual influencers.
Figure 5.3. Architecting apps for multi-instance deployments affords significant gains in the efficiency of resource use as well as resilience and other operational benefits.
Figure 5.4. My terminal configuration allows me to send requests to the microservices while watching the results in the other windows.
Figure 5.5. The deployment topology of the cookbook software, refactored into separate components and deployed into a cloud setting. At the moment, each app has only a single instance deployed.
Figure 5.6. Logically, you have a single app that serves a series of requests. Because each user logs in before trying any Get Data calls, you expect each of those will succeed.
Figure 5.7. When a single logical entity is deployed as multiple instances, care must be taken to ensure that the distributed set of events continues to be treated as a whole.
Figure 5.8. When you add a second instance of the Connections’ Posts app, its local list of valid tokens differs from that of the first. This is exactly the problem with stateful apps in cloud-native software.
Figure 5.9. Sticky sessions are implemented by the load balancer and are used to tie a specific user to a specific instance of an app.
Figure 5.10. A load balancer supporting sticky sessions will attempt to stick specific users to specific app instances, but may be forced to send a request to a different instance. In cloud-native software, you must assume that instances come and go with some regularity. If you don’t, the user experience suffers.
Figure 5.11. Storing valid tokens in a stateful service that’s bound to all instances of the Connections’ Posts service allows apps to be stateless but our overall software solution to be stateful.
Figure 5.12. Your new deployment replaces the Connections’ Posts service with a stateless version and adds a Redis server to store authentication tokens.
Chapter 6. Application configuration: Not just environment variables
Figure 6.1. The cloud-native app must ensure consistent outcomes despite differences in contextual influencers such as request history (different app instances have processed a different set of requests) and system environment values (such as IP addresses). Application configuration should be the same across instances but may differ at times.
Figure 6.2. Application configuration changes are often brought about from changes in the infrastructure, which are either anticipated (as depicted here, a rolling upgrade) or unexpected.
Figure 6.3. Apps have a specific configuration layer that supports both system environment and application configuration. This layer allows the implementation to use values regardless of how their values are provided.
Figure 6.4. The application source references properties that are defined in the property file. The property file acts as a specification of the configuration parameters for the app, and can indicate that values should come from env variables (INSTANCE_IP).
Figure 6.5. This software deployment topology currently requires a great deal of hand edits of connections between the services. These manual configurations will be progressively eliminated as you proceed through more cloud-native patterns.
Figure 6.6. Responsible for the deployment and management of the app instances, Kubernetes establishes the environment variables defined in the deployment manifest, drawing values from the infrastructure entities it has established for the app.
Figure 6.7. Application configuration is facilitated through the use of a source code-control system that will persist configuration values, and a configuration service that provides managed access to that data.
Figure 6.8. The application configuration layer depends on the property file as the means for injecting values; those values come in through the use of a config server.
Figure 6.9. The property file acts as the common configuration layer for both system config and application config. System config data is injected via env variables, and app config data is injected via a configuration service.
Chapter 7. The application lifecycle: Accounting for constant change
Figure 7.1. A simple depiction of the stages in an app’s lifecycle
Figure 7.2. Both instances of the Posts service are running with the same configuration and act as a single logical application.
Figure 7.3. Because the two instances of the Posts service have different configurations applied, the outcome of issuing a request will differ greatly depending on whether a request is routed to the first instance of the app or the second. This must be avoided, even during a zero-downtime upgrade.
Figure 7.4. Application configuration is best applied when the application is started. Most application frameworks naturally function this way.
Figure 7.5. The blue/green deployment is used when an app can’t tolerate having multiple versions running side by side (when the multiple versions can’t be made to act as a single logical instance).
Figure 7.6. During rolling upgrades, production traffic is routed to more than one version of the app. The app must be able to function as a single logical whole, even as requests are being distributed over different versions.
Figure 7.7. One consideration when deciding between blue/green and rolling upgrades is the resource requirement. Note that during a blue/green deployment, double the resources are needed for the Posts API, whereas the rolling upgrade has only a slight increase in the resource requirements.
Figure 7.8. Application lifecycle events must be coordinated across different components of your software.
Figure 7.9. This credential rotation pattern is an exemplar of the consideration that the software architect/developer must pay mind to. The goal is to ensure that the software has zero downtime during application lifecycle events that affect numerous apps.
Figure 7.10. During the rolling upgrade of the Connections’ Posts service, the different instances will be sending different secrets. The apps have been designed to support this app lifecycle approach.
Figure 7.11. Application startup is an important event that many other components in the cloud-native software will be interested in.
Figure 7.12. Apps have the responsibility for broadcasting lifecycle events because other components will be affected. Those other components likewise have the responsibility for adapting to those changes.
Figure 7.13. Application lifecycle states and transitions between them. In the happy path, when apps are started and stopped, there’s an opportunity to broadcast app lifecycle change events. But when something goes awry, state-change broadcasts will be incorrect or may never even be generated.
Figure 7.14. Control loops play an important role in cloud-native systems, providing redundancy that compensates for “glitches” in the system.
Figure 7.15. All lifecycle stages are passed through for a single-function invocation.
Figure 7.16. Serverless computing requires a platform that optimizes the early stages, and the developer is responsible for optimizing the starting and execution of the app.
Chapter 8. Accessing apps: Services, routing, and service discovery
Figure 8.1. In cloud-native software, apps are deployed as multiple instances. For the software to function predictably, you want each set of app instances to operate as a single logical entity.
Figure 8.2. Each set of app instances is represented by a logical entity that defines the behavior of the app. That behavior is expected from all instances.
Figure 8.3. Your software is defined as a composition of services. Each service is implemented as a set of service instances.
Figure 8.4. The single logical app represented by a set of app instances is a service. The protocol that allows a client to find and access its dependent services is service discovery. The means for distributing incoming requests across the set of app instances is dynamic routing.
Figure 8.5. The Google search service is addressed via the name www.google.com, and that name is mapped to a concrete IP address via DNS. The Google platform keeps the list of routes to search service instances up to date, and load-balances requests among them.
Figure 8.6. Until now, the configuration of your blog aggregation software lacked the use of any type of service discovery protocol and bound the Connections’ Posts service to the Posts service via IP address. This results in a brittle deployment.
Figure 8.7. With centralized, or server-side, load balancing, a client request is handled by a cluster of load balancers that has a list of routes to service instances. The load balancer distributes the client requests across different app instances.
Figure 8.8. With client-side load balancing, the client sends requests directly to the service instances and performs the task of distributing requests across all instances. The list of routes to service instances is maintained within the client itself.
Figure 8.9. The manifest for the Posts (abstract) service and the service instances that implement it. The list of service instance routes is kept up to date via a control loop that uses the service selector to find all app instances that meet certain criteria (in this case, the label app: posts).
Figure 8.10. Concrete implementation of the Posts service running in Minikube. The Kube Proxy is a load-balancer implementation and includes the list of IP addresses to all instances of the Posts service.
Figure 8.11. At the time of service access, the service discovery protocol allows a client to refer to a service by name, resulting in a more resilient binding between them.
Figure 8.12. The service discovery protocol must account for the eventually consistent nature of the Domain Name System.
Figure 8.13. DNS entries that map domain names to IP addresses
Figure 8.14. Service discovery differs depending on whether client-side load balancing or server-side load balancing is used.
Figure 8.15. Kubernetes provides an implementation of the service discovery protocol with the inclusion of a domain name service and processes that automatically create and access entries in that registry.
Chapter 9. Interaction redundancy: Retries and other control loops
Figure 9.1. Certain design patterns applied on both sides of an interaction will yield far more robust and reliable systems. We’ll cover client-side patterns in this chapter, and service-side patterns in the next.
Figure 9.2. Retries can insulate parts of your distributed system from errors in other parts.
Figure 9.3. Restricted networks act like restricted highways, backing up requests that keep coming in the same volumes as before. Even when the restrictions are lifted, it can take some time before all of the queued-up traffic is moving again.
Figure 9.4. The client, the Connections’ Posts service, will retry on connection or read timeouts to the Posts service. It will continue trying until it receives a success status code from the HTTP request to the Posts service.
Figure 9.5. A deployment containing five instances of the Connections’ Posts service and four of the Posts service results in 20 ways that an instance of the former may connect to an instance of the latter. There are four connections between instances of the Posts service and the single instance of the MySQL service. Retries are an effective way of finding a healthy path through the network of microservices.
Figure 9.6. Thinking ahead, you cache results when they’re available, so that when you later experience trouble, you have those cached values to use as a part of your fallback logic.
Figure 9.7. Implementation of client-side patterns such as retries and fallbacks yields a far more robust system. (You’ll turn to the services side of the interaction in the next chapter.)
Chapter 10. Fronting services: Circuit breakers and API gateways
Figure 10.1. Just as the client can and should implement certain patterns to act as a good participant in the interaction, so too should the service. These are the patterns covered in this chapter.
Figure 10.2. You model the operation of the circuit breaker via three states and define the conditions or events that cause transitions between them. When the circuit is Closed, traffic flows freely. When the circuit is Open, requests won’t reach the service. The Half-Open state is transitory, the means by which the circuit can be reset to Closed.
Figure 10.3. At times when a service is unavailable—because of network outages, trouble with the service itself, or another issue—one of the main benefits of circuit breakers is that they significantly reduce the amount of time wasted while waiting for responses that are at that moment unlikely to come.
Figure 10.4. For your first test run, you’ll be running with the naïve retries on the client side of the interaction, and a simple circuit breaker at the front of the service.
Figure 10.5. The deployment topology has versions of the Connections’ Posts and Connections services from the previous chapter and provides a new version of the Posts service. This implementation wraps the main Posts logic in a circuit breaker.
Figure 10.6. The default Hystrix implementation trips the circuit when 50% of requests fail and moves from the Open state to a Half-Open state seconds after entering the Open state. Successful or unsuccessful requests made while in the Half-Open state will transition the circuit breaker to Closed and Open states, respectively.
Figure 10.7. Failures can occur on either side of an interaction, and fallbacks provide safeguards.
Figure 10.8. The API gateway fronts all services and becomes the policy configuration and enforcement point for them.
Figure 10.9. You can think of the gateway as a single logical entity, something that’s needed for administration. But for cloud-native architectures, the implementation is best distributed.
Figure 10.10. The distributed gateway runs as a sidecar to each service. In Kubernetes this is achieved by running two containers in a single pod—one that’s the primary service and the other a gateway sidecar.
Figure 10.11. Figure 10.7 redrawn with retry behavior on the client side of the interaction implemented in a sidecar, and the circuit breaker on the service side also implemented in a sidecar.
Figure 10.12. The abstract “gateway” of figure 10.10 is now made concrete with an Envoy sidecar, one of several sidecar implementations.
Figure 10.13. A service mesh brings together sidecars and a control plane for their management.
Chapter 11. Troubleshooting: Finding the needle in the haystack
Figure 11.1. With a pull-based metrics-gathering approach, each service implements a metrics endpoint that’s accessed at a regular interval to capture and store the values for subsequent search and analysis.
Figure 11.2. The collector that implements the metrics aggregator must reach each service instance at every interval and must therefore control the load balancing. It will interact through a service discovery protocol to keep up to date with IP address changes.
Figure 11.3. The metrics gatherer must address each service instance individually, and because those IP addresses are accessible only from within a runtime environment such as Kubernetes (external access is via load balancer), the metrics gather is also generally deployed within that network space. In the case of Kubernetes, this also allows you to use the built-in DNS service for service discovery.
Figure 11.4. In a push-based metrics solution, each service sends metrics to an aggregation and storage service at a certain interval.
Figure 11.5. When a service mesh is used, the application services are simply configured to connect to the local sidecar proxy, and the service mesh control plane is used to keep the configuration of the metrics delivery components up to date.
Figure 11.6. Diagram appearing in a presentation from Scott Mansfield of Netflix shows a request to the Netflix homepage results in a series of downstream service invocations. Distributed tracing allows you to gain visibility into this complex call tree.
Figure 11.7. Requests carry tracers that are propagated in downstream requests. The tracers are then available in the runtime context of a service invocation and annotates data that’s aggregated into a distributed tracing service.
Figure 11.8. From the annotated log output, you can piece together some of the flow of a single request—that with trace ID 2e30. Notice that you can’t see where the calls to the services came from.
Figure 11.9. Here, the service invocations are overlaid on the time, trace ID, and span ID stamped log output shown in the previous figure. This information isn’t currently appearing in your logs.
Figure 11.10. Zipkin provides a user interface that allows for search through the data stored in the distributed metrics database and pulls together entries that are related through a common trace ID. This display shows five such traces, each of which draws together five individual service requests, represented as spans.
Figure 11.11. Zipkin display showing the details of a single request to the Connections’ Posts service. This service request resulted in four downstream requests: one to the Connections service, one to the Posts service, and then two more requests to the Connections service. The latency for each request, represented as a span, is also shown.
Figure 11.12. While the network was disrupted, requests to the Connections’ Posts service resulted in failed downstream requests. You see, for example, that what normally was satisfied with four downstream requests resulted in many more requests/spans. The bars reporting the time and number of spans (for example, “26.488s 22 spans”) are also now colored red, indicating that some of those downstream requests returned errors.
Figure 11.13. The details of one of the request traces show repeated failed calls to the Posts service, each taking roughly 500 ms. This is the value of the request time-out on the HTTP invocations made from the Connections’ Posts service.
Figure 11.14. When the network is restored, downstream requests again succeed, but you can see from the time taken to fulfill Connections’ Posts requests that a backlog of traffic had been generated and required time to dissipate.
Chapter 12. Cloud-native data: Breaking the data monolith
Figure 12.1. User requirements for software drive our development toward cloud-native architectural and management tenets. For cloud-native data, we’ll turn our focus to modularity and the autonomy that comes from it.
Figure 12.2. Independent microservices that share a single database are not autonomous.
Figure 12.3. A simple topology with an aggregating service communicating with dependent services via request/response.
Figure 12.4. Whenever one of the dependent services is unavailable or otherwise not functioning correctly, the Connections’ Posts service will also fail to generate a result.
Figure 12.5. A cache added to the Connections’ Posts service will store the responses from successful requests to dependent services. The source of truth for the data remains in the databases tied to each of the downstream services; the storage local to the Connections’ Posts service is not an authoritative copy.
Figure 12.6. By adding a cache to Connections’ Posts, you add a degree of autonomy to the service and achieve greater resilience as a result.
Figure 12.7. When changes occur in downstream services, events describing those changes are sent to interested parties where their local storage is updated.
Figure 12.8. The event-driven approach allows the Connections’ Posts service to operate with complete autonomy, using the data in the local storage. Missed events, however, can corrupt that local storage, “successfully” returning incorrect results.
Figure 12.9. Events are usually of interest to numerous parties, so when they’re not properly delivered, this can cause inconsistencies to propagate throughout the system.
Figure 12.10. With the addition of an event log, you’ve now completely decoupled each of the three services from one another. Events are produced into and consumed from the event log, and the event log is responsible for retaining the events until they’re no longer needed.
Figure 12.11. Events are produced into and consumed from the event log, which maintains those events as long as they’re needed. Through use of the event log, you’ve entirely decoupled the services from one another.
Figure 12.12. The full event and data topology of our implementation. The Posts and Connections services both “own” data (source of truth) and produce events (dotted arrows) when changes occur in that data. Posts and Connections’ Posts both store data they don’t own (local storage) and update that data by handling events (solid arrows).
Figure 12.13. The directory structure for our three microservices, showing the organization of event-producing and -consuming code, as well as read APIs and both “owned” data storage and “local” data storage.
Figure 12.14. A service implements a write controller that’s responsible for taking changes to the first-class entities of the service, an event handler that’s responsible for maintaining a local database of nonprimary entity data that’s nevertheless part of the bounded context, and a read controller that supports querying data across these databases.
Figure 12.15. The event topology defines the topics that will hold events and the producers and consumers of each. The Connections service produces users and connection events. The Posts service produces post events and consumes user events. The Connections’ Posts service consumes user, connection, and post events.
Figure 12.16. Messaging systems, largely standardized with JMS, provide support for queues and topics. Queues retain messages until each one is consumed. Topics don’t retain any messages, instead simply delivering them to all available subscribers.
Figure 12.17. Event topics in Kafka have behaviors that are a hybrid between JMS topics and queues. Like the old-school topics, events are delivered to all unique group IDs—there are multiple subscribers. But within a set of listeners that share the same group ID, the behavior is like a queue, delivering the event to one of the listeners.
Figure 12.18. Our derivation of cloud-native data begins by breaking apart the data monolith so that the data supports the bounded contexts of the microservices. Microservices get their own databases, and where needed, data is kept consistent across the distributed data fabric through eventing.
Figure 12.19. The write controller only writes to the event log, which is now the source of truth. The local database for the microservice stores only projections derived from the event log data; this derivation is implemented in the event handler.
Figure 12.20. The event log is the single source of truth. All microservice-local stores are projections derived from the events in the event log, by the event handlers. The microservice-local stores are only projections.
List of Tables
Chapter 9. Interaction redundancy: Retries and other control loops
Table 9.1. Employing a simple retry with other patterns can eliminate or lessen negative impacts.
Chapter 10. Fronting services: Circuit breakers and API gateways
Table 10.1. A circuit breaker provides significant protections against retry storms.
Table 10.2. Results from the network outage simulations show the benefit of applying certain cloud-native patterns to service interactions.
Chapter 12. Cloud-native data: Breaking the data monolith
Table 12.1. Service roles in our event-driven software architecture
Table 12.2. Service roles in our event-sourced software architecture
List of Listings
Chapter 4. Event-driven microservices: It’s not just request/response
Listing 4.1. Method from ConnectionsPostsController.java
Listing 4.2. Method from PostsWriteController.java
Listing 4.3. Method from EventsController.java of Connections’ Posts service
Chapter 5. App redundancy: Scale-out and statelessness
Listing 5.1. LoginController.java
Listing 5.2. CloudnativeApplication.java
Listing 5.3. ConnectionsPostsController.java
Listing 5.4. CloudnativeApplication.java
Listing 5.5. LoginController.java
Listing 5.6. ConnectionsPostsController.java
Chapter 6. Application configuration: Not just environment variables
Listing 6.1. application.properties
Listing 6.2. PostsController.java
Listing 6.3. cookbook-deployment-connectionsposts.yaml
Listing 6.4. Utils.java
Listing 6.5. PostsController.java
Listing 6.6. ConnectionsPostsController.java
Listing 6.7. Connections’ Posts application.properties
Chapter 7. The application lifecycle: Accounting for constant change
Listing 7.1. Utils.java
Listing 7.2. Method from PostsController.java
Listing 7.3. Method from ConnectionsPostsController.java
Listing 7.4. Method from the Utils class of the ConnectionsPosts service
Listing 7.5. Method from Posts_Controller.java
Listing 7.6. Excerpt from cookbook-deployment-posts.yaml
Chapter 8. Accessing apps: Services, routing, and service discovery
Listing 8.1. Excerpt from cookbook-deployment-connectionsposts.yaml
Listing 8.2. Excerpt from redis-deployment.yam
Chapter 9. Interaction redundancy: Retries and other control loops
Listing 9.1. Excerpt from ConnectionsPostsController.java
Listing 9.2. Excerpt from ConnectionsPostsController.java
Listing 9.3. Method from PostsServiceClient.java
Listing 9.4. Excerpt from pom.xml for the Connections’ Posts service
Listing 9.5. Method from PostsServiceClient.java
Listing 9.6. Method from PostsServiceClient.java
Chapter 10. Fronting services: Circuit breakers and API gateways
Listing 10.1. Method from PostsService.java
Listing 10.2. Methods from PostsService.java
Chapter 11. Troubleshooting: Finding the needle in the haystack
Listing 11.1. Log output from Connections’ Posts
Listing 11.2. Log output from Connections
Listing 11.3. Log output from Posts
Listing 11.4. Added to pom.xml of each of the three microservices
Listing 11.5. Added to deployment yaml file for each of the three microservices
Chapter 12. Cloud-native data: Breaking the data monolith
Listing 12.1. Method from ConnectionsWriteController.java
Listing 12.2. Method from ConnectionsWriteController.java
Listing 12.3. Methods from EventHandler.java
Listing 12.4. Method from PostsWriteController.java
Listing 12.5. Method from EventHandler.java
Index
[SYMBOL][A][B][C][D][E][F][G][H][I][J][K][L][M][N][O][P][Q][R][S][T][U][V][W][Y][Z]
SYMBOL
401 – Unauthorized response
500 status code
A
A/B testing
access logging
actual state
/actuator/metrics endpoint
all argument, 2nd, 3rd, 4th
Amazon Web Services (AWS), 2nd
AOP dependency
Apache Avro
Apache Kafka
Apache Log4j
API endpoints
API gateways
case for
topology
app health endpoints
app instances
application configuration
configuration layer
dynamic scaling
infrastructure changes causing configuration changes
injecting application configuration
config server, 2nd
security
injecting system/environment values
building microservices
running apps
setting up
updating with zero downtime
application lifecycle
app lifecycle events
blue/green upgrades
coordinating across different lifecycles
credential rotation
building microservices
running apps
setting up
ephemeral runtime environments
operational concerns
parallel deployments
rolling upgrades
serverless computing
state visibility
application logging
application metrics
pulling metrics
pushing metrics
application.properties file, 2nd, 3rd, 4th
applicationConfiguration key
ApplicationContextAware class
ApplicationPreparedEvent
applications
dynamic routing
client-side load balancing
route freshness
server-side load balancing
in cloud-native model
requirements for
data-driven
Internet of Things (IoT)
mobile support
multidevice support
shortened feedback cycles
zero downtime
service abstraction
blog aggregator
Google searches
service discovery
example of
in Kubernetes
on web
with client-side load-balancing
stateless
in cloud
stateful services and
apt get function
at-least-once delivery
auth token
authentication
Authentication app
authorization
availability, 2nd
availability zones (AZs), 2nd, 3rd, 4th
AWS (Amazon Web Services), 2nd
AWS Elastic Beanstalk
AZs (availability zones), 2nd, 3rd, 4th
Azure App Service
B
-b command line switch
back-off policy
@Backoff annotation
blog aggregator, service abstraction
blue/green deployment, 2nd, 3rd
blue/green upgrades
built-in DNS service
C
CAP theorem, 2nd
Cassandra database
CD (continuous delivery)
centralized load balancing
change, 2nd
as exception
as rule
change control, 2nd
different approach in treating
support for
circuit breakers
implementing
running apps
setting up
software circuit breakers
CLI (command-line interface)
client library
client-side load balancing
dynamic routing
service discovery
client-side patterns
Closed state, circuit breaker
cloud
cloud-native software versus
evolution of cloud-native software
stateful apps in
decomposing monolith and binding to database
poor handling of session state
Cloud Architecture Strategy, AWS
Cloud Foundry, 2nd
Cloud Foundry Operations Manager application
cloud-native applications
cloud-native data
caching
event log
event payload
idempotency
implementing event-driven microservices
topics and queues
event sourcing
implementing
source of truth
moving from request/response to event driven
cloud-native interactions
cloud-native platform
cloud-native repository
cloud-native software, 2nd, 3rd
application requirements
data-driven
Internet of Things
mobile support
multidevice support
shortened feedback cycles
zero downtime
cloud versus
defined
example of
interfacing with existing solutions
model for
cloud-native apps
cloud-native data
cloud-native interactions
reasons for not going cloud-native
cloud-native software delivery lifecycle
enablers
change is the rule
continuous delivery
repeatability
safe deployments
obstacles
change is exception
production instability
risky deployments
snowflakes
cloud-native software platforms
capabilities of
change control
containers, controlling what goes into
control functions
software development lifecycle (SDLC), support for entire
upgrading and vulnerability patching
core tenets of
containers
support for
evolution of
cloud
infrastructure-centric versus app-centric environment
map of responsibilities
cloudnative-circuitbreaker directory
cloudnative-connections microservice
cloudnative-eventlog module
cloudnative-posts microservice
cloudnative-requestresponse directory
cloudnative-statelessness directory
cloudnative-troubleshooting directory
CloudnativeApplication Spring Boot configuration
CloudnativeApplication.java file, 2nd
CMDB (configuration management database), 2nd
Cockcroft, Adrian
com.corneliadavis.cloudnative.connections.secrets property
com.corneliadavis.cloudnative.posts.secrets property, 2nd
com.corneliadavis.cloudnative.posts.write package, 2nd
command prompt, MYSQL
Command Query Responsibility Segregation (CQRS)
command-line interface (CLI)
Common Vulnerabilities and Exposures (CVE)
compliance
config layer
config map, Kubernetes
config package
config server, 2nd
running apps
setting up
configuration data store
configuration layer
configuration management database (CMDB), 2nd
configuredSecretsIn string
connection event
ConnectionEvent
CONNECTIONPOSTSCONTROLLER_IMPLEMENTRETRIES variable, 2nd
Connections microservice, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th, 12th, 13th, 14th, 15th, 16th, 17th, 18th, 19th
connections package
Connections service, configuring and deploying
Connections URL, 2nd, 3rd, 4th
Connections’ Posts microservice, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th, 12th, 13th, 14th, 15th, 16th, 17th, 18th, 19th, 20th
Connections’ Posts microservice
Connections’ Posts microservice
Connections’ Posts microservice
Connections’ Posts microservice
Connections’ Posts microservice
Connections’ Posts microservice
Connections’ Posts microservice
Connections’ Posts microservice
Connections’ Posts microservice
Connections’ Posts microservice
ConnectionsPosts controller
connectionsposts logs
connectionsposts package
connectionsposts-svc service
ConnectionsPostsController
ConnectionsPostsController.java file, 2nd, 3rd, 4th, 5th
ConnectionsWriteController
consistency, favoring availability over
containers
controlling what goes into
overview
continuous delivery (CD)
control functions, 2nd
control loops, 2nd, 3rd
controlling
types of
control plane
control-related functions
cookbook-deployment-connectionposts.yaml file
cookbook-deployment-kubernetes-connectionposts.yaml file
Core DNS, 2nd
CORS (cross-origin resource sharing)
cost management
Couchbase database
CrashLoopBackOff
create database command
create database cookbook command
credential rotation, 2nd, 3rd
building microservices
running apps
setting up
credentials, 2nd
CredHub, Pivotal
cross-origin resource sharing (CORS)
CRUD services, 2nd
curl command, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th, 12th, 13th, 14th, 15th, 16th, 17th, 18th, 19th
curl localhost:8080/connectionsosts/cdavisafc command
curl localhost:8081/posts command
curl localhost:8082/connections command
curl localhost:8082/users command
cursor
CVE (Common Vulnerabilities and Exposures)
D
daemonset controller
data-driven, as application requirement
DELETE operation
deleteDeploymentComplete.sh, 2nd
deployable artifacts, 2nd
deployApps.sh, 2nd, 3rd
deployment
parallel
risky
design patterns
desired state
distributed tracing
assembling traces via Zipkin
implementation details
running apps
setting up
tracer output
distribution, support for
DNS (Domain Name System), 2nd, 3rd
Docker
docker build command, 2nd, 3rd
Docker container
Docker Hub, 2nd, 3rd, 4th, 5th, 6th, 7th
Docker images, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th
docker push command, 2nd
Domain Name System (DNS), 2nd, 3rd
drawFromConfigServer
dynamic routing, 2nd
client-side load balancing
route freshness
server-side load balancing
dynamic scaling
E
EC2 (Elastic Compute Cloud platform), 2nd
Amazon and reliability support
availability in other countries
Elasticsearch
ELK stack
EmbeddedServletContainer
encryption of data in flight
endpoints controller
enterprise service bus (ESB)
environment variables, 2nd, 3rd, 4th
Envoy, 2nd, 3rd
ephemeral runtime environments
ESB (enterprise service bus)
Eureka
event handler, 2nd, 3rd
event log, 2nd, 3rd
event payload
idempotency
implementing event-driven microservices
running apps
setting up
topics and queues
event payload
event sourcing, 2nd
implementing
source of truth
event store/log
event topology
event-driven programming model, 2nd
cloud-native data
implementing event-driven microservices
running apps
setting up
microservices
obtaining and building
running
request/response programming model versus
setting up
studying code
event-driven software architecture
event-sourcing patterns
eventlogstart tag
EventsController
eventual consistency, 2nd
exactly-once delivery
F
FaaS (function-as-a-service)
failures, 2nd
fallback logic, 2nd
fallbackMethod1
fallbackMethod2
fat jar
favorites service
feedback cycles, shortened
foobar
front-loaded cycle
function-as-a-service (FaaS)
G
GAE (Google App Engine)
GCP (Google Cloud Platform), 2nd, 3rd, 4th, 5th
Get Data calls
get method
GET operation
get pods output
GET request
getByUsername method
getPostsByUserId method
Git
git checkout master command
GitHub, 2nd, 3rd
GKE (Google Kubernetes Engine)
Google App Engine (GAE)
Google Cloud Platform (GCP), 2nd, 3rd, 4th, 5th
Google Kubernetes Engine (GKE)
Google searches, service abstraction
group ID
groupId, 2nd
H
H2 dependency
Half-Open state, circuit breaker, 2nd, 3rd
hardcoding strings
HEAD request
health endpoints and probes
/healthz endpoint
@HistrixCommand() annotation, 2nd, 3rd, 4th
horizontal scaling
HTTP 401 – Unauthorized response
HTTP error
HTTP POST event, 2nd
HTTP requests
HTTP sessions
Hystrix, 2nd, 3rd
I
–i switch
IaaS (infrastructure-as-a-service)
idempotency
idempotent method
identity store
imperative programming
in-memory hash map
independent microservices, 2nd, 3rd
infect endpoint
infrastructure as code
infrastructure-as-a-service (IaaS)
INSTANCE_IP variable, 2nd, 3rd, 4th, 5th
IoT (Internet of Things)
IP addresses, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th
ip variable
ipaddress property, 2nd, 3rd
IPADDRESS variable
isHealthy Boolean
Istio, 2nd
isValidSecret method
J
J2EE (Java 2 Platform, Enterprise Edition)
JAR files, 2nd, 3rd, 4th, 5th
Java 2 Platform, Enterprise Edition (J2EE)
java command
Java Development Kit (JDK)
Java Runtime Environment (JRE)
JavaScript
JBoss, 2nd
jdbc URL
JDK (Java Development Kit)
JMeter, 2nd, 3rd, 4th, 5th, 6th
JRE (Java Runtime Environment)
K
Kafka, 2nd, 3rd
key/value pairs
key/value store, 2nd
keys * command
Kibana
kind clients
kind retries
Kube DNS
Kube Proxy
kubectl apply command, 2nd, 3rd, 4th
kubectl command, 2nd, 3rd
kubectl create -f cookbook-deployment-connections.yaml
kubectl create -f cookbook-deployment-posts.yaml
kubectl create -f mysql-deployment.yaml command
kubectl create -f redis-deployment.yaml command
kubectl create command
kubectl create namespace command
kubectl delete deploy command
kubectl delete deploy jmeter-deployment command, 2nd
kubectl exec command
$ kubectl get all command
kubectl get all command, 2nd, 3rd, 4th, 5th, 6th, 7th
kubectl get pods command, 2nd
kubectl logs -f pod/posts-fc74d75bc-92txh command
kubectl logs -l app=connections command
kubectl logs -l app=connectionsposts command
kubectl logs -l app=posts command
kubectl logs command
kubectl logs –f <podname> command
kubectl logs –f command
Kubernetes, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th, 12th, 13th, 14th, 15th, 16th, 17th, 18th, 19th, 20th
Kubernetes
Kubernetes
Kubernetes
Kubernetes
Kubernetes
Kubernetes
Kubernetes
Kubernetes
eventual consistency and
service discovery in
L
latency
load balancers, 2nd
load balancing, 2nd
load spikes
LoadBalancer
./loadData.sh command
loadData.sh script
local storage
localhost
Logback
/login endpoint
LoginController.java file, 2nd
Logstash
look-aside caching
loose coupling, 2nd, 3rd
M
manageability
Mansfield, Scott
medium trust code
messaging systems
metrics gatherer
microservices, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th, 12th
credential rotation
decomposing monolith and binding to database
event driven
running apps
setting up
obtaining and building
event-driven programming model
request/response programming model
running
event-driven programming model
request/response programming model
system/environment values
Microsoft Azure
Minikube, 2nd, 3rd, 4th, 5th, 6th
minikube command
minikube service –url sccs command
minikube service list command
minikube service mysql –url command
mobile devices, support for
Model, View, Controller (MVC) pattern
modularity
MongoDB
msql CLI
MVC (Model, View, Controller) pattern
mvn clean install command, 2nd, 3rd, 4th, 5th
my global cookbook
MySQL, 2nd, 3rd, 4th, 5th
mysql CLI, 2nd, 3rd, 4th, 5th, 6th
mysql command
mysql-57bdb878f5-dhlck pod
mysql-deployment.yaml
N
namespaces controller
Netflix, 2nd, 3rd, 4th, 5th
Netflix Eurek
Netflix Ribbon
network disruption
NewFromConnectionsController class
newPost method
Nginx
O
oldSecret
onApplicationEvent method
Open state, circuit breaker, 2nd
OpenSSH
openssh function
operating system version (os.version)
OPTIONS request
OS kernel, 2nd
OS root filesystem
P
parallel deployments
partition tolerance
PID (process ID)
PII (personally identifiable information)
ping
pipelines
Pivotal Cloud Cache
pods, 2nd, 3rd
POM files
pom.xml files
post event
POST request, 2nd, 3rd
PostEvent
Posts microservice, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th, 12th, 13th, 14th, 15th, 16th, 17th, 18th, 19th, 20th
Posts microservice
Posts microservice
Posts microservice
Posts microservice
posts package
Posts service, configuring and deploying, 2nd
Posts URL, 2nd, 3rd, 4th
PostsController class
PostsController.java file, 2nd, 3rd, 4th
PostsService class, 2nd
PostsServiceClient class
postsServiceClient.getPosts
PostSummary class
PostsWriteController
Process ID (PID)
production instability, 2nd
Prometheus
property files, 2nd, 3rd, 4th, 5th
pull-based approach
PUT operation
Q
queues
R
RabbitMQ
read controller
Read role, 2nd
read-through caching
Ready to Ship software
recommendations service
@Recover annotation, 2nd
recovery point objectives (RPOs)
recovery time objectives (RTOs)
Redis, 2nd, 3rd, 4th, 5th, 6th, 7th
Redis IP, 2nd
Redis port, 2nd
redis-cli, 2nd, 3rd
redis-svc
redundancy, 2nd, 3rd
/refresh URL
regions
repeatability
control of deployable artifact
control of environment
control of process
replica sets
replication controller
request durability
request resilience
request retries
kind clients
retry storms
running apps
setting up
simple retries
running apps
setting up
when not to retry
request/response pattern, 2nd, 3rd
request/response programming model
cloud-native data
event-driven programming model versus
microservices
obtaining and building
running
setting up
studying code
resilience, 2nd, 3rd
resiliency patterns
resilient interactions
control loops
controlling
types of
fallback logic
request retries
kind clients
retry storms
simple retries
when not to retry
ResourceAccessException
responsiveness
RESTful service
restricted networks
restTemplate, 2nd
retry behavior
retry logic disabled
retry logic enabled
retry pattern
retry storms, 2nd, 3rd
fallback logic
running apps
setting up
@Retryable method, 2nd, 3rd
returning cached results command
Ribbon client
risky deployments
rolling upgrades, 2nd, 3rd
route commands
route freshness
routing, 2nd
RPOs (recovery point objectives)
RTOs (recovery time objectives)
runbook
Running App Version
S
S3 (Simple Storage Service)
safe methods
scale-out/in
SCCS (Spring Cloud Configuration Server), 2nd, 3rd, 4th, 5th, 6th
SCCS URL
SDLC (Software Development Lifecycle), 2nd
continuous delivery
streamlined
traditional
variability across
security, 2nd
sequential programming model
server-side load balancing
serverless computing
service abstraction
blog aggregator
Google searches
service discovery, 2nd, 3rd, 4th
example of
in Kubernetes
on web
with client-side load-balancing
service mesh, 2nd, 3rd
control plane
sidecars
service roles, 2nd
service-side patterns
session ID
session state, poor handling of
configuring and deploying Connections and Posts services
configuring and deploying connections’ Posts service
deploying and configuring database
introducing cloud-native platform
side effects
sidecars, 2nd
single logical app
single logical entity
Site Reliability Engineering (SRE)
SLAs (service-level agreements), 2nd
sleep command
sleepWindowMilliseconds
SLF4J
snowflakes, 2nd, 3rd, 4th, 5th, 6th, 7th
SO (special order) application
software artifacts
software delivery lifecycle
Software Development Lifecycle (SDLC), 2nd, 3rd, 4th, 5th
software-defined compute
source code control (SCC) system
source of the truth, 2nd
source-level debugging
span ID, 2nd
special order (SO) application
Splunk, 2nd
Spring Boot application, 2nd, 3rd, 4th, 5th
Spring Boot JPA
Spring Cloud
Spring Cloud Configuration Server (SCCS), 2nd, 3rd, 4th, 5th
Spring Cloud Sleuth
Spring Framework, 2nd
Spring Retry, 2nd
spring.zipkin.baseUrl property
SQS (Simple Queue Service)
SRE (Site Reliability Engineering)
ssh, 2nd
SSH access, 2nd
state visibility
state-change broadcasts
state-change events
statefulness and statelessness
HTTP sessions and sticky sessions
multiple instance deployment
stateful apps in cloud
decomposing monolith and binding to database
poor handling of session state
stateful services and stateless apps
making apps stateless
stateful services as special services
status.podIP attribute
stderr, 2nd
stdout, 2nd
stem cells
sticky sessions, 2nd
system variables
System.getenv
System.out
system/environment values
building microservices
running apps
setting up
systemEnvironment key
T
targetPort
TCP liveness probes
TCP/UDP protocol level
theFirstSecret
theSecondSecret
tight coupling
tokens, 2nd
Tomcat container, 2nd, 3rd
topics
trace ID, 2nd
TRACE request
tracers
traditional load-balancing
troubleshooting
application logging
application metrics
pulling metrics from cloud-native applications
pushing metrics from cloud-native applications
distributed tracing
assembling traces via Zipkin
implementation details
running apps
setting up
tracer output
Twelve-Factor App, 2nd
U
UAT (user acceptance testing)
unauthenticated
unified log
upgrading
user acceptance testing (UAT)
user event
User Profile app
user-ID-to-username mapping data
UserEvent
Users URL, 2nd, 3rd, 4th
Utils class, 2nd, 3rd, 4th, 5th
Utils.java file, 2nd
V
valid login token
@Value annotation, 2nd
Vault, HashiCorp, 2nd
vent log topic
Version of Deployable Artifact
Version of the App Config
VERSIONING_TRIGGER
vertical scaling
VMs (virtual machines), 2nd
vulnerability patching
W
watch kubectl get all command
watch kubectl get pods command, 2nd
WebLogic, 2nd
WebSphere, 2nd
while loop, 2nd
Write and Event Producer
write controller, 2nd, 3rd
write logic (commands)
Y
YAML files, 2nd
Z
zero downtime, 2nd, 3rd
as application requirement
updating application configuration with
zero-downtime credential rotation pattern
Zipkin, 2nd
Zuul