DrillLab
第 15 / 17 节LESSON 15 / 17约 22 分钟~22 min

两道书面题:延迟传播与生产配置The two written questions: how delay spreads, and production configuration

写代码的题有测试兜底,这两道题只有你自己。给你一套可复用的答题结构。The coding tasks have tests to fall back on. These two questions have only you. Here is an answer structure you can reuse.

3 个练习3 exercisesFederation · 第 5 部分Federation · Part 5
这一页有什么On this page9
学完这节你会After this lesson you can
  • 解释联邦图里某个 subgraph 高延迟为什么会拖慢整体Explain why one slow subgraph in a federated graph slows the whole request down
  • 说出至少一种缓存策略,并说清它的失效策略和代价Name at least one caching strategy, and state how it is invalidated and what it costs
  • 从一段 application.properties 里指出三个以上生产隐患Point out three or more production risks in a block of application.properties
  • 掌握一个「风险 → 后果 → 修正 → 理由」的答题结构Learn one answer structure: risk, then consequence, then fix, then reason
这在考试里考什么What the exam does with this

这两道题占的分不小,而且完全没有测试。很多人在这里写两句话就交了 —— 而它恰恰是最容易通过「结构化表达」拿分的地方。These two questions are worth real points, and no test checks them. Many people write two sentences and submit. This is the easiest place in the exam to earn points just by organising what you say.

这节课要看的真实文件Real files this lesson looks at高亮行 = 需要你动手改的文件Highlighted rows are the files you edit
graphql-federation-practice/QUESTIONS.md两道题的原文The two questions as written

提醒:源项目在磁盘上是做完的版本 —— 下面就是答案。想自己先写一遍的话,现在关上。Heads up: on disk this project is the finished version — what follows is the answer. Close this if you want to write it yourself first.

TextQUESTIONS.md源项目From source
1# Written Questions
2
3## Question 1: Apollo Federation Architecture
4
5**Question:** Given a scenario where the User subgraph is experiencing high latency (500ms+ response times), explain how this impacts dependent subgraphs in a federated graph and describe one caching strategy to mitigate the performance impact.
6
7**Answer:**
8
9[Write answer here]
10
11## Question 2: Spring Boot Production Deployment
12
13Review the following Spring Boot `application.properties` snippet for a microservice being deployed to AWS EKS:
14
15```properties
16server.port=8080
17server.address=0.0.0.0
18spring.datasource.url=jdbc:postgresql://${DB_HOST}:5432/orders
19spring.datasource.username=${DB_USER}
20spring.datasource.password=${DB_PASSWORD}
21management.endpoints.web.exposure.include=*
22```
23
24Identify at least three production concerns or security issues. For each issue, explain the risk and provide corrected configuration with justification.
25
26**Answer:**
27
28[Write answer here]
Source: graphql-federation-practice/QUESTIONS.md
graphql-federation-practice/java-service/src/main/resources/application.properties项目里真实的配置(和题面给的片段不完全一样)The real configuration in the project, which is not quite the snippet in the question
Propertiesapplication.properties源项目From source
1server.port=8080
2server.address=0.0.0.0
3management.endpoints.web.exposure.include=*
Source: graphql-federation-practice/java-service/src/main/resources/application.properties
§01

先说答题结构Start with the answer structure

这两道题都能套同一个模板。The same template fits both questions.

书面题的评分点通常是「有没有覆盖到关键面」, 而不是文采。所以用固定结构写,最不容易漏:

写什么
结论先行一句话给出核心判断,别铺垫
机制为什么会这样 —— 讲清因果链,不只是现象
方案具体做什么,最好带上配置或代码
代价与边界这个方案的代价是什么、什么时候不适用 —— 这一段最能区分水平

最后那一段是关键。只说方案的人像是背过; 能说出代价的人像是用过。

Written questions are usually scored on whether you covered the key angles, not on prose. So write to a fixed structure and you are least likely to miss one:

SectionWhat goes in it
Verdict firstOne sentence with the core judgement. No warm-up.
MechanismWhy it happens — spell out the causal chain, not just the symptom
FixExactly what to do, ideally with config or code
Cost and limitsWhat the fix costs, when it does not apply — this section separates the levels

That last section is the one that counts. Someone who only lists the fix sounds memorised; someone who can name the cost sounds like they have shipped it.

§02

