Skip to content

Commit 1c851bc

Browse files
microservice review (#1776)
Please have a look at the comments I added. Thanks :)
1 parent 5fa9b59 commit 1c851bc

File tree

1 file changed

+58
-52
lines changed

1 file changed

+58
-52
lines changed

guides/deployment/microservices.md

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ A comprehensive guide on deploying your CAP application as microservices.
1313
## Create a Solution Monorepo <UnderConstruction/>
1414

1515
Assumed we want to create a composite application consisting of two or more micro services, each living in a separate GitHub repository, for example:
16-
16+
<!-- Those links aren't working links. Why do we use those? -->
1717
- https://github.com/capire/bookstore
1818
- https://github.com/capire/reviews
1919
- https://github.com/capire/orders
@@ -24,9 +24,9 @@ With some additional repos, used as dependencies in the same manner, like:
2424
- https://github.com/capire/bookshop
2525
- https://github.com/capire/data-viewer
2626

27-
This guide describes a way to manage development and deployment via *[monorepos](https://en.wikipedia.org/wiki/Monorepo)* using *[npm workspaces](https://docs.npmjs.com/cli/using-npm/workspaces)* and *[git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules)* techniques...
27+
This guide describes a way to manage development and deployment via *[monorepos](https://en.wikipedia.org/wiki/Monorepo)* using *[NPM workspaces](https://docs.npmjs.com/cli/using-npm/workspaces)* and *[git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules)* techniques...
2828

29-
1. Create a new monorepo root directory using `npm` workspaces:
29+
1. Create a new monorepo root directory using *NPM workspaces*:
3030

3131
```sh
3232
mkdir capire
@@ -47,14 +47,14 @@ This guide describes a way to manage development and deployment via *[monorepos]
4747
git submodule update --init
4848
```
4949

50-
Add a .gitignore
50+
Add a _.gitignore_ file with the following content:
5151
```txt
5252
node_modules
5353
gen
5454
```
5555
> The outcome of this looks and behaves exactly as the monorepo layout in *[cap/samples](https://github.com/sap-samples/cloud-cap-samples)*, so we can exercise the subsequent steps in there...
5656
57-
3. Test-drive locally as usual
57+
3. Test-drive locally:
5858
```sh
5959
npm install
6060
```
@@ -67,8 +67,12 @@ This guide describes a way to manage development and deployment via *[monorepos]
6767
cds w bookstore
6868
```
6969

70+
Each microservice can be started independently. If you start each microservice, one after the other in a different terminal, the connection is already established.
7071

71-
::: details Other project structures
72+
[Learn more about Automatic Bindings by `cds watch`](../extensibility/composition#bindings-via-cds-watch){.learn-more}
73+
74+
75+
::: details The project structure
7276

7377
The project structure used here is as follows:
7478

@@ -81,13 +85,13 @@ The project structure used here is as follows:
8185
└─ package.json
8286
```
8387

84-
The individual services (`bookstore`, `reviews`, `orders`) can be
88+
The individual services (`bookstore`, `reviews`, `orders`) can be one of the following:
8589
* folders, committed directly to the root project
8690
* git submodules
8791

88-
Links between the projects are established using npm dependencies.
92+
Links between the projects are established using NPM dependencies.
8993
Since the root project defines workspaces, these dependencies are also found locally without the need for publishing or linking.
90-
When one of the projects is cloned in isolation, it is still possible to fetch dependencies to other modules via the npm registry.
94+
When one of the projects is cloned in isolation, it's still possible to fetch dependencies to other modules via the NPM registry.
9195

9296
:::
9397

@@ -97,22 +101,24 @@ If you have multiple CAP applications relying on the same domain model or want t
97101

98102
In the following steps, we create an additional project to easily collect the relevant models from these projects, and act as a vehicle to deploy these models to SAP HANA in a controlled way.
99103

100-
::: details Evaluation
104+
::: details Why a shared database?
105+
106+
A shared database is beneficial if the following are important for you:
107+
108+
- **Query Performance:** Complex queries are executed much faster, for example `$expand` to an entity on another microservice, compared to calls across services with own data persistencies.
109+
- **Independent Scalability** of application runtimes, compared to a monolithic application.
101110

102-
The advantages are as follows:
103-
- **Query Performance:** Complex queries are executed much faster, for example $expand to an entity on another microservice (compared to calls across services with own data persistencies)
104-
- **Independent Scalability** of application runtimes (compared to a monolithic application)
111+
These are the (not so beneficial) side effects you when using a shared persistence:
105112

106-
Disadvantages:
107-
- Accessing data directly (without an API) means any changes in the data model affect all applications directly
108-
- every change in one of the services either requires
109-
- a redeployment of all microservices involved
110-
- a logic to decide which microservices need redeployment to avoid inconsistencies
111-
- violates 12 factors concept
113+
- Accessing data directly (without an API) means any changes in the data model affect all applications directly.
114+
- Every change in one of the services requires either one of the following:
115+
- Redeployment of all microservices involved.
116+
- Logic to decide which microservices need redeployment to avoid inconsistencies.
117+
- Violates the 12 factors concept.
112118

113119
:::
114120

115-
### Add a project for shared database
121+
### Add a Project For Shared Database
116122

117123
1. Add another `cds` project to collect the models from these projects:
118124

@@ -127,7 +133,7 @@ The advantages are as follows:
127133
npm add @capire/orders
128134
```
129135

130-
> Note how *npm workspaces* allows us to use the package names of the projects, and nicely creates symlinks in *node_modules* accordingly.
136+
> Note how *NPM workspaces* allows us to use the package names of the projects, and nicely creates symlinks in *node_modules* accordingly.
131137
132138
2. Add a `db/schema.cds` file as a mashup to actually collect the models:
133139

@@ -181,15 +187,15 @@ The project structure used here is as follows:
181187
└─ package.json
182188
```
183189

184-
The `shared-db` module is simply another CAP project, with only db content. The dependencies are installed via npm, so it is still possible to install via an npm registry if used outside of the monorepo setup.
190+
The `shared-db` module is simply another CAP project, with only db content. The dependencies are installed via NPM, so it's still possible to install via an NPM registry if used outside of the monorepo setup.
185191

186-
The db model could also be collected on root level instead of creating a separate `shared-db` module. When collecting on root level, the `cds build --ws` option can be used to collect the models of all npm workspaces.
192+
The db model could also be collected on root level instead of creating a separate `shared-db` module. When collecting on root level, the `cds build --ws` option can be used to collect the models of all NPM workspaces.
187193

188194
:::
189195

190-
### Deployment as separate mta
196+
### Deployment as Separate MTA
191197

192-
In a setup with multiple deployment units, we can add the `shared-db` project as its own mta deployment:
198+
In a setup with multiple deployment units, we can add the `shared-db` project as its own MTA deployment:
193199

194200
```sh
195201
cds add mta
@@ -260,11 +266,11 @@ resources:
260266
261267
262268
263-
#### Binding to shared database
269+
#### Binding to a Shared Database
264270
265271
The only thing left to care about is to ensure all 3+1 projects are bound and connected to the same database at deployment, subscription, and runtime.
266272
267-
Configure the mta.yaml of the other apps to bind to the existing shared database, for example, in the reviews module:
273+
Configure the _mta.yaml_ of the other apps to bind to the existing shared database, for example, in the reviews module:
268274
269275
```yaml [reviews/mta.yaml]
270276
...
@@ -295,15 +301,15 @@ resources:
295301
#### Subsequent updates
296302
297303
- TODO...
298-
- Whenever one of the projects has changes affecting the database, that triggers a new deployment of the `shared-db` project
304+
- Whenever one of the projects has changes affecting the database that triggers a new deployment of the `shared-db` project
299305
- `git submodules` gives you control of which versions to pull, for example by `git branches` or `git tags`
300306
- Ensure to first deploy `shared-db` before deploying the others
301307

302308

303309

304310
## All-in-one Deployment
305311

306-
Here we go on with our guide how to deploy all 3+1 projects at once with a common `mta.yaml`
312+
This section is about how to deploy all 3+1 projects at once with a common _mta.yaml_.
307313

308314
![component diagram with synchronous and event communication for orders](./assets/microservices/bookstore.excalidraw.svg)
309315

@@ -359,18 +365,18 @@ build-parameters:
359365

360366

361367
::: info `cds build --ws`
362-
If the CDS models of every npm workspace contained in the monorepo should be considered, then instead of creating this `shared-db` folder, you can also use:
368+
If the CDS models of every NPM workspace contained in the monorepo should be considered, then instead of creating this `shared-db` folder, you can also use:
363369
```shell
364370
cds build --for hana --production --ws
365371
```
366-
The `--ws` aggregates all models in the npm workspaces.
372+
The `--ws` aggregates all models in the NPM workspaces.
367373

368374
In this walkthrough, we only include a subset of the CDS models in the deployment.
369375
:::
370376

371377

372378
::: details Configure each app for cloud readiness
373-
The preceding steps added configuration only to the workspace root.
379+
The preceding steps only added configuration to the workspace root.
374380

375381
Additionally add database configuration to each module that we want to deploy - bookstore, orders, and reviews:
376382

@@ -384,7 +390,7 @@ npm i @cap-js/hana --workspace reviews
384390

385391
### Applications
386392

387-
Replace the mta module for samples-srv with versions for each CAP service and adjust `name`, `path`, and `provides[0].name` to match the module name. Also change the `npm-ci` builder to the `npm` builder.
393+
Replace the MTA module for `samples-srv` with versions for each CAP service and adjust `name`, `path`, and `provides[0].name` to match the module name. Also change the `npm-ci` builder to the `npm` builder.
388394

389395
::: code-group
390396
```yaml [mta.yaml]
@@ -500,7 +506,7 @@ Add the admin role
500506
:::
501507

502508
::: details Configure each app for cloud readiness
503-
Add npm dependency `@sap/xssec`:
509+
Add NPM dependency `@sap/xssec`:
504510

505511
```shell
506512
npm i @sap/xssec --workspace bookstore
@@ -713,7 +719,7 @@ modules:
713719

714720
#### Static Content
715721

716-
The approuter can serve static content. Since our UIs are located in different npm workspaces, we create symbolic links to them as an easy way to deploy them as part of the approuter.
722+
The approuter can serve static content. Since our UIs are located in different NPM workspaces, we create symbolic links to them as an easy way to deploy them as part of the approuter.
717723

718724
```shell
719725
mkdir .deploy/app-router/resources
@@ -768,7 +774,7 @@ modules:
768774
```
769775
:::
770776

771-
The xs-app.json file describes how to forward incoming request to the API endpoint / OData services and is located in the app/router folder. Each exposed CAP Service endpoint needs to be directed to the corresponding application which is providing this CAP service.
777+
The _xs-app.json_ file describes how to forward incoming request to the API endpoint / OData services and is located in the app/router folder. Each exposed CAP Service endpoint needs to be directed to the corresponding application which is providing this CAP service.
772778

773779
::: code-group
774780
```json [.deploy/app-router/xs-app.json]
@@ -854,7 +860,7 @@ Additionally, the welcomeFile is important for deployed Vue UIs as they obtain C
854860

855861
### Deploy
856862

857-
In order to build, deploy, and undeploy easily, add these `npm` scripts:
863+
To build, deploy, and undeploy easily, add these `npm` scripts:
858864

859865
::: code-group
860866
```json [package.json]
@@ -868,13 +874,13 @@ In order to build, deploy, and undeploy easily, add these `npm` scripts:
868874

869875
Before deploying you need to log in to Cloud Foundry.
870876

871-
To locally build the apps, run
877+
Build the apps locally:
872878

873879
```shell
874880
npm run build
875881
```
876882

877-
To deploy the built artifacts to Cloud Foundry, run
883+
Deploy the built artifacts to Cloud Foundry:
878884

879885
```shell
880886
npm run deploy
@@ -923,26 +929,26 @@ While these benefits exist, they are accompanied by complexity and performance l
923929

924930
Instead of just choosing between a monolith and microservices, these aspects can be combined into an architecture that fits the specific product.
925931

926-
Since each cut not only has benefits, but also drawbacks, it is important to choose which benefits actually help the overall product and which drawbacks can be accepted.
932+
Since each cut not only has benefits, but also drawbacks, it's important to choose which benefits actually help the overall product and which drawbacks can be accepted.
927933

928934
![Multiple deployment units - one contains the UIs, one contains shared service instances, one contains a shared db, two each contain an app connected to the shared db, one contains a db and an app, which is also connected to the shared db](./assets/microservices/complex.excalidraw.svg)
929935

930936
### A Late Cut
931937

932-
When developing a product it may initially not be apparent where the boundaries are.
938+
When developing a product, it may initially not be apparent where the boundaries are.
933939

934940
Keeping this in mind, an app can be developed as a modular application with use case specific CAP services.
935941
It can first be deployed as a [monolith / modulith](#monolith-or-microservice). Once the boundaries are clear, it can then be split into multiple applications.
936942

937943
Generally, the semantic separation and structure can be enforced using modules. The deployment configuration is then an independent step on top. In this way, the same application can be deployed as a monolith, as microservices with shared db, as true microservices, or a combination of these, just via configuration change.
938944

939-
![Modules which can be arranged in different deploy configurations, e.g. as a monolith (bookshop, reviews, orders), as two apps (bookshop, orders in one, reviews in the other), etc.](./assets/microservices/late-cut.excalidraw.svg)
945+
![Modules which can be arranged in different deploy configurations, for example, as a monolith (bookshop, reviews, orders), as two apps (bookshop, orders in one, reviews in the other), and so on.](./assets/microservices/late-cut.excalidraw.svg)
940946

941947
### Best Practices
942948

943949
* Prefer a late cut
944950
* Stay flexible in where to cut
945-
* Prefer staying loosely coupled → e.g. ReviewsService → reviewed events → UPDATE avg ratings
951+
* Prefer staying loosely coupled → for example, ReviewsService → reviewed events → UPDATE avg ratings
946952
* Leverage db-level integration selectively → Prefer referring to (public) service entities, not (private) db entities
947953

948954
## Appendix
@@ -956,14 +962,14 @@ A monolith is a single deployment unit with a single application. This is very c
956962
A modulith, even though the app is separated into multiple CAP services inside multiple modules, can still be deployed as a single monolithic application.
957963
This combines the benefit of a clear structure and distributed development while keeping a simple deployment.
958964

959-
![A single app containing the modules bookshop, reviews and orders](./assets/microservices/modulith.excalidraw.svg)
965+
![A single app containing the modules bookshop, reviews, and orders](./assets/microservices/modulith.excalidraw.svg)
960966

961967
True microservices each consist of their own deployment unit with their own application and their own database.
962-
Meaning that they are truly independent of each other. And it works well if they actually are independent.
968+
Meaning that they're truly independent of each other. And it works well if they are actually independent.
963969

964970
![A simplified microservices view - three deployment units, each with one app and one database](./assets/microservices/true-microservices.excalidraw.svg)
965971

966-
The above is a simplified view. In an actual microservice deployment, there are typically shared service instances and wiring needs to be provided so that apps can talk to each other, directly or via events.
972+
What was mentioned earlier is a simplified view. In an actual microservice deployment, there are typically shared service instances and wiring needs to be provided so that apps can talk to each other, directly or via events.
967973
If the microservices are not cut well, the communication overhead leads to high performance losses and often the need for data replication or caching.
968974

969975
![A more complete microservices view - two deployment units with one app, one db and some UIs each, one deployment unit for shared service instances](./assets/microservices/true-microservices-full.excalidraw.svg)
@@ -983,7 +989,7 @@ Benefits:
983989
Requirement:
984990
- The app needs to be stateless, state needs to be persisted
985991

986-
Multiple app instances can be used both for monoliths and microservices.
992+
Multiple app instances can be used for both monoliths and microservices.
987993

988994
![A single app with multiple application instances](./assets/microservices/app-instances.excalidraw.svg)
989995

@@ -1027,7 +1033,7 @@ For some parts, a 100% cpu utilization over an extended period is accepted for e
10271033

10281034
#### Fault Tolerance
10291035

1030-
While app instances already provide some resilience, there are failure classes (e.g. bugs) which affect each app instance.
1036+
While app instances already provide some resilience, there are failure classes (for example, bugs) which affect each app instance.
10311037

10321038
Separating functionality into different apps means that when one app experiences issues, the functionality of the other apps is still available.
10331039
In the bookstore example, while reviews may be down, orders may still be possible.
@@ -1038,7 +1044,7 @@ This benefit is null for apps with synchronous dependencies on each other. If A
10381044

10391045
With multiple apps, you can still deploy them together as one unit, for example as part of a multitarget application archive.
10401046
Once an application grows bigger, this takes a significant amount of time.
1041-
Deployments can then be split up either by type (e.g. deploying UIs separately) or horizontally (e.g. deploying each app via its own deployment unit).
1047+
Deployments can then be split up either by type (for example, deploying UIs separately) or horizontally (for example, deploying each app via its own deployment unit).
10421048

10431049
Benefits:
10441050
- Faster individual deploy times
@@ -1048,7 +1054,7 @@ Drawbacks:
10481054
- Coordination between deployment units for updates with dependencies
10491055
- Configuration wiring to connect systems across deployment units
10501056

1051-
![One deployment unit for UIs and one deployment unit for apps, db etc.](./assets/microservices/multiple-deployment-units.excalidraw.svg)
1057+
![One deployment unit for UIs and one deployment unit for apps, db and so on.](./assets/microservices/multiple-deployment-units.excalidraw.svg)
10521058

10531059

10541060
With a single deployment unit, when a fix for one part needs to be deployed, the risk of redeploying the rest of the application needs to be considered.
@@ -1067,7 +1073,7 @@ Here we need to differentiate between two scenarios:
10671073
- Using multiple databases of the same type
10681074

10691075
A polyglot persistence can be used when the app has different requirements for the types of data it needs to store.
1070-
For example, there may be a large amount of large files that can be stored in a document store, while corresponding administrative data is stored in a relational database.
1076+
For example, there may be a large number of large files that can be stored in a document store, while corresponding administrative data is stored in a relational database.
10711077

10721078
Benefits:
10731079
- Use suitable technology for different use cases
@@ -1093,7 +1099,7 @@ Drawbacks:
10931099

10941100
When data is distributed across multiple databases, strategies may be necessary to combine data from multiple sources.
10951101

1096-
- Fetching on-demand
1102+
- Fetching on demand
10971103
- Caching
10981104
- HANA synonyms
10991105
- Data Replication

0 commit comments

Comments
 (0)