SW Development Method - Google
SW Development Method - Google
110
HOTOS ’23, June 22–24, 2023, Providence, RI, USA Sanjay Ghemawat, Robert Grandl, Srdjan Petrovic, Michael Whittaker et al.
111
Towards Modern Development of Cloud Applications HOTOS ’23, June 22–24, 2023, Providence, RI, USA
112
HOTOS ’23, June 22–24, 2023, Providence, RI, USA Sanjay Ghemawat, Robert Grandl, Srdjan Petrovic, Michael Whittaker et al.
API Description the components; and to handle requests to start new compo-
RegisterReplica Register a proclet as alive and ready. nents. The manager also issues environment-specific APIs
StartComponent Start a component, potentially in another process. (e.g., Google Cloud [16], AWS [4]) to update traffic assign-
ComponentsToHost Get components a proclet should host. ments and to scale up and down components based on load,
Table 1: Example API between the application and runtime. health, and performance constraints. Note that the runtime
implements the control plane but not the data plane. Proclets
manages the components in a running binary. It runs them, communicate directly with one another.
starts them, stops them, restarts them on failure, etc. 4.4 Atomic Rollouts
The implementer of the API is the runtime, which is re-
sponsible for all control plane operations. The runtime de- Developers inevitably have to release new versions of their
cides how and where proclets should run. For example, a application. A widely used approach is to perform rolling
multiprocess runtime may run every proclet in a subpro- updates, where the machines in a deployment are updated
cess; an SSH runtime may run proclets via SSH; and a cloud from the old version to the new version one by one. During
runtime may run proclets as Kubernetes pods [25, 28]. a rolling update, machines running different versions of the
Concretely, proclets interact with the runtime over a Unix code have to communicate with each other, which can lead
pipe. For example, when a proclet is constructed, it sends to failures. [78] shows that the majority of update failures
a RegisterReplica message over the pipe to mark itself are caused by these cross-version interactions.
as alive and ready. It periodically issues ComponentsToHost To address these complexities, we propose a different ap-
requests to learn which components it should run. If a com- proach. The runtime ensures that application versions are
ponent calls a method on a different component, the proclet rolled out atomically, meaning that all component commu-
issues a StartComponent request to ensure it is started. nication occurs within a single version of the application.
The runtime implements these APIs in a way that makes The runtime gradually shifts traffic from the old version to
sense for the deployment environment. We expect most run- the new version, but once a user request is forwarded to a
time implementations to contain the following two pieces: specific version, it is processed entirely within that version.
(1) a set of envelope processes that communicate directly One popular implementation of atomic rollouts is the use of
with proclets via UNIX pipes, and (2) a global manager that blue/green deployments [9].
orchestrates the execution of the proclets (see Figure 3). 5 Enabled Innovations
Global Manager
5.1 Transport, Placement, and Scaling
AWS
Deployment/Management
Web UI
Generates distributed code
Integration with Cloud APIs
The runtime has a bird’s-eye view into application execution,
Profiling Tools GKE
Debugging Tools
Rollouts
Scaling which enables new avenues to optimize performance. For
Colocation Azure
E2E Testing Tools
Placement example, our framework can construct a fine-grained call
Metrics, traces, logs
Cloudlab
graph between components and use it to identify the critical
path, the bottleneck components, the chatty components, etc.
Envelope Envelope Using this information, the runtime can make smarter scal-
ing, placement, and co-location decisions. Moreover, because
Application
A
proclet proclet serialization and transport are abstracted from the developer,
C
B the runtime is free to optimize them. For network bottle-
OS Processes
necked applications, for example, the runtime may decide
Containers to compress messages on the wire. For certain deployments,
Execution
Servers VMs Pods the transport may leverage technologies like RDMA [32].
5.2 Routing
Figure 3: Proposed Deployer Architecture. The performance of some components improves greatly
when requests are routed with affinity. For example, consider
An envelope runs as the parent process to a proclet and an in-memory cache component backed by an underlying
relays API calls to the manager. The manager launches en- disk-based storage system. The cache hit rate and overall per-
velopes and (indirectly) proclets across the set of available formance increase when requests for the same key are routed
resources (e.g., servers, VMs). Throughout the lifetime of to the same cache replica. Slicer [44] showed that many ap-
the application, the manager interacts with the envelopes plications can benefit from this type of affinity based routing
to collect health and load information of the running com- and that the routing is most efficient when embedded in
ponents; to aggregate metrics, logs, and traces exported by the application itself [43]. Our programming framework can
113
Towards Modern Development of Cloud Applications HOTOS ’23, June 22–24, 2023, Providence, RI, USA
be naturally extended to include a routing API. The run- researchers to focus on developing new solutions for tuning
time could also learn which methods benefit the most from applications and reducing deployment costs.
routing and route them automatically.
6 Prototype Implementation
5.3 Automated Testing Our prototype implementation is written in Go [38] and in-
cludes the component APIs described in Figure 2, the code
One of the touted benefits of microservice architectures is
generator described in Section 4.2, and the proclet architec-
fault-tolerance. The idea is that if one service in an applica-
ture described in Section 4.3. The implementation uses a
tion fails, the functionality of the application degrades but
custom serialization format and a custom transport protocol
the app as a whole remains available. This is great in theory,
built directly on top of TCP. The prototype also comes with
but in practice it relies on the developer to ensure that their
a Google Kubernetes Engine (GKE) deployer, which imple-
application is resilient to failures and, more importantly, to
ments multi-region deployments with gradual blue/green
test that their failure-handling logic is correct. Testing is
rollouts. It uses Horizontal Pod Autoscalers [20] to dynami-
particularly challenging due to the overhead in building and
cally adjust the number of container replicas based on load
running 𝑛 different microservices, systematically failing and
and follows an architecture similar to that in Figure 3. Our
restoring them, and checking for correct behavior. As a re-
implementation is available at github.com/ServiceWeaver.
sult, only a fraction of microservice-based systems are tested
for this type of fault tolerance. With our proposal, it is trivial 6.1 Evaluation
to run end-to-end tests. Because applications are written as To evaluate our prototype, we used a popular web applica-
single binaries in a single programming language, end-to- tion [41] representative of the kinds of microservice applica-
end tests become simple unit tests. This opens the door to tions developers write. The application has eleven microser-
automated fault tolerance testing, akin to chaos testing [47], vices and uses gRPC [18] and Kubernetes [25] to deploy on
Jepsen testing [14], and model checking [62]. the cloud. The application is written in various programming
languages, so for a fair comparison, we ported the application
5.4 Stateful Rollouts to be written fully in Go. We then ported the application to
Our proposal ensures that components in one version of an our prototype, with each microservice rewritten as a compo-
application never communicate with components in a dif- nent. We used Locust [26], a workload generator, to load-test
ferent version. This makes it easier for developers to reason the application with and without our prototype.
about correctness. However, if an application updates state The workload generator sends a steady rate of HTTP
in a persistent storage system, like a database, then different requests to the applications. Both application versions were
versions of an application will indirectly influence each other configured to auto-scale the number of container replicas
via the data they read and write. These cross-version interac- in response to load. We measured the number of CPU cores
tions are unavoidable—persistent state, by definition, persists used by the application versions in a steady state, as well as
across versions—but an open question remains about how their end-to-end latencies. Table 2 shows our results.
to test these interactions and identify bugs early to avoid
catastrophic failures during rollout. Metric Our Prototype Baseline
QPS 10000 10000
5.5 Discussion Average Number of Cores 28 78
Note that innovation in the areas discussed in this section is Median Latency (ms) 2.66 5.47
not fundamentally unique to our proposal. There has been ex- Table 2: Performance Results.
tensive research on transport protocols [63, 64], routing [44,
65], testing [45, 75], resource management [57, 67, 71], trou- Most of the performance benefits of our prototype come
bleshooting [54, 56], etc. However, the unique features of from its use of a custom serialization format designed for non-
our programming model enable new innovations and make versioned data exchange, as well as its use of a streamlined
existing innovations much easier to implement. transport protocol built directly on top of TCP. For example,
For instance, by leveraging the atomic rollouts in our pro- the serialization format used does not require any encoding
posal, we can design highly-efficient serialization protocols of field numbers or type information. This is because all
that can safely assume that all participants are using the same encoders and decoders run at the exact same version and
schema. Additionally, our programming model makes it easy agree on the set of fields and the order in which they should
to embed routing logic directly into a user’s application, be encoded and decoded in advance.
providing a range of benefits [43]. Similarly, our proposal’s For an apples-to-apples comparison to the baseline, we
ability to provide a bird’s eye view of the application allows did not co-locate any components. When we co-locate all
114
HOTOS ’23, June 22–24, 2023, Providence, RI, USA Sanjay Ghemawat, Robert Grandl, Srdjan Petrovic, Michael Whittaker et al.
eleven components into a single OS process, the number of While this paper doesn’t address the cases where the use
cores drops to 9 and the median latency drops to 0.38 ms, of multiple binaries is required, we believe that our proposal
both an order of magnitude lower than the baseline. This allows developers to write fewer binaries (i.e. by grouping
mirrors industry experience [34, 39]. multiple services into single binaries whenever possible),
achieve better performance, and postpone hard decisions
7 Related Work related to how to partition the application. We are explor-
Actor Systems. The closest solutions to our proposal are ing how to accommodate applications written in multiple
Orleans [74] and Akka [3]. These frameworks also use ab- languages and compiled into separate binaries.
stractions to decouple the application and runtime. Ray [70] 8.2 Integration with External Services
is another actor based framework but is focused on ML ap-
Applications often need to interact with external services
plications. None of these systems support atomic rollouts,
(e.g., a Postgres database [29]). Our programming model
which is a necessary component to fully address challenges
allows applications to interact with these services as any
C2-C5. Other popular actor based frameworks such as Er-
application would. Not anything and everything has to be a
lang [61], E [52], Thorn [48] and C++ Actor Framework [10]
component. However, when an external service is extensively
put the burden on the developer to deal with system and
used within and across applications, defining a correspond-
low level details regarding deployment and execution, hence
ing component might provide better code reuse.
they fail to decouple the concerns between the application
and the runtime and therefore don’t fully address C1-C5. 8.3 Distributed Systems Challenges
Distributed object frameworks like CORBA, DCOM, and Java While our programming model allows developers to focus
RMI use a programming model similar to ours but suffered on their business logic and defer a lot of the complexity of
from a number of technical and organizational issues [58] deploying their applications to a runtime, our proposal does
and don’t fully address C1-C5 either. not solve fundamental challenges of distributed systems [53,
Microservice Based Systems. Kubernetes [25] is widely 68, 76]. Application developers still need to be aware that
used for deploying container based applications in the cloud. components may fail or experience high latency.
However, its focus is orthogonal to our proposal and doesn’t
address any of C1-C5. Docker Compose [15], Acorn [1], 8.4 Programming Guidance
Helm [19], Skaffold [35], and Istio [21] abstract away some There is no official guidance on how to write distributed
microservice challenges (e.g., configuration generation). How- applications, hence it’s been a long and heated debate on
ever, challenges related to splitting an application into mi- whether writing applications as monoliths or microservices
croservices, versioned rollouts, and testing are still left to is a better choice. However, each approach comes with its
the user. Hence, they don’t satisfy C1-C5. own pros and cons. We argue that developers should write
Other Systems. There are many other solutions that make their application as a single binary using our proposal and de-
it easier for developers to write distributed applications, in- cide later whether they really need to move to a microservices-
cluding dataflow systems [51, 59, 77], ML inference serving based architecture. By postponing the decision of how ex-
systems [8, 17, 42, 50, 73], serverless solutions [11, 24, 36], actly to split into different microservices, it allows them to
databases [29, 49], and web applications [66]. More recently, write fewer and better microservices.
service meshes [46, 69] have raised networking abstractions
9 Conclusion
to factor out common communication functionality. Our pro-
posal embodies these same ideas but in a new domain of The status quo when writing distributed applications in-
general serving systems and distributed applications. In this volves splitting applications into independently deployable
context, new challenges arise (e.g., atomic rollouts). services. This architecture has a number of benefits but also
many shortcomings. In this paper, we propose a different
8 Discussion programming paradigm that sidesteps these shortcomings.
Our proposal encourages developers to (1) write monolithic
8.1 Multiple Application Binaries
applications divided into logical components, (2) defer to a
We argue that applications should be written and built as runtime the challenge of physically distributing and execut-
single binaries, but we acknowledge that this may not al- ing the modularized monoliths, and (3) deploy applications
ways be feasible. For example, the size of an application atomically. These three guiding principles unlock a number
may exceed the capabilities of a single team, or different of benefits and open the door to a bevy of future innovation.
application services may require distinct release cycles for Our prototype implementation reduced application latency
organizational reasons. In all such cases, it may be necessary by up to 15× and reduced cost by up to 9× compared to the
for the application to consist of multiple binaries. status quo.
115
Towards Modern Development of Cloud Applications HOTOS ’23, June 22–24, 2023, Providence, RI, USA
116
HOTOS ’23, June 22–24, 2023, Providence, RI, USA Sanjay Ghemawat, Robert Grandl, Srdjan Petrovic, Michael Whittaker et al.
117