第 1 题 · 题面与要点拆解Question 1 · the text, broken into the points it asks for

原文:

题目要求两件事:① 解释影响(对依赖它的 subgraph)、② 给一种缓存策略缓解性能问题。

注意题面用的词是 dependent subgraphs。 这里有个需要说清的细节:subgraph 之间通常并不直接互相调用—— 它们都由 Router 编排。所以「影响」的准确传导路径是:

能把这条路径说清楚,这道题就答对了一半。

The original text:

The question asks for two things: ① explain the impact on the subgraphs that depend on it, and ② give one caching strategy to take the edge off the performance hit.

Note the wording: dependent subgraphs. There is a detail worth spelling out here — subgraphs normally do not call each other directly. The Router orchestrates all of them. So the accurate path the impact travels is:

Explain that path clearly and you are already halfway to a full answer.

TextQUESTIONS.md(第 1 题原文)QUESTIONS.md (the original text of question 1)源项目From source
1## Question 1: Apollo Federation Architecture
2
3Given a scenario where the User subgraph is experiencing high latency
4(500ms+ response times), explain how this impacts dependent subgraphs
5in a federated graph and describe one caching strategy to mitigate the
6performance impact.
Source: graphql-federation-practice/QUESTIONS.md
Text影响的传导路径How the effect propagates已跑通Verified
1User subgraph 慢(500ms+)
2
3Router 的查询计划里,「取 User 的 @key 字段」这一步是前置依赖
4
5Router 必须先拿到 { __typename: "User", id } 才能去问 Orders subgraph
6 ↓ 所以这两步是串行的,不能并行
7Orders subgraph 即使自己只要 10ms,也要等到 500ms 之后才被调用
8
9客户端看到的总延迟 ≈ 500 + 10 + Router 开销
10
11更糟的连锁:Router 的连接池 / 线程被长时间占用
12 ↓ 一个慢 subgraph 拖住整个 Router 的吞吐
13所有查询(哪怕完全不碰 User)都开始变慢
1User subgraph is slow (500ms+)
2
3In the Router query plan, fetching User's @key fields is a prerequisite
4
5The Router needs { __typename: "User", id } before it can ask Orders
6 ↓ so the two steps are serial, they cannot run in parallel
7Orders subgraph needs only 10ms itself, but waits until the 500ms is up
8
9Total latency the client sees ≈ 500 + 10 + Router overhead
10
11Worse knock-on effect: Router connection pool / threads held a long time
12 ↓ one slow subgraph holds back the throughput of the whole Router
13Every query slows down, even the ones that never touch User
§03

第 1 题 · 一份可以照着写的答案Question 1 · an answer you can follow

这是 DrillLab 写的参考答案,不是官方标准答案。This is a reference answer written by DrillLab, not an official one.

下面这份按「结论 → 机制 → 方案 → 代价」写。标为 DrillLab 自出—— 原项目的 QUESTIONS.md 里答案区是空的 ([Write answer here]), 没有官方答案可对照。

The answer below follows verdict → mechanism → fix → cost. It is marked as written by DrillLab: the answer area in the original QUESTIONS.md is empty ([Write answer here]), so there is no official answer to compare against.

Text第 1 题参考答案(DrillLab 自出)Reference answer to question 1 (written by DrillLab)示意Illustrative
1**结论**
2
3User subgraph 的高延迟不会「只影响 User 字段」。因为 Router 的查询计划里,
4取 User 的 @key 字段是解析其他 subgraph 上 User 扩展字段(如 Orders 的
5User.orders)的前置步骤,这两步必须串行。因此任何涉及 User 的查询,
6其尾延迟都会被抬到 500ms 以上;更严重的是 Router 侧的连接与线程被长时间
7占用,会波及完全不碰 User 的查询。
8
9**机制**
10
111. 查询计划分阶段。Router 先向 Accounts subgraph 请求 User 及其 @key
12 字段(id),拿到 entity representation 后,才能向 Orders subgraph 发
13 _entities(representations: [{ __typename: "User", id }]) 请求。
14 后者依赖前者的输出,无法并行。
152. 串行相加。总延迟 ≈ Accounts(500ms) + Orders(10ms) + Router 编排开销。
16 Orders 自身再快也无法改善。
173. 资源放大。Router 到 Accounts 的连接在 500ms 内一直占用。QPS 上升时,
18 按 Little's Law(并发数 ≈ 到达率 × 停留时间),所需并发是原来的数十倍。
19 连接池耗尽后,排队开始,其他 subgraph 的请求也被拖慢 —— 一个慢服务
20 放大成全图退化。
214. 超时与部分失败。如果 Router 配了 subgraph 超时,500ms 会触发超时,
22 User 相关字段变成 null 并带 errors,客户端拿到部分数据。
23
24**缓解方案:在 Router 层做 entity 缓存**
25
26对 User 这类「变化不频繁、被大量引用」的 entity,在 Router 与 Accounts
27之间加一层按 entity key 分片的缓存(Apollo Router 的 entity caching,
28后端用 Redis):
29
30- 缓存键:subgraph 名 + __typename + @key 字段值 + 请求的字段集合。
31 例如 accounts:User:id=123:{name,email}。
32- 命中时跳过对 Accounts 的网络调用,串行的第一段从 500ms 降到 ~1ms。
33- TTL 按数据容忍度设定。用户资料这类数据 60–300s 是合理起点。
34- 主动失效:Accounts 在用户资料变更时向缓存发删除指令(write-through
35 或 event-driven invalidation),避免只依赖 TTL 造成的陈旧窗口。
36- 配合 stale-while-revalidate:过期后先返回旧值、后台异步刷新,
37 把「缓存过期」这一刻的延迟尖刺也削掉。
38
39**代价与边界**
40
41- 一致性变弱。TTL 内会读到旧数据。所以只适合能容忍秒级陈旧的字段;
42 余额、权限、库存这类不能这么做。
43- 缓存键必须包含字段集合,否则不同查询会互相污染。
44- 必须按调用者身份分片,否则会跨用户泄漏(这是安全问题,不只是正确性)。
45- 缓存治标不治本。命中率不会是 100%,冷启动和长尾 key 仍然吃 500ms。
46 真正的修复是查 Accounts 慢在哪(N+1、缺索引、下游依赖),
47 缓存只是买时间。
48- 其他值得同时做的:给 subgraph 请求设超时和熔断,避免慢服务拖垮 Router;
49 用 APQ(automatic persisted queries)减小请求体;
50 对高频组合查询考虑在 Router 前加响应级缓存。
1**Conclusion**
2
3High latency in the User subgraph does not stay inside the User fields. In
4the Router query plan, fetching User's @key fields must finish before User
5extension fields on other subgraphs (Orders' User.orders) can be resolved,
6so the two steps run in sequence. Any query touching User then has a tail
7latency above 500ms, and busy Router connections slow unrelated queries too.
8
9**Mechanism**
10
111. The query plan runs in stages. The Router first asks the Accounts subgraph
12 for User and its @key field (id). Only with that entity representation can
13 it call Orders with _entities(representations: [{ __typename: "User", id }]).
14 The second call needs the first call's output, so they cannot overlap.
152. The times add up. Total ≈ Accounts(500ms) + Orders(10ms) + Router overhead.
16 Making Orders faster on its own changes nothing.
173. Resource amplification. Each Router-to-Accounts connection is held for the
18 full 500ms. As QPS rises, Little's Law (concurrency ≈ arrival rate × time
19 in system) puts the needed concurrency dozens of times higher. Once the
20 pool is empty requests queue, and every other subgraph slows down too.
214. Timeouts and partial failure. If the Router sets a subgraph timeout, 500ms
22 trips it: User fields return null with errors and the client sees partial data.
23
24**Mitigation: entity caching at the Router layer**
25
26For an entity like User, which changes rarely and is referenced everywhere,
27put a cache keyed by entity key between the Router and Accounts (Apollo
28Router entity caching, with Redis behind it):
29
30- Cache key: subgraph name + __typename + @key value + the requested fields.
31 Example: accounts:User:id=123:{name,email}.
32- A hit skips the call to Accounts; the first serial step drops to about 1ms.
33- Set the TTL by how stale the data may be; 60–300s suits user profiles.
34- Active invalidation: Accounts tells the cache to delete when a profile
35 changes (write-through or event-driven), instead of waiting for the TTL.
36- Add stale-while-revalidate: return the old value, then refresh in the
37 background. That removes the latency spike at the moment of expiry.
38
39**Costs and limits**
40
41- Consistency gets weaker. Inside the TTL you read old data, so this only
42 fits fields that tolerate seconds of staleness, not balance or permissions.
43- The cache key must include the field set, or different queries pollute it.
44- Shard by caller identity, or data leaks across users. That is security,
45 not only correctness.
46- A cache treats the symptom. The hit rate is never 100%; cold starts and
47 long-tail keys still cost 500ms. The real fix is finding why Accounts is
48 slow (N+1, missing index, slow dependency). The cache only buys time.
49- Also worth doing: timeouts and a circuit breaker on subgraph requests, APQ
50 (automatic persisted queries) to shrink bodies, a response cache in front.
§04

第 2 题 · 题面与那段配置Question 2 · the text and the configuration block

题目给了一段部署到 AWS EKS 的application.properties, 要求指出至少三个生产/安全问题, 每个都说明风险并给出修正配置与理由。

注意题面给的片段和项目里真实的文件不一样。项目里那个只有三行:

题面给的片段多了数据源和口令占位符。答题时以题面为准。但注意项目真实文件里那行management.endpoints.web.exposure.include=*是两边都有的 —— 这是最明显的问题。

The question hands you an application.properties destined for AWS EKS and asks you to name at least three production or security problems, each with the risk, a corrected config, and the reasoning.

Careful: the snippet in the question is not the same as the real file in the project. The real one is three lines long:

The snippet in the question adds a datasource and password placeholders. Answer against the question, not the repo. But notice that the line management.endpoints.web.exposure.include=* appears in both — that is the most obvious problem of the lot.

PropertiesQUESTIONS.md 里给的片段The snippet given in QUESTIONS.md源项目From source
1server.port=8080
2server.address=0.0.0.0
3spring.datasource.url=jdbc:postgresql://${DB_HOST}:5432/orders
4spring.datasource.username=${DB_USER}
5spring.datasource.password=${DB_PASSWORD}
6management.endpoints.web.exposure.include=*
Source: graphql-federation-practice/QUESTIONS.md
Properties项目里真实的 application.properties(全文)The real application.properties in the project (full file)源项目From source
1server.port=8080
2server.address=0.0.0.0
3management.endpoints.web.exposure.include=*
Source: graphql-federation-practice/java-service/src/main/resources/application.properties
只有三行,没有数据源配置 —— 因为这个项目用的是内存仓库。这也再次印证 orders.db 是干扰项。Only three lines, and no data-source configuration, because this project uses an in-memory repository. That is one more confirmation that orders.db is a distractor.
§05

第 2 题 · 找问题的清单Question 2 · a checklist for finding the problems

按这几个面扫一遍,三个问题很容易凑够,而且不会漏掉重要的。Scan these areas in turn. Three problems are easy to reach, and you will not miss the important ones.

  1. 暴露面。哪些端点被公开了? actuator 全开是最典型的问题。
  2. 凭据管理。口令从哪来? 环境变量算及格,但不算好。
  3. 传输安全。有 TLS 吗? 数据库连接加密了吗?
  4. 资源与韧性。连接池、超时、重试、 优雅停机 —— 一个都没配。
  5. 可观测性。健康检查分不分 liveness / readiness? 日志格式适合采集吗?
  6. 配置管理本身。所有环境共用一个 properties 文件? 没有 profile 隔离?

题目只要三个,但列五六个更好—— 只要每个都写清「风险 → 修正 → 理由」, 不会因为写多而扣分。

  1. Exposure. Which endpoints are public? Actuator wide open is the classic one.
  2. Credentials. Where does the password come from? An environment variable is a pass, not a good grade.
  3. Transport security. Is there TLS? Is the database connection encrypted?
  4. Resources and resilience. Connection pool, timeouts, retries, graceful shutdown — not one of them is configured.
  5. Observability. Does the health check split liveness from readiness? Is the log format fit for collection?
  6. Config management itself. One properties file for every environment? No profile separation?

The question asks for three, but five or six is better — as long as each one spells out risk → fix → reasoning, nobody deducts points for writing more.

§06

第 2 题 · 一份可以照着写的答案Question 2 · an answer you can follow

同样按结构写,每个问题一小节。 下面列了六个,前三个是最该写的。

Same structure again, one short section per problem. Six are listed below; the first three are the ones you really must write.

Text第 2 题参考答案(DrillLab 自出)Reference answer to question 2 (written by DrillLab)示意Illustrative
1### 问题 1(最严重):actuator 端点全量暴露
2
3management.endpoints.web.exposure.include=*
4
5**风险**:这一行把所有 actuator 端点开在业务端口上,包括
6- /actuator/env —— 打印全部环境变量,DB_PASSWORD 直接泄漏
7- /actuator/heapdump —— 可下载堆转储,内存里的凭据和用户数据全在里面
8- /actuator/configprops、/actuator/beans —— 暴露完整内部结构
9- /actuator/loggers —— 可写,攻击者能改日志级别(掩盖痕迹或打爆磁盘)
10在 EKS 里如果这个 Service 挂了 Ingress,等于把这些开到公网。
11
12**修正**
13management.endpoints.web.exposure.include=health,info,prometheus
14management.endpoint.health.show-details=never
15management.endpoint.health.probes.enabled=true
16management.server.port=8081
17management.endpoints.web.base-path=/internal
18
19**理由**:白名单代替通配符(默认拒绝);管理端点搬到独立端口 8081,
20Ingress 只暴露 8080,运维流量走集群内部;health 不显示细节,
21避免泄漏下游拓扑;probes.enabled 分出 liveness/readiness 供 k8s 探针用。
22
23
24### 问题 2:数据库口令的管理方式
25
26spring.datasource.password=${DB_PASSWORD}
27
28**风险**:占位符本身没错,但它把问题推给了「谁来设这个环境变量」。
29在 EKS 里常见做法是 ConfigMap 或 Deployment 的 env —— 而这两者
30kubectl describe 就能看到明文,会进 etcd(默认不加密)、
31会被 CI 日志打出来、会随 Deployment yaml 进版本库。
32而且环境变量对同 Pod 内所有进程和 /proc/PID/environ 可见。
33
34**修正**
35- 用 AWS Secrets Manager + External Secrets Operator,或
36 Secrets Store CSI Driver,把口令以文件形式挂进容器,
37 用 spring.config.import=optional:file:/mnt/secrets/ 读取
38- 打开 RDS IAM 认证,用短期 token 替代静态口令(最优)
39- 开启自动轮换,配合 HikariCP 的 max-lifetime 让连接自然更新
40- 给 Pod 配最小权限的 IRSA 角色
41
42**理由**:静态长期口令是最难治的一类风险 —— 一旦泄漏无法追溯、
43轮换成本高。挂载文件优于环境变量(不进 /proc/environ、不被子进程继承);
44IAM 认证彻底消除静态凭据。
45
46
47### 问题 3:没有 TLS,数据库连接也未加密
48
49**风险**:server.port=8080 是纯 HTTP;JDBC URL 没有 sslmode 参数。
50即使在 VPC 内,明文流量也违反多数合规要求(PCI-DSS、HIPAA),
51且无法防御同 VPC 内的横向嗅探。
52
53**修正**
54spring.datasource.url=jdbc:postgresql://${DB_HOST}:5432/orders?sslmode=verify-full&sslrootcert=/etc/ssl/certs/rds-ca.pem
55server.forward-headers-strategy=framework
56
57**理由**:应用侧 TLS 通常在 Ingress 或 service mesh(mTLS)终止,
58所以 8080 保持 HTTP 是可接受的架构选择 —— 但必须显式说明前面有
59TLS 终止层,并配 forward-headers-strategy 让应用正确识别原始协议
60(否则重定向会掉回 http)。数据库侧 sslmode=verify-full 强制加密并校验
61证书,防中间人。
62
63
64### 问题 4:连接池、超时、重试全部缺失
65
66**风险**:用默认值上生产等于没有容量规划。下游变慢时连接池耗尽,
67线程全部阻塞在等连接,健康检查也超时,k8s 反复重启 Pod —— 雪崩。
68
69**修正**
70spring.datasource.hikari.maximum-pool-size=10
71spring.datasource.hikari.minimum-idle=2
72spring.datasource.hikari.connection-timeout=3000
73spring.datasource.hikari.max-lifetime=1800000
74spring.datasource.hikari.validation-timeout=1000
75spring.mvc.async.request-timeout=5000
76
77**理由**:池大小要按「DB 最大连接数 ÷ 副本数」倒推,不是越大越好;
78connection-timeout 短一点,让请求快速失败而不是排队等死
79(fail fast 比 fail slow 好);max-lifetime 小于数据库侧的
80idle timeout,避免用到已被服务端关闭的连接。
81
82
83### 问题 5:没有优雅停机
84
85**风险**:EKS 滚动更新时 Pod 收到 SIGTERM 就立刻断开,
86正在处理的请求被截断,客户端看到 502。
87
88**修正**
89server.shutdown=graceful
90spring.lifecycle.timeout-per-shutdown-phase=20s
91
92**理由**:graceful 让容器停止接收新请求但把在途请求处理完。
93超时值要小于 k8s 的 terminationGracePeriodSeconds(默认 30s),
94否则会被 SIGKILL 打断。
95
96
97### 问题 6:单份配置、无环境隔离
98
99**风险**:同一个 properties 文件用于 dev/staging/prod,
100改一处影响所有环境;本地调试用的宽松设置会带到生产。
101
102**修正**:拆成 application.yml(公共)+ application-prod.yml,
103用 SPRING_PROFILES_ACTIVE=prod 激活;敏感项一律走外部 Secret,
104不进镜像。CI 里加一步「生产 profile 配置校验」。
105
106**理由**:配置是部署产物的一部分,需要和代码一样做审查与分环境管理。
1### Problem 1 (the most serious): every actuator endpoint is exposed
2
3management.endpoints.web.exposure.include=*
4
5**Risk**: this line opens every actuator endpoint on the business port:
6- /actuator/env — prints all environment variables, so DB_PASSWORD leaks
7- /actuator/heapdump — a downloadable heap dump holding credentials and data
8- /actuator/configprops, /actuator/beans — expose the internal structure
9- /actuator/loggers — writable, so an attacker can hide traces or fill the disk
10In EKS, if this Service sits behind an Ingress, all of that faces the internet.
11
12**Fix**
13management.endpoints.web.exposure.include=health,info,prometheus
14management.endpoint.health.show-details=never
15management.endpoint.health.probes.enabled=true
16management.server.port=8081
17management.endpoints.web.base-path=/internal
18
19**Why**: an allowlist replaces the wildcard (deny by default). Management moves
20to its own port 8081, so Ingress exposes only 8080 and ops traffic stays inside
21the cluster. health hides details; probes.enabled gives k8s its two probes.
22
23
24### Problem 2: how the database password is managed
25
26spring.datasource.password=${DB_PASSWORD}
27
28**Risk**: the placeholder itself is fine, but it moves the question to who sets
29that environment variable. In EKS that is usually a ConfigMap or the env block
30of a Deployment, and both show the value in plain text under kubectl describe,
31land in etcd (not encrypted by default), reach CI logs, and enter version
32control with the yaml. Env vars are also visible via /proc/PID/environ.
33
34**Fix**
35- Use AWS Secrets Manager with External Secrets Operator, or the
36 Secrets Store CSI Driver, to mount the password into the container as a file,
37 and read it with spring.config.import=optional:file:/mnt/secrets/
38- Turn on RDS IAM auth and use short-lived tokens instead of a static password
39- Enable automatic rotation; HikariCP max-lifetime then renews connections
40- Give the Pod an IRSA role with least privilege
41
42**Why**: a long-lived static password is the hardest risk to handle: once it
43leaks you cannot trace it, and rotation is expensive. A mounted file beats an
44env var (not in /proc/environ, not inherited). IAM auth removes the secret.
45
46
47### Problem 3: no TLS, and the database connection is not encrypted either
48
49**Risk**: server.port=8080 is plain HTTP, and the JDBC URL has no sslmode.
50Even inside a VPC, plaintext traffic breaks most compliance rules (PCI-DSS,
51HIPAA) and does not stop sniffing from elsewhere in the same VPC.
52
53**Fix**
54spring.datasource.url=jdbc:postgresql://${DB_HOST}:5432/orders?sslmode=verify-full&sslrootcert=/etc/ssl/certs/rds-ca.pem
55server.forward-headers-strategy=framework
56
57**Why**: application TLS usually terminates at the Ingress or in a service mesh
58(mTLS), so leaving 8080 on HTTP is an acceptable choice — but you must say that
59a TLS termination layer sits in front, and set forward-headers-strategy so the
60app reads the original protocol (otherwise redirects fall back to http). On the
61database side sslmode=verify-full forces encryption and checks the certificate.
62
63
64### Problem 4: no connection pool settings, no timeouts, no retries
65
66**Risk**: defaults in production mean no capacity planning. A slow dependency
67empties the pool, blocks threads, times out health checks, and k8s restarts.
68
69**Fix**
70spring.datasource.hikari.maximum-pool-size=10
71spring.datasource.hikari.minimum-idle=2
72spring.datasource.hikari.connection-timeout=3000
73spring.datasource.hikari.max-lifetime=1800000
74spring.datasource.hikari.validation-timeout=1000
75spring.mvc.async.request-timeout=5000
76
77**Why**: derive the pool size from DB max connections ÷ replica count; bigger
78is not better. A short connection-timeout makes a request fail quickly instead
79of queueing forever. Keep max-lifetime below the database idle timeout so you
80never hand out a connection the server has already closed.
81
82
83### Problem 5: no graceful shutdown
84
85**Risk**: during an EKS rolling update the Pod drops connections the moment it
86gets SIGTERM; in-flight requests are cut off and clients see 502.
87
88**Fix**
89server.shutdown=graceful
90spring.lifecycle.timeout-per-shutdown-phase=20s
91
92**Why**: graceful stops accepting new requests but finishes the in-flight ones.
93The timeout must be shorter than the k8s terminationGracePeriodSeconds (30s by
94default), or SIGKILL interrupts the shutdown.
95
96
97### Problem 6: one config file, no separation between environments
98
99**Risk**: the same properties file serves dev/staging/prod, so one edit hits
100every environment, and loose local debug settings travel into production.
101
102**Fix**: split it into application.yml (shared) plus application-prod.yml, and
103activate with SPRING_PROFILES_ACTIVE=prod. Every secret comes from an external
104Secret and never enters the image. Add a prod-profile config check step in CI.
105
106**Why**: config ships with the artifact, so review it and split it per environment, like code.
§07

写这两道题时的几条实操建议A few practical tips for writing these two answers

  • 给出可以粘贴的配置。「应该限制 actuator 暴露」和management.endpoints.web.exposure.include=health,info是两个水平。
  • 按严重性排序。把 actuator 全开放在第一个 —— 它是唯一能直接 导致口令泄漏的。评分的人可能只认真看前两条。
  • 承认某些「问题」其实是合理设计。server.address=0.0.0.0 在容器里是必须的(不然 Pod 外面连不上)。 把它当成安全问题反而暴露了对容器网络的不理解。能指出「这一条不是问题」是加分的。
  • 每条都写「理由」。题目原文明确要求 with justification。 只给配置不给理由会丢分。
  • 别写空话。「要遵循最佳实践」「要加强安全意识」这类句子零分, 而且会稀释真正有内容的部分。
  • Give config someone can paste. “Actuator exposure should be restricted” and management.endpoints.web.exposure.include=health,info are two different grades.
  • Order by severity. Put actuator wide open first — it is the only one that leaks the password outright. Whoever grades this may only read the first two carefully.
  • Admit when a “problem” is actually sound design. server.address=0.0.0.0 is required inside a container — without it nothing outside the Pod can connect. Calling it a security issue advertises that you do not understand container networking. Pointing out “this one is not a problem” earns credit.
  • Give reasoning for every item. The question says with justification in so many words. Config with no reasoning loses marks.
  • No filler. Sentences like “follow best practices” and “improve security awareness” score zero, and they dilute the parts that have substance.
练习Practice

动手做Get your hands on it

填空只是过渡。真正掌握的标准,是在没有答案的时候从头写出来 —— 所以做完 L2 之后一定要往 L3、L4 走。Filling blanks is a stepping stone. The real bar is writing it from nothing, so once L2 is comfortable, push on to L3 and L4.

L1认出来Spot it哪一行是最严重的安全问题Which line is the most serious security problem

题面给的六行配置里,哪一行能直接导致数据库口令泄漏?

Of the six configuration lines in the question, which one can directly leak the database password?

Properties源项目From source
1server.port=8080
2server.address=0.0.0.0
3spring.datasource.url=jdbc:postgresql://${DB_HOST}:5432/orders
4spring.datasource.username=${DB_USER}
5spring.datasource.password=${DB_PASSWORD}
6management.endpoints.web.exposure.include=*
Source: graphql-federation-practice/QUESTIONS.md
先选一个选项Pick an option first
L1认出来Spot it为什么 User subgraph 慢会拖慢 Orders subgraphWhy a slow User subgraph slows the Orders subgraph down

客户端查 { user(id:"1") { name orders { id } } }。 Accounts subgraph 要 500ms,Orders subgraph 只要 10ms。 总延迟大约是多少,为什么?

A client asks for { user(id:"1") { name orders { id } } }. The Accounts subgraph takes 500ms, the Orders subgraph only 10ms. Roughly what is the total latency, and why?

先选一个选项Pick an option first
L3写整块Write a block写出 actuator 那一条的修正配置Write the corrected configuration for the actuator lineDrillLab 自出Written by DrillLab

针对 management.endpoints.web.exposure.include=*, 写出修正后的配置。至少要做到:白名单、管理端口分离、 health 不泄漏细节、支持 k8s 探针。

Write the corrected configuration for management.endpoints.web.exposure.include=*. At a minimum: an allow list, management on its own port, a health endpoint that leaks no detail, and support for Kubernetes probes.

要求Requirements
  • 用白名单列出需要的端点,不用 *List the endpoints you need in an allow list; do not use *
  • management.server.port 设成与业务端口不同的值Set management.server.port to something other than the business port
  • health 端点不显示详情The health endpoint shows no details
  • 开启 health probes(liveness / readiness)Turn on the health probes (liveness and readiness)
Propertiesapplication-prod.properties
This check is textual: it looks for the right constructs, it does not run your code
提示Hints共 4 级,已看 0 级4 levels, 0 opened
先自己想两分钟。想不出来再点右上角 —— 提示是一级一级放的,不会一次给完。Think for two minutes first. Then use the button above — hints come one level at a time, never all at once.

看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.

迁移Transfer

换一道题也能用Works on other problems too

考试不会原题重考。真正能带走的是「看到这种信号 → 伸手去拿这个解法」。The exam will not reuse the same question. What you take away is the reflex: see this signal, reach for that solution.

「某个服务慢了会怎样」A question like: what happens when one service gets slow
先找串行依赖,再讲资源放大Find the serial dependency first, then explain how resource use grows
「给一种缓存策略」A question like: propose a caching strategy
缓存键 + TTL + 失效策略 + 一致性代价,四件套Four parts: cache key, TTL, how it is invalidated, and the consistency cost
审查配置You are asked to review configuration
六个面:暴露 / 凭据 / 传输 / 资源韧性 / 可观测 / 配置管理Six areas: what is exposed, credentials, transport, resource resilience, observability, config management
看到 include=*You see include=*
白名单代替通配符,默认拒绝Replace the wildcard with an allow list; deny by default
看到 0.0.0.0 就想报警You are about to report 0.0.0.0 as a problem
容器里这是必须的,别当成问题Inside a container it is required; it is not a problem
书面题要求 justificationA written question asks for justification
每条都写理由,只给配置会丢分Give a reason for every item; configuration alone loses points
这节的要点What to take away
  1. 答题结构:结论 → 机制 → 方案 → 代价与边界。最后一段最能区分水平。Answer structure: conclusion, then mechanism, then solution, then cost and limits. The last part separates good answers from average ones.
  2. 第 1 题的核心是「Router 的查询计划里 @key 那一步是前置依赖,所以串行」。The core of Question 1: in the Router query plan the @key step must finish first, so the calls run one after another.
  3. 缓存答案要包含四件事:缓存键、TTL、主动失效、一致性代价。A caching answer needs four things: the cache key, the TTL, active invalidation, and the consistency cost.
  4. 第 2 题按六个面扫:暴露面 / 凭据 / 传输 / 资源韧性 / 可观测性 / 配置管理。For Question 2, scan six areas: what is exposed, credentials, transport, resource resilience, observability, config management.
  5. actuator 全开是最严重的(/actuator/env 直接泄漏口令);server.address=0.0.0.0 在容器里不是问题。Leaving all of actuator open is the worst problem, because /actuator/env prints the password. server.address=0.0.0.0 is not a problem inside a container.

接下来What next

  1. 把这一节的练习做掉Do this lesson’s exercises3 个,就在这一页上面 —— 别攒着最后一起做3 of them, further up this page — do not save them for later
    回到练习 ↑Back up to them ↑
  2. 接着看下一节Continue to the next lessonDebug Lab · Federation 十种典型故障Debug Lab · ten common Federation failures
    下一节Next lesson
读完并且做过上面的练习了吗?Read it and worked through the exercises above?
上一节:Previous: 六个端点:状态码就是这道题的全部Six endpoints: the status codes are the whole task