×

能涨薪水30%的.NET 微服务面试题 35 道(带答案)

独孤求败 独孤求败 发表于2026-02-26 09:18:31 浏览10 评论0

抢沙发发表评论

第 1 题:如何用 DDD 划分微服务边界?

✅ 题目重述:

在微服务架构中,如何合理划分服务边界?请结合“领域驱动设计(DDD)”说明你的理解。

✅ 考察意图:

  • 是否理解微服务划分不是按技术层,而是按业务能力
  • 是否掌握 DDD 战略设计(限界上下文、子域、聚合)
  • 是否能避免常见错误(如过度拆分、错误合并)

✅ 理想答案结构:

  1. 划分原则

    • 基于业务能力子域(Subdomain)划分,而非技术层(如“用户服务”、“订单服务”)。
    • 每个微服务对应一个限界上下文(Bounded Context) —— 拥有独立模型、术语、数据库。
  2. DDD 核心概念应用

    • 服务间通过事件通信,实现最终一致性。
    • 如 OrderCreatedEvent → PaymentService 订阅处理。
    • 事务一致性边界,一个聚合通常在一个服务内。
    • 如 Order 聚合包含 OrderItems,但不应跨服务(如订单+库存)。
    • 核心域(如订单、支付)→ 优先独立服务,投入最多资源。
    • 支撑域(如通知、审计)→ 可复用服务。
    • 通用域(如身份认证)→ 可采购或共享。
    • 子域分类
    • 聚合(Aggregate)
    • 领域事件(Domain Event)
  3. 避免错误合并

    • ❌ 订单服务 + 支付服务合并 → 导致事务膨胀、职责不清。
    • ✅ 正确做法:订单服务 → 发布事件 → 支付服务异步处理。
  4. .NET 实践(加分项)

    • 使用 MediatR 实现领域事件分发:
      public class OrderCreatedHandler : INotificationHandler<OrderCreatedEvent>
      {
          public Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
          {
              // 发布到消息队列或直接调用
              return Task.CompletedTask;
          }
      }
    • 参考微软官方示例:eShopOnContainers 架构(Ordering、Basket、Payment 独立服务)。

✅ 常见错误 & 避坑指南:

  • ❌ “按数据库表划分服务” → 导致服务粒度过细。
  • ❌ “按团队划分服务” → 可能违反业务边界。
  • ❌ “共享数据库” → 破坏服务自治性。

✅ 加分项/扩展知识:

  • 提到“上下文映射”(Context Mapping)和“防腐层”(Anti-Corruption Layer)。
  • 提到“CQRS 模式”在服务内部的应用(如读写分离)。

第 2 题:HTTP/REST vs gRPC 如何选?

✅ 题目重述:

在 .NET 微服务中,服务间通信有哪些方式?请对比 HTTP + REST 与 gRPC 的优缺点,并说明适用场景。

✅ 考察意图:

  • 是否理解同步通信的两种主流协议
  • 是否能根据场景选择合适技术
  • 是否掌握 .NET 中的具体实现

✅ 理想答案结构:

  1. 通信方式总览

    • 同步:HTTP/REST、gRPC
    • 异步:消息队列(RabbitMQ/Kafka)、事件总线
  2. HTTP/REST vs gRPC 对比

    维度
    HTTP + REST (JSON)
    gRPC (Protobuf)
    协议
    HTTP/1.1
    HTTP/2
    数据格式
    文本(JSON/XML)
    二进制(Protobuf)
    性能
    较低(文本解析、Header 冗余)
    高(二进制、多路复用、头部压缩)
    类型安全
    弱(靠文档/约定)
    强(.proto 生成强类型客户端)
    跨语言
    广泛支持
    支持多语言(官方支持 C#, Java, Go, Python 等)
    浏览器支持
    ✅ 原生支持
    ❌ 需 gRPC-Web 代理
    调试/工具
    ✅ Postman、浏览器 DevTools
    ❌ 需 grpcurl、BloomRPC 等
    流式通信
    ❌ 需 WebSocket/SSE
    ✅ 原生支持(服务端流、客户端流、双向流)
  3. 适用场景

    • 内部服务高频调用(如订单→库存)
    • 实时双向通信(如聊天、游戏同步)
    • 多语言微服务环境
    • 需要强类型契约和版本管理
    • 对外暴露 API(Web/Mobile/BFF)
    • 与遗留系统集成
    • 快速原型、低频调用
    • 用 REST
    • 用 gRPC
  4. .NET 实践(加分项)

    • 使用 Grpc.AspNetCore 创建服务:
      public class PaymentService : Payment.PaymentBase
      {
          public override Task<PayResponse> Pay(PayRequest request, ServerCallContext context)
          {
              // 业务逻辑
              return Task.FromResult(new PayResponse { Success = true });
          }
      }
    • 使用 Grpc.Net.Client 创建客户端:
      var channel = GrpcChannel.ForAddress("https://localhost:5001");
      var client = new Payment.PaymentClient(channel);
      var response = await client.PayAsync(new PayRequest { Amount = 99.9m });

✅ 常见错误 & 避坑指南:

  • ❌ “gRPC 适合所有场景” → 忽略浏览器不支持问题。
  • ❌ “REST 性能足够” → 在高频内部调用中,gRPC 优势明显。
  • ❌ “Protobuf 难调试” → 可用 BloomRPC 等工具可视化。

✅ 加分项/扩展知识:

  • 提到 gRPC-Web 用于浏览器调用。
  • 提到 Dapr 服务调用 默认使用 gRPC。

🧩 第 3 题:服务发现:Consul vs Dapr?

✅ 题目重述:

在 .NET 微服务架构中,如何实现服务发现(Service Discovery)?请说明基于 Consul 和基于 Dapr 的实现方式有何不同。

✅ 考察意图:

  • 是否理解服务发现的核心价值(动态路由、健康检查)
  • 是否掌握两种主流实现方式
  • 是否能对比传统 SDK 集成 vs 云原生 Sidecar 模式

✅ 理想答案结构:

  1. 服务发现核心价值

    • 动态路由:客户端无需硬编码服务地址。
    • 健康检查:自动剔除故障实例。
    • 负载均衡:在多个实例间分发请求。
  2. Consul 实现方式

    • 服务注册:应用启动时调用 Consul API 注册自己。
      var client = new ConsulClient();
      await client.Agent.ServiceRegister(new AgentServiceRegistration
      {
          ID = "OrderService-01",
          Name = "OrderService",
          Address = "localhost",
          Port = 5001,
          Check = new AgentServiceCheck { HTTP = "http://localhost:5001/health", Interval = TimeSpan.FromSeconds(10) }
      });
    • 服务发现:客户端查询 Consul 获取实例列表。
      var services = await client.Catalog.Service("OrderService");
  3. Dapr 实现方式

    • Sidecar 模式:每个服务旁部署 Dapr 进程,应用无感知。
    • 服务调用:通过 localhost:3500 调用 Dapr API。
      GET http://localhost:3500/v1.0/invoke/PaymentService/method/pay
    • 自动服务发现:Dapr 运行时负责注册、发现、负载均衡。
  4. 核心区别对比

    维度
    Consul(直接集成)
    Dapr(Sidecar 抽象)
    集成方式
    SDK 嵌入应用
    Sidecar 进程,应用无感知
    服务注册
    应用主动注册
    Sidecar 自动注册
    服务发现调用
    应用查询 Consul + 负载均衡
    调用 localhost Dapr 端点
    多语言支持
    需各语言 SDK
    所有语言统一 HTTP/gRPC 接口
    可移植性
    绑定 Consul
    可切换后端(Consul/K8s/mDNS)
    学习成本
    需掌握 Consul API
    只需调用 Dapr API,更简单
  5. .NET 实践(加分项)

    • Consul + Steeltoe(Spring Cloud 风格集成)。
    • Dapr + .NET SDK(Dapr.Client)简化调用。

✅ 常见错误 & 避坑指南:

  • ❌ “Consul 只能用于服务发现” → 它还支持 KV 配置、健康检查。
  • ❌ “Dapr 是服务网格” → Dapr 是运行时,可替代部分服务网格功能。
  • ❌ “服务发现不需要健康检查” → 健康检查是核心功能。

✅ 加分项/扩展知识:

  • 提到 Kubernetes DNS 作为服务发现替代方案。
  • 提到 mDNS 用于本地开发环境。

🧩 第 4 题:API 网关选 Ocelot 还是 YARP?

✅ 题目重述:

请解释在 .NET 微服务中,为什么需要 API 网关(API Gateway)?请以 Ocelot 或 YARP 为例,说明它能解决哪些问题。

✅ 考察意图:

  • 是否理解网关的核心价值(路由、认证、限流)
  • 是否掌握 .NET 生态主流工具
  • 是否能对比新旧方案

✅ 理想答案结构:

  1. 为什么需要 API 网关?—— 解决六大问题

    问题
    说明
    路由聚合
    统一入口,隐藏内部服务拓扑(如 /api/order → OrderService)
    认证授权
    集中校验 JWT/OAuth2,避免每个服务重复实现
    限流熔断
    防止突发流量(如秒杀)击垮服务
    负载均衡
    在多个服务实例间分发请求
    日志监控
    统一收集访问日志、性能指标
    协议转换
    对外暴露 REST,内部调用 gRPC 或消息队列
  2. Ocelot 实现方式

    • 功能:路由、请求聚合、限流、熔断、认证、负载均衡。
    • 配置:基于 JSON 文件(ocelot.json)。
      {
        "Routes": [
          {
            "DownstreamPathTemplate""/api/orders",
            "DownstreamScheme""http",
            "DownstreamHostAndPorts": [ { "Host""order-service""Port"80 } ],
            "RateLimitOptions": { "ClientWhitelist": [], "EnableRateLimiting"true"Period""1s""Limit"10 }
          }
        ]
      }
    • 缺点:性能一般,配置静态(需重载),社区活跃度下降。
  3. YARP 实现方式

    • 微软官方出品,基于 ASP.NET Core Middleware,性能更高。
    • 配置可编程(C# 代码动态加载),适合云原生/K8s 环境。
    • 更轻量,适合作为“反向代理”而非“全能网关”。
  4. 如何选择?

    • 选 Ocelot:需要开箱即用的全功能网关,且不追求极致性能。
    • 选 YARP:需要高性能、动态配置、云原生集成。
  5. .NET 实践(加分项)

    • Ocelot + Polly 实现熔断:
      services.AddOcelot().AddPolly();
    • YARP + Kubernetes 服务发现:
      builder.Services.AddReverseProxy()
          .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

✅ 常见错误 & 避坑指南:

  • ❌ “网关只做路由” → 忽略认证、限流等核心功能。
  • ❌ “Ocelot 是最新方案” → YARP 是微软官方推荐的新方向。
  • ❌ “网关可以替代服务发现” → 网关通常依赖服务发现组件。

✅ 加分项/扩展知识:

  • 提到 BFF(Backend for Frontend) 模式(为不同客户端定制聚合接口)。
  • 提到 Kubernetes Ingress 作为网关替代方案。

🧩 第 5 题:分布式配置怎么管?

✅ 题目重述:

在 .NET 微服务中,如何实现分布式配置管理?请对比使用 Consul KV、Azure App Configuration 和 Dapr Configuration 的优缺点。

✅ 考察意图:

  • 是否理解配置中心的核心价值(集中管理、动态更新)
  • 是否掌握主流工具及其适用场景
  • 是否能实现 .NET 集成

✅ 理想答案结构:

  1. 为什么需要分布式配置?

    • 避免配置散落在各服务的 appsettings.json
    • 支持动态更新(无需重启服务)。
    • 统一管理多环境(dev/stage/prod)、多租户配置。
  2. 三种方案对比

    维度
    Consul KV
    Azure App Configuration
    Dapr Configuration
    部署模式
    自建(需维护 Consul 集群)
    全托管云服务(PaaS)
    Sidecar 抽象(可对接多种后端)
    .NET 集成
    Consul
     NuGet + 手动监听
    Microsoft.Extensions.Configuration.AzureAppConfigurationDaprClient.GetConfiguration()
    实时更新
    ✅ 支持 Watch 长轮询
    ✅ 推送 + 轮询
    ✅ 通过 Dapr Sidecar 自动更新
    多环境支持
    ✅ Key 前缀隔离(如 dev/prod)
    ✅ Label + Profile 原生支持
    ✅ 依赖后端能力
    安全性
    ✅ ACL + TLS
    ✅ 托管身份 + RBAC
    ✅ 依赖后端 + mTLS
    适用场景
    自建 IDC / 混合云
    Azure 云原生项目
    多云 / 混合云 / Dapr 生态项目
    缺点
    ❌ 需自运维,无 UI
    ❌ 仅限 Azure
    ❌ 需部署 Dapr,学习曲线陡
  3. .NET 实现要点

    • Consul KV
      var client = new ConsulClient();
      var kv = await client.KV.Get("app:database:connectionString");
      Configuration["Database:ConnectionString"] = kv.Response.Value;
    • Azure App Configuration
      builder.Configuration.AddAzureAppConfiguration(options =>
          options.Connect(connectionString).UseFeatureFlags());
    • Dapr Configuration
      var client = new DaprClientBuilder().Build();
      var items = await client.GetConfigurationAlpha1Async(storeName: "configstore", keys: new[] { "database.connectionString" });
  4. 高级功能(加分项)

    • 功能开关(Feature Flags):Azure App Configuration 原生支持。
    • 配置热更新:使用 IOptionsMonitor<T> 监听变更。

✅ 常见错误 & 避坑指南:

  • ❌ “用数据库存配置” → 不适合高频读取、无版本管理。
  • ❌ “配置更新需要重启服务” → 应实现动态刷新。
  • ❌ “所有服务用同一套配置” → 应支持环境隔离。

✅ 加分项/扩展知识:

  • 提到 Spring Cloud Config 作为 Java 生态方案。
  • 提到 配置加密(如 Azure Key Vault 集成)。

🧩 第 6 题:日志监控:ELK vs OpenTelemetry?

✅ 题目重述:

在 .NET 微服务中,如何实现分布式日志收集与监控?请说明 ELK(Elasticsearch + Logstash + Kibana)与使用 OpenTelemetry + Prometheus + Grafana 两种方案的差异。

✅ 考察意图:

  • 是否理解“可观测性三大支柱”(Logs、Metrics、Traces)
  • 是否能区分日志系统与指标/链路系统
  • 是否掌握 .NET 与主流工具的集成方式

✅ 理想答案结构:

  1. 分布式日志与监控的核心目标

    • 集中收集、统一存储、实时分析、可视化告警。
    • 支持故障排查、性能优化、容量规划。
  2. ELK 方案(侧重 Logs)

    • Elasticsearch:存储 + 搜索日志。
    • Logstash/Filebeat:采集日志(Filebeat 更轻量)。
    • Kibana:可视化日志(搜索、仪表盘)。
    • 组件
    • .NET 集成
      Log.Logger = new LoggerConfiguration()
          .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://es:9200"))
          {
              AutoRegisterTemplate = true,
              IndexFormat = "logs-{0:yyyy.MM.dd}"
          })
          .CreateLogger();
    • 适用场景:错误日志分析、安全审计、业务日志查询。
  3. OpenTelemetry + Prometheus + Grafana(侧重 Metrics/Traces)

    • OpenTelemetry:统一采集 SDK(支持 .NET)。
    • Prometheus:拉取指标,存储时序数据。
    • Grafana:可视化指标和链路(通过 Jaeger/Tempo)。
    • 组件
    • .NET 集成
      services.AddOpenTelemetry()
          .WithMetrics(b => b.AddAspNetCoreInstrumentation().AddPrometheusExporter())
          .WithTracing(b => b.AddAspNetCoreInstrumentation().AddJaegerExporter());
    • 适用场景:服务性能监控(QPS、延迟、错误率)、调用链追踪、SLO 保障。
  4. 核心差异总结

    维度
    ELK(日志中心)
    OpenTelemetry + Prometheus + Grafana(指标/链路中心)
    核心数据
    Logs(文本日志)
    Metrics(数值指标)、Traces(调用链)
    主要用途
    调试、审计、错误分析
    性能优化、容量规划、服务依赖分析
    数据结构
    半结构化(需 grok 解析)
    强结构化(直方图、计数器、链路 Span)
    .NET 集成
    Serilog + Elasticsearch Sink
    OpenTelemetry SDK + Prometheus Exporter
    实时性
    延迟较高(秒~分钟级)
    延迟低(毫秒~秒级)
    存储成本
    高(全文索引)
    低(时序数据库压缩)
    可视化
    Kibana(日志搜索、仪表盘)
    Grafana(指标图表、链路拓扑)
  5. 现代架构推荐:三者融合(加分项)

    • 用 OpenTelemetry 同时采集 Logs、Metrics、Traces。
    • Logs → Elasticsearch/Loki
    • Metrics → Prometheus
    • Traces → Jaeger/Tempo
    • 统一用 Grafana 可视化(Grafana 8+ 支持 Logs + Traces)。

✅ 常见错误 & 避坑指南:

  • ❌ “用 MongoDB 存日志” → 无全文检索、聚合分析能力。
  • ❌ “只用 ELK 监控性能” → 日志不适合做实时指标计算。
  • ❌ “OpenTelemetry 只能做链路” → 它支持 Logs、Metrics、Traces 三位一体。

✅ 加分项/扩展知识:

  • 提到 Loki(轻量日志系统,Grafana Labs 出品)。
  • 提到 Tempo(分布式追踪系统,与 Grafana 深度集成)。
  • 提到 Serilog + OpenTelemetry Exporter 实现日志采集。

🧩 第 7 题:分布式事务怎么做?

✅ 题目重述:

在 .NET 微服务中,如何实现分布式事务?请说明“本地消息表”、“Saga 模式”和“Seata”三种方案的原理和适用场景。

✅ 考察意图:

  • 是否理解分布式事务的难点(CAP 定理、最终一致性)
  • 是否掌握主流解决方案
  • 是否能根据场景选择合适方案

✅ 理想答案结构:

  1. 为什么微服务需要分布式事务?

    • 单体应用:本地数据库事务(ACID)即可。
    • 微服务:跨多个数据库/服务,无法用本地事务保证一致性。
  2. 本地消息表(Local Message Table)—— 最常用、最推荐

    • 在业务数据库中,增加一个“消息表”(如 OutboxMessages)。
    • 业务操作和“插入消息”在同一个本地事务中完成。
    • 后台任务(Worker)轮询消息表,将消息发送到消息队列(如 RabbitMQ/Kafka)。
    • 下游服务消费消息,执行本地操作。
    • 原理
    • 流程示例(下单扣库存)
      1. OrderService:
         BEGIN TRANSACTION
           → INSERT INTO Orders (...)
           → INSERT INTO OutboxMessages (Message = '{"Type":"ReduceStock", "Data":...}')
         COMMIT
      2. Background Worker:
         → SELECT * FROM OutboxMessages WHERE Sent = false
         → Publish to RabbitMQ: "stock.reduce" with message
         → UPDATE OutboxMessages SET Sent = true
      3. StockService:
         → Consume "stock.reduce"
         → UPDATE Stocks SET Quantity = Quantity - 1 WHERE ProductId = X
    • 优点:100% 保证消息不丢失(和业务操作原子性),技术简单。
    • 缺点:需手动实现轮询和去重,消息表可能膨胀。
    • 适用场景:电商下单、支付通知、积分发放等最终一致性场景。
  3. Saga 模式 —— 长流程、多步骤事务

    • 将一个大事务拆分为多个本地事务 + 补偿操作(Compensating Transaction)。
    • 两种实现方式:
    • 编排式(Orchestrated):由一个中心协调器(Saga Orchestrator)调用各服务,并记录状态。
    • 协同式(Choreography):各服务通过事件驱动,互相监听和触发下一步。
    • 原理
    • 流程示例(旅行预订:航班 + 酒店 + 出租车)
      编排式:
      1. Saga Orchestrator → 调用 FlightService.Book()
      2. → 调用 HotelService.Book()
      3. → 调用 TaxiService.Book()
      4. 如果 Taxi 失败 → 调用 HotelService.Cancel() → 调用 FlightService.Cancel()
    • 优点:支持复杂、长周期业务流程,无全局锁。
    • 缺点:补偿逻辑复杂,需每个服务实现 Cancel 方法。
    • 适用场景:旅行预订、贷款审批、跨部门审批流等多步骤、可补偿场景。
  4. Seata(阿里开源)—— 强一致性(谨慎使用)

    • 类似“分布式版数据库事务”,通过 TC(事务协调器)+ TM(事务管理器)+ RM(资源管理器)实现。
    • 支持 AT(自动补偿)、TCC(Try-Confirm-Cancel)、Saga、XA 模式。
    • 在 .NET 中通过 Seata AT 模式,对业务代码无侵入。
    • 原理
    • 流程(AT 模式)
      1. OrderService 注册为 RM,开启全局事务。
      2. 执行本地 SQL(如 INSERT Order),Seata 记录“before image”和“after image”。
      3. 调用 StockService,同样记录镜像。
      4. 如果 StockService 失败 → Seata 根据 before image 自动回滚 OrderService 数据。
    • 优点:对业务代码透明(只需加 [Transaction] 注解),支持强一致性。
    • 缺点:性能低(全局锁、镜像存储),依赖 Seata Server 集群,.NET 支持弱。
    • 适用场景:金融、支付等必须强一致的场景(但尽量避免)。
  5. 三种方案对比表(面试必备)

    方案
    一致性
    性能
    复杂度
    适用场景
    .NET 成熟度
    本地消息表
    最终一致
    电商、支付、通知
    ⭐⭐⭐⭐⭐
    Saga 模式
    最终一致
    旅行预订、审批流
    ⭐⭐⭐⭐(MassTransit)
    Seata
    强一致
    金融核心(慎用)
    ⭐⭐(社区版)
  6. .NET 实现(加分项)

    • 本地消息表:使用 Entity Framework Core + BackgroundService + RabbitMQ.Client
    • Saga 模式:使用 MassTransit Saga(编排式)或 事件驱动(协同式)。
    • Seata:使用 Seata.Client NuGet 包(社区维护,稳定性待验证)。

✅ 常见错误 & 避坑指南:

  • ❌ “用分布式锁实现事务” → 性能极低,且不保证原子性。
  • ❌ “所有场景用 Seata” → 强一致性带来性能和复杂度问题。
  • ❌ “Saga 不需要补偿” → 补偿是 Saga 的核心机制。

✅ 加分项/扩展知识:

  • 提到 Eventuate Tram(Chris Richardson 的 Saga 框架)。
  • 提到 NServiceBus(商业 Saga 框架,功能强大)。

🧩 第 8 题:熔断降级:Polly 怎么配?

✅ 题目重述:

在 .NET 微服务中,如何实现服务熔断与降级?请以 Polly 为例,说明如何配置熔断策略,并解释“半开”状态的作用。

✅ 考察意图:

  • 是否理解熔断器模式(Circuit Breaker Pattern)
  • 是否掌握 Polly 库的使用
  • 是否理解“半开状态”的价值

✅ 理想答案结构:

  1. 熔断与降级的目的

    • 防止故障扩散(雪崩效应)。
    • 快速失败,提升系统可用性。
    • 降级提供有损服务,而非完全不可用。
  2. Polly 配置示例

    var circuitBreakerPolicy = Policy
        .Handle<HttpRequestException>() // 处理哪些异常
        .OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode) // 或哪些结果
        .CircuitBreakerAsync(
            exceptionsAllowedBeforeBreaking: 5// 允许5次失败
            durationOfBreak: TimeSpan.FromSeconds(30), // 熔断30秒
            onBreak: (ex, ts) => Console.WriteLine("熔断开启!"),
            onReset: () => Console.WriteLine("熔断重置!"),
            onHalfOpen: () => Console.WriteLine("半开状态,试探性放行!")
        );

    var fallbackPolicy = Policy<HttpResponseMessage>
        .Handle<Exception>()
        .FallbackAsync(
            fallbackAction: ct => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent("{\"error\":\"服务暂时不可用,请稍后重试\"}")
            }),
            onFallbackAsync: ex => Console.WriteLine("已降级")
        );

    services.AddHttpClient("OrderService")
        .AddPolicyHandler(circuitBreakerPolicy)
        .AddPolicyHandler(fallbackPolicy);
  3. “半开状态”详解

    • 如果成功 → 重置为 Closed。
    • 如果失败 → 重新进入 Open。
    • 熔断状态(Open):直接拒绝请求,快速失败。
    • 半开状态(Half-Open):熔断器在超时后,允许少量请求通过,试探服务是否恢复。
    • 作用:避免服务恢复后瞬间被大量请求压垮,实现平滑恢复。
  4. 适用场景

    • 调用第三方支付、短信、风控等不稳定外部服务。
    • 微服务间调用,下游服务可能过载。
  5. .NET 实践(加分项)

    • 与 IHttpClientFactory 集成:
      services.AddHttpClient("PaymentService")
          .AddPolicyHandler(circuitBreakerPolicy)
          .AddPolicyHandler(fallbackPolicy);
    • 监控熔断器状态变化(日志或指标)。

✅ 常见错误 & 避坑指南:

  • ❌ “熔断后永久拒绝” → 必须设置 durationOfBreak 和半开状态。
  • ❌ “降级返回空数据” → 应返回友好提示或默认值。
  • ❌ “所有异常都熔断” → 应区分可重试异常(如超时)和不可重试异常(如参数错误)。

✅ 加分项/扩展知识:

  • 提到 Polly.Contrib.WaitAndRetry(指数退避重试)。
  • 提到 Polly Metrics(集成 Prometheus 监控熔断器状态)。

🧩 第 9 题:健康检查怎么做?

✅ 题目重述:

在 .NET 微服务中,如何实现服务的健康检查(Health Check)?请说明 ASP.NET Core 内置健康检查机制,并举例如何检查数据库、Redis 和外部 API 的健康状态。

✅ 考察意图:

  • 是否理解健康检查在微服务中的作用(K8s、服务发现)
  • 是否掌握 ASP.NET Core 内置机制
  • 是否能扩展自定义检查

✅ 理想答案结构:

  1. 为什么需要健康检查?

    • Kubernetes:通过 /health 端点判断 Pod 是否 Ready。
    • 服务发现(如 Consul):自动剔除故障实例。
    • 网关(如 Ocelot/YARP):根据健康状态做负载均衡。
  2. ASP.NET Core 内置健康检查机制(三步配置)

    • 步骤 1:注册健康检查服务
      builder.Services.AddHealthChecks();
    • 步骤 2:添加具体检查项
      builder.Services.AddHealthChecks()
          .AddDbContextCheck<AppDbContext>("Database")
          .AddRedis("redis-connection-string", name: "Redis")
          .AddUrlGroup(new Uri("https://api.payment.com/health"), name: "Payment API");
    • 步骤 3:暴露健康检查端点
      app.MapHealthChecks("/health");
  3. 三种典型检查项详解

    • 检查数据库(SQL Server / PostgreSQL / MySQL)
      builder.Services.AddHealthChecks()
          .AddDbContextCheck<AppDbContext>(
              name: "Database",
              failureStatus: HealthStatus.Degraded,
              tags: new[] { "db" }
          );
    • 检查 Redis
      builder.Services.AddHealthChecks()
          .AddRedis(
              configuration: "localhost:6379,password=123",
              name: "Redis",
              tags: new[] { "cache" }
          );
    • 检查外部 API(自定义 IHealthCheck)
      public classPaymentApiHealthCheck : IHealthCheck
      {
          privatereadonly HttpClient _httpClient;
          public PaymentApiHealthCheck(HttpClient httpClient) => _httpClient = httpClient;

          public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
          {
              try
              {
                  var response = await _httpClient.GetAsync("/health", cancellationToken);
                  return response.IsSuccessStatusCode
                      ? HealthCheckResult.Healthy("Payment API is healthy")
                      : HealthCheckResult.Unhealthy($"Payment API returned {response.StatusCode}");
              }
              catch (Exception ex)
              {
                  return HealthCheckResult.Unhealthy("Payment API unreachable", ex);
              }
          }
      }

      builder.Services.AddHttpClient();
      builder.Services.AddHealthChecks()
          .AddCheck<PaymentApiHealthCheck>("Payment API", tags: new[] { "external" });
  4. 高级用法(加分项)

    • 分组检查
      app.MapHealthChecks("/health/db"new HealthCheckOptions
      {
          Predicate = check => check.Tags.Contains("db")
      });
    • UI 可视化(AspNetCore.HealthChecks.UI)
      dotnet add package AspNetCore.HealthChecks.UI
      dotnet add package AspNetCore.HealthChecks.UI.Client
      builder.Services.AddHealthChecksUI().AddInMemoryStorage();
      app.MapHealthChecks("/health"new HealthCheckOptions
      {
          ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
      });
      app.MapHealthChecksUI();
    • 与 Kubernetes 集成
      livenessProbe:
        httpGet:
          path:/health
          port:80
      initialDelaySeconds:10
      periodSeconds:5
      readinessProbe:
      httpGet:
          path:/health
          port:80
      initialDelaySeconds:5
      periodSeconds:3

✅ 常见错误 & 避坑指南:

  • ❌ “健康检查只检查自身” → 应检查依赖服务(DB、Redis、API)。
  • ❌ “返回 200 就是健康” → 应区分 HealthyDegradedUnhealthy
  • ❌ “健康检查耗时过长” → 应设置超时,避免阻塞。

✅ 加分项/扩展知识:

  • 提到 自定义健康检查状态(如 HealthStatus.Degraded)。
  • 提到 健康检查缓存(避免频繁检查)。

🧩 第 10 题:灰度发布怎么做?

✅ 题目重述:

在 .NET 微服务中,如何实现配置的灰度发布(Feature Flag)?请以 Azure App Configuration 为例,说明如何动态控制功能开关。

✅ 考察意图:

  • 是否理解灰度发布的核心价值(无发布上线、A/B测试)
  • 是否掌握 Azure App Configuration 的使用
  • 是否能实现动态功能开关

✅ 理想答案结构:

  1. 什么是灰度发布(Feature Flag)?

    • 🚀 金丝雀发布:先对 1% 用户开放新功能。
    • 🧪 A/B 测试:对比两个版本的用户行为。
    • 🛑 紧急回滚:功能出问题,立即关闭开关。
    • 🧑‍💻 开发者特性:仅对内部员工开放调试功能。
    • 定义:通过配置动态控制功能是否启用,无需重新部署代码。
    • 用途
  2. Azure App Configuration 实现方案(四步走)

    • 在 Azure 门户中,随时切换功能开关状态(On/Off)。
    • .NET 应用默认每 30 秒轮询一次配置变更(可配置)。
    • Controller 层用 [FeatureGate] 特性
      [FeatureGate("NewCheckoutFlow")]
      [HttpPost("new")]
      public IActionResult NewCheckout()
      {
          return Ok("New checkout flow enabled!");
      }
    • **Service 层用 IFeatureManager**:
      public classRecommendationService
      {
          privatereadonly IFeatureManager _featureManager;
          public RecommendationService(IFeatureManager featureManager) => _featureManager = featureManager;

          public async Task<stringGetRecommendationsAsync()
          {
              if (await _featureManager.IsEnabledAsync("EnableRecommendation"))
                  return"New AI recommendations!";
              else
                  return"Default recommendations.";
          }
      }
    • 登录 Azure 门户 → 创建 “App Configuration” 资源。
    • 进入 “Feature Manager” → 添加功能标志,如:
    • NewCheckoutFlow → 默认 Off
    • EnableRecommendation → 默认 On
    • 步骤 1:创建 Azure App Configuration 实例
    • 步骤 2:在 .NET 项目中集成
      dotnet add package Microsoft.FeatureManagement.AspNetCore
      dotnet add package Microsoft.Azure.AppConfiguration.AspNetCore
      var builder = WebApplication.CreateBuilder(args);
      builder.Configuration.AddAzureAppConfiguration(options =>
      {
          options.Connect("your-connection-string")
                 .UseFeatureFlags();
      });
      builder.Services.AddFeatureManagement();
    • 步骤 3:在 Controller 或 Service 中使用功能开关
    • 步骤 4:动态更新(无需重启)
  3. 高级用法(加分项)

    • 用户/群组定向(Targeting)
      {
        "id""NewCheckoutFlow",
      "enabled"true,
      "conditions": {
          "client_filters": [
            {
              "name""Microsoft.Targeting",
              "parameters": {
                "Audience": {
                  "DefaultRolloutPercentage"10,
                  "Groups": [
                    {
                      "Name""internal-users",
                      "RolloutPercentage"100
                    }
                  ]
                }
              }
            }
          ]
        }
      }
      var userContext = new TargetingContext
      {
          UserId = "user123",
          Groups = new List<string> { "premium" }
      };
      if (await _featureManager.IsEnabledAsync("NewCheckoutFlow", userContext)) { ... }
    • 与 A/B 测试集成:结合 Azure Monitor + Application Insights。

✅ 常见错误 & 避坑指南:

  • ❌ “功能开关硬编码在代码中” → 应使用配置中心。
  • ❌ “开关变更需要重启服务” → 应实现动态刷新。
  • ❌ “所有用户看到相同功能” → 应支持用户定向。

✅ 加分项/扩展知识:

  • 提到 LaunchDarkly(第三方 Feature Flag 服务)。
  • 提到 自定义 Feature Filter(如按地区、设备类型)。

🧩 第 11 题:服务网格是啥?和网关啥区别?

✅ 题目重述:

在 .NET 微服务架构中,什么是“服务网格(Service Mesh)”?它与 API 网关有何不同?请以 Linkerd 或 Dapr 为例说明其价值。

✅ 考察意图:

  • 是否理解服务网格的核心价值(透明化通信治理)
  • 是否能区分服务网格与 API 网关
  • 是否掌握 Dapr 在 .NET 中的应用

✅ 理想答案结构:

  1. 什么是服务网格(Service Mesh)?

    • 数据平面(Data Plane):每个服务旁部署一个“Sidecar 代理”(如 Envoy、Dapr Sidecar),拦截所有进出流量。
    • 控制平面(Control Plane):管理所有 Sidecar,下发策略(如路由、熔断、mTLS)。
    • 定义:一种基础设施层,用于处理服务间通信(东西向流量),提供可观测性、安全、弹性能力,而无需修改业务代码
    • 核心组件
  2. 服务网格 vs API 网关

    维度
    服务网格(Service Mesh)
    API 网关(API Gateway)
    流向
    服务间通信(东西向)
    客户端 → 服务(南北向)
    部署位置
    每个服务旁(Sidecar)
    系统入口(集中式)
    主要功能
    mTLS、重试、熔断、指标、链路追踪
    路由、认证、限流、协议转换
    是否侵入代码
    ❌ 无侵入(Sidecar 透明代理)
    ✅ 需配置路由/策略
    适用规模
    中大型微服务(>50 服务)
    所有规模(必备入口)
    典型工具
    Linkerd、Istio、Dapr(轻量级)
    Ocelot、YARP、Kong、Apigee
  3. 以 Dapr 为例说明服务网格价值(.NET 友好!)

    • .NET、Java、Go、Python… 统一调用方式
    • 可运行在 K8s、VM、本地 —— 一套代码到处跑
    • 服务间通信自动加密,证书由 Dapr 自动管理
    • 自动暴露 Prometheus 指标(http://localhost:9090/metrics
    • 自动注入 Trace ID,对接 Zipkin/Jaeger
    • 开发者只需调用 http://localhost:3500/v1.0/invoke/<service>/method/<endpoint>
    • Dapr Sidecar 自动处理:服务发现、重试、mTLS、负载均衡
    • 服务调用(替代 gRPC/HTTP 客户端)
      var result = await _daprClient.InvokeMethodAsync<string>("PaymentService""pay", data);
    • 弹性策略(重试、熔断)
      # dapr/config.yaml
      apiVersion:dapr.io/v1alpha1
      kind:Configuration
      metadata:
      name:daprConfig
      spec:
      httpPipeline:
          handlers:
          -name:retry
            type:middleware.http.retry
          -name:circuit-breaker
            type:middleware.http.circuit-breaker
    • 可观测性(Metrics + Tracing)
    • 安全(mTLS 自动启用)
    • 多语言 & 多云
  4. 面试回答模板(结构化表达)

    “服务网格是处理服务间通信的基础设施层,通过 Sidecar 代理(如 Dapr)透明提供 mTLS、重试、熔断、指标等能力,无需修改业务代码

    与 API 网关不同:网关管‘从外到内’(南北向),服务网格管‘从内到内’(东西向)。

    我们选用 Dapr 作为轻量级服务网格方案,因为:

    例如,服务调用只需 daprClient.InvokeMethodAsync(...),重试/熔断/加密全由 Sidecar 处理。”

    • 对 .NET 支持极好(官方 SDK)
    • 通过 localhost 调用,简化服务发现和弹性策略
    • 自动集成可观测性和安全(mTLS)
    • 多云/混合云友好

✅ 常见错误 & 避坑指南:

  • ❌ “服务网格就是 API 网关” → 混淆东西向和南北向流量。
  • ❌ “Dapr 是完整服务网格” → Dapr 是运行时,功能比 Istio 轻量。
  • ❌ “Sidecar 会显著增加延迟” → 现代 Sidecar(如 Dapr)性能损耗 < 5%。

✅ 加分项/扩展知识:

  • 提到 Istio 的 VirtualService 和 DestinationRule。
  • 提到 Linkerd 的轻量级设计(Rust 编写)。
  • 提到 服务网格接口(SMI) 标准。

🧩 第 12 题:零信任安全怎么落地?

✅ 题目重述:

在 .NET 微服务中,如何实现“零信任安全(Zero Trust Security)”?请说明在服务间通信、身份认证、访问控制三个层面的具体实践。

✅ 考察意图:

  • 是否理解零信任安全的核心原则(永不信任,始终验证)
  • 是否掌握微服务安全的三层防护
  • 是否能结合 .NET 技术栈落地

✅ 理想答案结构:

  1. 什么是零信任安全?

    • 核心原则Never Trust, Always Verify —— 无论请求来自“内网”还是“外网”,都必须验证身份、设备、权限。
    • 三大支柱
    1. 服务间通信安全(mTLS)
    2. 身份认证(JWT/OIDC)
    3. 细粒度访问控制(RBAC/ABAC/OPA)
  2. 服务间通信安全 → 强制 mTLS(双向 TLS)

    • 方案 A:使用 Dapr(推荐,最简单)
      # dapr/config.yaml
      apiVersion: dapr.io/v1alpha1
      kind: Configuration
      metadata:
        name: appconfig
      spec:
        mtls:
          enabled: true  # 开启 mTLS,自动签发/轮换证书
    • 方案 B:使用 Kestrel + 证书(手动)
      builder.WebHost.ConfigureKestrel(serverOptions =>
      {
          serverOptions.ConfigureHttpsDefaults(httpsOptions =>
          {
              httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
              httpsOptions.OnAuthenticate = (context, options) =>
              {
                  var cert = context.Connection.ClientCertificate;
                  if (!IsValidClientCert(cert)) context.Abort();
              };
          });
      });
  3. 身份认证 → JWT + OIDC(OpenID Connect)

    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Authority = "https://your-oidc-provider.com";
            options.Audience = "your-api";
            options.TokenValidationParameters = new()
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true
            };
        });

    app.UseAuthentication();
    app.UseAuthorization();

    [Authorize]
    [HttpGet("profile")]
    public IActionResult GetProfile()
    {
        var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        return Ok($"Hello, {userId}");
    }
  4. 访问控制 → 策略引擎(OPA / 自定义策略)

    • 自定义授权策略(ABAC)
      services.AddAuthorization(options =>
      {
          options.AddPolicy("OwnerOnly", policy =>
              policy.Requirements.Add(new OwnerRequirement()));
      });

      publicclassOwnerAuthorizationHandler : AuthorizationHandler<OwnerRequirement>
      {
          protected override Task HandleRequirementAsync(
              AuthorizationHandlerContext context,
              OwnerRequirement requirement
      )

          {
              var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
              var resourceOwnerId = context.Resource?.ToString(); // 从路由/参数提取
              if (userId == resourceOwnerId) context.Succeed(requirement);
              return Task.CompletedTask;
          }
      }

      services.AddSingleton<IAuthorizationHandler, OwnerAuthorizationHandler>();

      [Authorize(Policy = "OwnerOnly")]
      [HttpPut("orders/{id}")]
      public IActionResult UpdateOrder(int id) { ... }
  5. 面试回答模板(结构化表达)

    “在 .NET 微服务中,我们通过三个层面实现零信任:

    例如,订单服务会验证 JWT 中的用户 ID 是否与订单 Owner 匹配,否则拒绝访问。”

    1. 服务间通信:强制 mTLS —— 使用 Dapr 自动启用双向 TLS,防止中间人攻击。
    2. 身份认证:JWT + OIDC —— 用户通过 Azure AD/Keycloak 登录,服务验证 JWT 提取身份。
    3. 访问控制:自定义授权策略 —— 实现‘用户只能访问自己数据’等细粒度规则,替代传统角色授权。

✅ 常见错误 & 避坑指南:

  • ❌ “内网通信不需要加密” → 零信任要求所有通信加密。
  • ❌ “JWT 只验证签名” → 必须验证 Issuer、Audience、Lifetime。
  • ❌ “角色授权足够” → 角色授权无法实现“用户A只能访问自己的数据”。

✅ 加分项/扩展知识:

  • 提到 OPA(Open Policy Agent) 作为独立策略引擎。
  • 提到 SPIFFE/SPIRE 作为 mTLS 证书管理方案。
  • 提到 Azure AD Conditional Access 作为零信任策略。

🧩 第 13 题:混沌工程怎么玩?

✅ 题目重述:

在 .NET 微服务中,如何实现“混沌工程(Chaos Engineering)”?请说明使用 Chaos Mesh 或 Azure Chaos Studio 进行故障注入的实践步骤。

✅ 考察意图:

  • 是否理解混沌工程的核心价值(主动验证系统韧性)
  • 是否掌握主流工具的使用
  • 是否理解 .NET 开发者的配合角色

✅ 理想答案结构:

  1. 什么是混沌工程?

    • 假设系统会失败 → 主动测试恢复能力
    • 最小化爆炸半径(只影响一小部分流量)
    • 自动化 + 可观测(监控指标变化)
    • 定义:在生产或预生产环境主动、可控地注入故障(如网络延迟、服务宕机、CPU 打满),验证系统是否能自动恢复或优雅降级。
    • 核心原则
  2. 方案 1:使用 Chaos Mesh(开源,K8s 原生)

    • 安装
      curl -sSL https://mirrors.chaos-mesh.org/v2.5.0/install.sh | bash
    • 注入“Pod Kill”故障
      apiVersion: chaos-mesh.org/v1alpha1
      kind:PodChaos
      metadata:
      name:pod-kill-example
      spec:
      action:pod-kill
      mode:one
      selector:
          namespaces:
            -default
          labelSelectors:
            "app":"order-service"
      duration:"30s"
      kubectl apply -f pod-kill.yaml
  3. 方案 2:使用 Azure Chaos Studio(托管服务)

    • 创建实验
      {
        "name""cpu-pressure-test",
      "properties": {
          "steps": [
            {
              "name""cpu-pressure",
              "actions": [
                {
                  "type""continuous",
                  "selectorId""my-vmss-selector",
                  "duration""PT10M",
                  "parameters": {
                    "pressureLevel""90",
                    "workers""4"
                  }
                }
              ]
            }
          ]
        }
      }
  4. .NET 开发者需要做什么?

    • 确保服务有健康检查端点/health)→ 供 K8s 判断是否重启。
    • 确保服务有熔断降级机制(Polly)→ 故障时优雅降级。
    • 确保监控告警完备(Prometheus + Grafana)→ 快速发现问题。
    • ❌ 不需要改代码 —— 混沌工程是运维/架构师职责。
    • ✅ 需要配合
  5. 面试回答模板(结构化表达)

    “混沌工程是通过主动注入故障(如杀 Pod、CPU 打满、网络延迟)来验证系统韧性的实践。

    在 .NET 微服务中,我们主要使用:

    作为开发者,我们确保:

    这样,即使混沌实验搞垮部分服务,系统也能自动恢复或优雅降级。”

    • 服务提供 /health 端点供 K8s 健康检查
    • 集成 Polly 实现熔断降级
    • 对接 Prometheus 监控关键指标
    1. Chaos Mesh:在 K8s 集群中注入 Pod Kill、网络分区等故障,验证服务自愈能力。
    2. Azure Chaos Studio:在 Azure 云上模拟 CPU 压力、服务中断,验证自动扩缩容和熔断机制。

✅ 常见错误 & 避坑指南:

  • ❌ “混沌工程只在测试环境做” → 应在预生产/生产环境做(控制爆炸半径)。
  • ❌ “注入故障后不监控” → 必须定义“稳态指标”(如错误率 < 0.1%)。
  • ❌ “开发者需要写混沌代码” → 混沌工程是基础设施层操作。

✅ 加分项/扩展知识:

  • 提到 Gremlin(商业混沌工程平台)。
  • 提到 Chaos Toolkit(开源混沌工程框架)。
  • 提到 “稳态指标”定义(如 SLO:错误率 < 0.1%,延迟 < 500ms)。

🧩 第 14 题:蓝绿部署怎么做?

✅ 题目重述:

在 .NET 微服务中,如何实现“蓝绿部署(Blue-Green Deployment)”?请说明在 Kubernetes 或 Azure App Service 中的具体操作步骤。

✅ 考察意图:

  • 是否理解蓝绿部署的核心价值(零停机发布)
  • 是否掌握 K8s 和 Azure 的具体操作
  • 是否能对比不同平台的实现差异

✅ 理想答案结构:

  1. 什么是蓝绿部署?

    • ✅ 零停机发布
    • ✅ 秒级回滚(切回旧环境)
    • ✅ 生产环境测试(新版本上线前可真实流量验证)
    • 定义:维护两套完全相同的生产环境(Blue 和 Green),一次只有一套对外提供服务。发布新版本时,部署到“非活跃环境”,测试通过后切换流量,实现零停机。
    • 核心价值
  2. 在 Kubernetes 中实现

    • 当前状态:Blue 环境在线(v1)
      # service.yaml —— 当前指向 Blue
      apiVersion:v1
      kind:Service
      metadata:
      name:order-service
      spec:
      selector:
          app:order-service
          version:v1# 流量打到 Blue
    • 部署 Green 环境(v2)
      # green-deployment.yaml
      apiVersion:apps/v1
      kind:Deployment
      metadata:
      name:order-service-green
      spec:
      replicas:3
      selector:
          matchLabels:
            app:order-service
            version:v2
      template:
          metadata:
            labels:
              app:order-service
              version:v2
          spec:
            containers:
            -name:order-service
              image:myapp/order-service:v2
    • 切换流量 → 指向 Green
      # 更新 service.yaml
      spec:
        selector:
          app: order-service
          version: v2  # 切到 Green
      kubectl apply -f service.yaml
  3. 在 Azure App Service 中实现

    • 创建 Staging Slot
      az webapp deployment slot create --name MyApp --resource-group MyRG --slot staging
    • 部署新版本到 Staging Slot
      az webapp deployment source config --name MyApp --resource-group MyRG --slot staging --repo-url <your-git-repo> --branch main
    • 执行“交换”操作(Swap)
      az webapp deployment slot swap --name MyApp --resource-group MyRG --slot staging --target-slot production
  4. 面试回答模板(结构化表达)

    “蓝绿部署是通过维护两套环境(Blue/Green),发布时先部署到非活跃环境,测试通过后切换流量,实现零停机。

    在 .NET 微服务中:

    我们项目用 Azure Slots,因为操作简单、集成 CI/CD、支持自动回滚。”

    • 使用 Deployment Slots(Production/Staging)
    • 部署到 Staging,测试后执行 Swap
    • Azure 自动处理预热和流量切换
    • 用两个 Deployment(label: version=v1/v2)
    • 通过更新 Service 的 selector 切换流量
    • 回滚只需改回 label
    1. Kubernetes 方案
    2. Azure App Service 方案

✅ 常见错误 & 避坑指南:

  • ❌ “蓝绿部署需要双倍资源” → 可在非高峰时段执行,或使用自动扩缩容。
  • ❌ “切换流量会导致用户会话丢失” → 应使用粘性会话或无状态设计。
  • ❌ “蓝绿部署适用于所有场景” → 数据库变更需额外处理(如双写兼容)。

✅ 加分项/扩展知识:

  • 提到 数据库蓝绿部署(如使用双写、影子表)。
  • 提到 Azure Traffic Manager 实现跨区域蓝绿部署。
  • 提到 CI/CD 集成(如 GitHub Actions 自动 Swap)。

🧩 第 15 题:金丝雀发布怎么做?

✅ 题目重述:

在 .NET 微服务中,如何实现“金丝雀发布(Canary Release)”?请说明使用 Istio 或 Flagger 在 Kubernetes 中的流量切分策略。

✅ 考察意图:

  • 是否理解金丝雀发布的渐进式发布思想
  • 是否掌握 Istio 和 Flagger 的配置
  • 是否能结合监控指标实现自动化

✅ 理想答案结构:

  1. 什么是金丝雀发布?

    • ✅ 降低发布风险(有问题只影响小部分用户)
    • ✅ 数据驱动决策(根据真实指标决定是否全量)
    • ✅ 自动化回滚(指标异常时自动切回旧版)
    • 定义:新版本先对一小部分用户/流量开放(如 1%),监控关键指标(错误率、延迟),若正常则逐步扩大比例(5% → 20% → 100%),否则自动回滚。
    • 核心价值
  2. 方案 1:使用 Istio(手动控制流量)

    • 部署 v1 和 v2
      # deployment-v1.yaml
      metadata:
      labels:
          app:order-service
          version:v1
      # deployment-v2.yaml
      metadata:
      labels:
          app:order-service
          version:v2
    • 创建 DestinationRule
      apiVersion: networking.istio.io/v1alpha3
      kind:DestinationRule
      metadata:
      name:order-service
      spec:
      host:order-service
      subsets:
      -name:v1
          labels:
            version:v1
      -name:v2
          labels:
            version:v2
    • 创建 VirtualService(初始 99% → v1, 1% → v2)
      apiVersion: networking.istio.io/v1alpha3
      kind:VirtualService
      metadata:
      name:order-service
      spec:
      hosts:
      -order-service
      http:
      -route:
          -destination:
              host:order-service
              subset:v1
            weight:99
          -destination:
              host:order-service
              subset:v2
            weight:1
  3. 方案 2:使用 Flagger(自动化金丝雀)

    • 安装 Flagger
      helm repo add flagger https://flagger.app
      helm install flagger flagger/flagger --set prometheus.url=http://prometheus:9090
    • 创建 Canary 资源
      apiVersion: flagger.app/v1beta1
      kind:Canary
      metadata:
      name:order-service
      spec:
      targetRef:
          apiVersion:apps/v1
          kind:Deployment
          name:order-service
      progressDeadlineSeconds:60
      service:
          port:80
      analysis:
          interval:1m
          threshold:3
          maxWeight:50
          stepWeight:5
          metrics:
          -name:request-success-rate
            threshold:99
            interval:1m
          -name:request-duration
            threshold:500
            interval:1m
    • 部署新版本
      kubectl set image deployment/order-service order-service=myapp/order-service:v2
  4. 面试回答模板(结构化表达)

    “金丝雀发布是渐进式发布策略,先对小部分流量(如 1%)开放新版本,监控指标正常后再逐步全量。

    在 .NET 微服务中:

    我们项目用 Flagger,因为它自动化程度高,减少人为失误。”

    • 定义 Canary 资源,设置成功率/延迟阈值
    • 部署新版本后,Flagger 自动从 0% → 5% → ... → 100%
    • 指标异常时自动回滚
    • 通过 VirtualService 设置流量权重(如 99% v1 / 1% v2)
    • 人工监控 Prometheus 指标,手动调整权重
    1. Istio 方案
    2. Flagger 方案(推荐)

✅ 常见错误 & 避坑指南:

  • ❌ “金丝雀发布就是 A/B 测试” → A/B 测试侧重功能对比,金丝雀侧重发布安全。
  • ❌ “流量权重随意调整” → 应根据监控指标逐步调整。
  • ❌ “不设置回滚阈值” → 必须定义明确的失败指标(如错误率 > 1%)。

✅ 加分项/扩展知识:

  • 提到 Argo Rollouts(另一种金丝雀发布工具)。
  • 提到 SLO(Service Level Objective) 定义(如“成功率 > 99.9%”)。
  • 提到 人工审批步骤(如 Flagger 的 confirm-promotion webhook)。

🧩 第 16 题:分布式追踪怎么做?

✅ 题目重述:

在 .NET 微服务中,如何实现“分布式追踪(Distributed Tracing)”?请说明使用 OpenTelemetry + Jaeger 的集成步骤和关键概念(如 Span、Trace、Baggage)。

✅ 考察意图:

  • 是否理解分布式追踪的核心价值(可视化调用链)
  • 是否掌握 OpenTelemetry 在 .NET 中的集成
  • 是否理解 Trace、Span、Baggage 等核心概念

✅ 理想答案结构:

  1. 为什么需要分布式追踪?

    • ❓ 哪个服务最慢?
    • ❓ 错误发生在哪个环节?
    • ❓ 调用链是否完整?
    • 在微服务架构中,一个用户请求可能经过多个服务:
      Client → API Gateway → OrderService → PaymentService → InventoryService
    • 传统日志无法直观看出:
  2. 核心概念

    • Trace:一次完整请求的全局唯一 ID(如用户下单)。
    • Span:一个服务内的操作单元(如 OrderService.ProcessOrder)。
    • Baggage:跨服务透传的业务上下文(如 UserIdOrderId)。
  3. .NET 集成 OpenTelemetry + Jaeger

    • 步骤 1:安装 NuGet 包
      dotnet add package OpenTelemetry
      dotnet add package OpenTelemetry.Extensions.Hosting
      dotnet add package OpenTelemetry.Instrumentation.AspNetCore
      dotnet add package OpenTelemetry.Instrumentation.Http
      dotnet add package OpenTelemetry.Exporter.Jaeger
    • 步骤 2:配置 OpenTelemetry
      var builder = WebApplication.CreateBuilder(args);

      builder.Services.AddOpenTelemetry()
          .ConfigureResource(resource => resource
              .AddService("OrderService"))
          .WithTracing(tracing => tracing
              .AddAspNetCoreInstrumentation()
              .AddHttpClientInstrumentation()
              .AddJaegerExporter(options =>
              {
                  options.AgentHost = "localhost";
                  options.AgentPort = 6831;
              }));

      var app = builder.Build();
      app.Run();
    • 步骤 3:部署 Jaeger(本地测试)
      docker run -d --name jaeger \
        -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
        -p 6831:6831/udp \
        -p 16686:16686 \
        jaegertracing/all-in-one:1.50
      → 访问 http://localhost:16686 查看追踪。
  4. 手动创建 Span 和 Baggage

    • 手动创建 Span
      public classOrderService
      {
          privatereadonly Tracer _tracer;
          public OrderService(TracerProvider tracerProvider) => _tracer = tracerProvider.GetTracer("OrderService");

          public async Task ProcessOrderAsync(string orderId)
          {
              usingvar span = _tracer.StartActiveSpan("ProcessOrder");
              span.SetAttribute("order.id", orderId);
              await ValidateOrderAsync(orderId);
              await ChargePaymentAsync(orderId);
              span.End();
          }
      }
    • 使用 Baggage 透传上下文
      // 在 OrderService 中设置 Baggage
      Baggage.SetBaggage("user.id""12345");

      // 在 PaymentService 中读取
      var userId = Baggage.GetBaggage("user.id"); // 自动跨服务传递!
  5. 面试回答模板(结构化表达)

    “分布式追踪用于可视化跨服务调用链,核心概念是 Trace(全局ID)、Span(操作单元)、Baggage(透传上下文)。

    在 .NET 中:

    例如,用户下单请求的 Trace 会显示:API Gateway → OrderService → PaymentService 的完整耗时和错误点。”

    1. 集成 OpenTelemetry SDK:通过 AddAspNetCoreInstrumentation() 自动追踪 HTTP 请求。
    2. 导出到 Jaeger:配置 AddJaegerExporter(),数据发送到 Jaeger UI。
    3. 手动埋点:用 StartActiveSpan() 记录关键方法。
    4. Baggage 透传:用 Baggage.SetBaggage() 传递业务上下文(如 UserId),自动跨服务。

✅ 常见错误 & 避坑指南:

  • ❌ “只追踪入口服务” → 应追踪所有服务,形成完整调用链。
  • ❌ “Baggage 传大量数据” → Baggage 会增加网络开销,只传关键上下文。
  • ❌ “Span 不设置属性” → 应设置 SetAttribute("key", value) 便于过滤和分析。

✅ 加分项/扩展知识:

  • 提到 W3C Trace Context 标准(traceparenttracestate 头)。
  • 提到 Zipkin 作为 Jaeger 替代方案。
  • 提到 自动传播上下文(如通过 HTTP Header)。

🧩 第 17 题:多租户架构怎么设计?

✅ 题目重述:

在 .NET 微服务中,如何实现“多租户(Multi-tenancy)”架构?请说明数据库层面(Shared Schema vs Separate Database)和代码层面(TenantContext)的设计方案。

✅ 考察意图:

  • 是否理解多租户的三种主流模式
  • 是否掌握 .NET 代码层的租户上下文管理
  • 是否能结合数据库和代码实现完整方案

✅ 理想答案结构:

  1. 数据库层面三种模式

    • 同库不同 Schema(如 tenant1.Orderstenant2.Orders)。
    • ✅ 折中方案,租户表独立但同库。
    • ❌ 中等成本,需管理多 Schema。
    • 🎯 适用:中大型 SaaS。
    • 所有租户共享表,每行加 TenantId
    • ✅ 成本低,易维护。
    • ❌ 隔离性弱,需防“TenantId 污染”。
    • 🎯 适用:SaaS、中小租户。
    • 每个租户独立数据库。
    • ✅ 数据完全隔离,安全性高。
    • ❌ 成本高,运维复杂。
    • 🎯 适用:金融、医疗、大客户。
    • Separate Database(分库)
    • Shared Schema(共享表)
    • Separate Schema(分 Schema)
  2. 代码层面:TenantContext 设计

    • 解析租户标识(Middleware):
      app.Use(async (context, next) =>
      {
          var tenantId = context.Request.Headers["X-Tenant-ID"].ToString();
          TenantContext.CurrentTenantId = tenantId;
          await next();
      });
    • EF Core 自动注入 TenantId
      public override int SaveChanges()
      {
          foreach (var entry in ChangeTracker.Entries<ITenantEntity>())
          {
              if (entry.State == EntityState.Added)
                  entry.Entity.TenantId = TenantContext.CurrentTenantId;
          }
          return base.SaveChanges();
      }
    • 查询时自动过滤
      public IQueryable<Order> GetOrders() => _context.Orders
          .Where(o => o.TenantId == TenantContext.CurrentTenantId);
  3. 其他资源的多租户隔离

    • 缓存:Key 中包含 TenantId → cache.Get($"user:{tenantId}:{userId}")
    • 文件存储:路径中包含 TenantId → /tenants/{tenantId}/uploads/...
    • 消息队列:Topic/Queue 按租户隔离 → order-created-tenant1
  4. 面试回答模板(结构化表达)

    “在 .NET 微服务中,多租户架构主要从数据库隔离代码上下文两层实现:

    1. 数据库层面三种模式:

    2. 代码层面:

    3. 配置化切换:

    • 通过配置文件(如 appsettings.json)指定当前租户模式,方便不同客户灵活部署。”
    • 通过 Middleware 从 Header/JWT/Host 解析租户 ID,存入 TenantContext.CurrentTenantId
    • 在 EF Core 中重写 SaveChanges,自动为实体设置 TenantId
    • 缓存、文件存储等资源 Key/Path 中嵌入 TenantId
    • Separate Database:每个租户独立数据库 → 数据隔离性最强,适合金融/医疗等高安全场景。
    • Shared Schema:所有租户共享表,每行加 TenantId → 成本最低,适合中小 SaaS,需严防数据污染。
    • Separate Schema:同库不同 Schema → 折中方案,适合中大型租户。

常见错误 & 避坑指南:

  • ❌ “Shared Schema 不检查 TenantId” → 可能导致数据泄露。
  • ❌ “TenantId 放在全局静态变量” → 在异步/并行场景下会错乱。
  • ❌ “缓存不隔离租户” → 租户 A 可能读到租户 B 的数据。

✅ 加分项/扩展知识:

  • 提到 AsyncLocal 作为 TenantContext 的线程安全实现。
  • 提到 数据库路由中间件(如 EF Core 的 IDbContextFactory)。
  • 提到 租户管理后台(动态创建/删除租户数据库)。

🧩 第 18 题:事件溯源是啥?

✅ 题目重述:

在 .NET 微服务中,如何实现“事件溯源(Event Sourcing)”?请说明与传统 CRUD 的区别,并以订单服务为例描述事件存储和重放机制。

✅ 考察意图:

  • 是否理解事件溯源的核心思想(只存事件,不存状态)
  • 是否能对比传统 CRUD
  • 是否掌握事件存储和重放的实现

✅ 理想答案结构:

  1. 什么是事件溯源?

    • 传统 CRUD:直接读写“当前状态”(如 Order.Status = "Paid")。
    • 事件溯源只存储事件(如 OrderCreatedEventOrderPaidEvent),状态通过重放事件计算得出
  2. 与传统 CRUD 的关键区别

    维度
    传统 CRUD
    事件溯源(Event Sourcing)
    存储内容
    当前状态(如 Status=Paid)
    事件流(OrderCreated, OrderPaid...)
    更新方式
    UPDATE 覆盖
    INSERT 新事件
    查询状态
    直接 SELECT
    重放所有事件 → 计算当前状态
    审计能力
    弱(需额外日志表)
    强(事件即审计日志)
    回滚/时光倒流
    困难
    容易(重放到指定事件)
    复杂度
    高(需事件存储、重放引擎)
  3. 以订单服务为例

    • 使用 EventStoreDBMongoDB 或 SQL Server with JSON
    • 表结构:
      StreamId (OrderId)
      EventId
      EventType
      Data (JSON)
      Timestamp
      order-123
      1
      OrderCreated
      {"Product":"iPhone", "Quantity":1}
      2024-06-01 10:00:00
      order-123
      2
      OrderPaid
      {"Amount":999.0}
      2024-06-01 10:05:00
    • 事件定义
      public abstract record OrderEvent(Guid OrderId, DateTime Timestamp);
      public record OrderCreatedEvent(Guid OrderId, string Product, int Quantity, DateTime Timestamp) : OrderEvent(OrderId, Timestamp);
      public record OrderPaidEvent(Guid OrderId, decimal Amount, DateTime Timestamp) : OrderEvent(OrderId, Timestamp);
    • 事件存储(Event Store):
    • 状态重放
      public classOrder
      {
          public Guid Id { getprivateset; }
          publicstring Status { getprivateset; } = "Pending";
          publicdecimal TotalAmount { getprivateset; }

          public void Replay(IEnumerable<OrderEvent> events)
          {
              foreach (var @eventin events) Apply(@event);
          }

          private void Apply(OrderCreatedEvent e) => Status = "Created";
          private void Apply(OrderPaidEvent e)
          {
              Status = "Paid";
              TotalAmount = e.Amount;
          }
      }

      // 查询状态
      var events = eventStore.LoadEvents("order-123");
      var order = new Order { Id = Guid.Parse("order-123") };
      order.Replay(events);
      Console.WriteLine(order.Status); // 输出 "Paid"
  4. 与 CQRS 结合(加分项)

    • 写模型(Command Side):接收命令 → 生成事件 → 存储事件。
    • 读模型(Query Side):订阅事件 → 更新“物化视图”(如 SQL 表)→ 快速查询。
      public class OrderPaidEventHandler
      {
          public void Handle(OrderPaidEvent e)
          {
              var summary = dbContext.OrderSummaries.Find(e.OrderId);
              summary.Status = "Paid";
              summary.TotalAmount = e.Amount;
              dbContext.SaveChanges();
          }
      }
  5. 面试回答模板(结构化表达)

    “事件溯源是一种数据建模模式,只存储事件,不存储当前状态,状态通过重放事件计算得出。

    与传统 CRUD 的区别:

    以订单服务为例:

    优势:完整审计、支持时光倒流;缺点:复杂度高,适合金融/电商等场景。”

    • CRUD:直接 UPDATE 状态
    • 事件溯源:INSERT 事件,重放重建状态
    1. 定义事件:OrderCreatedEventOrderPaidEvent
    2. 存储到 Event Store(如 EventStoreDB),每个订单一个事件流
    3. 查询状态时,加载所有事件 → 重放到最新 → 得到当前状态
    4. 结合 CQRS:用物化视图优化查询性能

✅ 常见错误 & 避坑指南:

  • ❌ “事件溯源就是事件驱动” → 事件驱动是通信模式,事件溯源是数据存储模式。
  • ❌ “重放事件性能差” → 应结合 CQRS,用物化视图优化查询。
  • ❌ “事件不可变” → 事件一旦存储,绝不修改(可追加补偿事件)。

✅ 加分项/扩展知识:

  • 提到 EventStoreDB(专为事件溯源设计的数据库)。
  • 提到 Snapshotting(定期保存状态快照,避免重放全部事件)。
  • 提到 Event Versioning(事件结构演进,如新增字段)。

🧩 第 19 题:服务网格可观测性怎么做?

✅ 题目重述:

在 .NET 微服务中,如何实现“服务网格的可观测性”?请说明使用 OpenTelemetry 收集 Metrics、Logs、Traces 并导出到 Grafana Tempo/Loki/Prometheus 的配置步骤。

✅ 考察意图:

  • 是否理解“可观测性三件套”(Metrics、Logs、Traces)
  • 是否掌握 OpenTelemetry 统一采集
  • 是否能集成 Grafana 生态

✅ 理想答案结构:

  1. 什么是服务网格的可观测性?

    • 📊 Metrics:QPS、延迟、错误率(用 Prometheus)
    • 📝 Logs:错误日志、调试信息(用 Loki)
    • 🔗 Traces:跨服务调用链(用 Tempo)
    • 在服务网格(如 Istio、Linkerd、Dapr)中,Sidecar 代理自动处理服务间通信,但开发者仍需监控:
  2. .NET 集成 OpenTelemetry + Grafana 三件套

    • 步骤 1:安装 NuGet 包
      dotnet add package OpenTelemetry
      dotnet add package OpenTelemetry.Extensions.Hosting
      dotnet add package OpenTelemetry.Instrumentation.AspNetCore
      dotnet add package OpenTelemetry.Instrumentation.Http
      dotnet add package OpenTelemetry.Exporter.Prometheus
      dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
    • 步骤 2:配置 OpenTelemetry
      var builder = WebApplication.CreateBuilder(args);

      builder.Services.AddOpenTelemetry()
          .ConfigureResource(resource => resource.AddService("OrderService"))
          
          // 启用 Tracing
          .WithTracing(tracing => tracing
              .AddAspNetCoreInstrumentation()
              .AddHttpClientInstrumentation()
              .AddOtlpExporter(options => options.Endpoint = new Uri("http://localhost:4317")))

          // 启用 Metrics
          .WithMetrics(metrics => metrics
              .AddAspNetCoreInstrumentation()
              .AddHttpClientInstrumentation()
              .AddPrometheusExporter())

          // 启用 Logging(通过 Serilog)
          .UseSerilog((ctx, config) => config
              .WriteTo.OpenTelemetry(options =>
              {
                  options.Endpoint = "http://localhost:4317";
                  options.ResourceAttributes = new Dictionary<stringobject>
                  {
                      ["service.name"] = "OrderService"
                  };
              }));

      var app = builder.Build();
      app.MapPrometheusScrapingEndpoint(); // 暴露 Prometheus 指标端点
      app.Run();
    • 步骤 3:部署 Grafana + Prometheus + Loki + Tempo(本地 Docker)
      # docker-compose.yml
      version:'3'
      services:
      prometheus:
          image:prom/prometheus
          ports:["9090:9090"]
      loki:
          image:grafana/loki:latest
          ports:["3100:3100"]
      tempo:
          image:grafana/tempo:latest
          command:["-config.file=/etc/tempo.yaml"]
          ports:["4317:4317"]
      grafana:
          image:grafana/grafana
          ports:["3000:3000"]
          environment:
            -GF_AUTH_ANONYMOUS_ENABLED=true
            -GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
  3. 在 Grafana 中创建仪表盘

    • Metrics:显示 QPS、错误率(Prometheus)。
    • Logs:搜索错误日志(Loki)。
    • Traces:查看调用链(Tempo)。
    • 添加数据源:Prometheus、Loki、Tempo。
    • 创建仪表盘:
  4. 面试回答模板(结构化表达)

    “服务网格的可观测性指统一监控 Metrics、Logs、Traces。

    在 .NET 中:

    例如,发现错误率上升时,可直接在 Grafana 中跳转到对应 Trace 和 Logs,快速定位问题。”

    • Metrics → Prometheus(通过 /metrics 端点)
    • Traces → Tempo(通过 OTLP 协议)
    • Logs → Loki(通过 OTEL Collector)
    • AddAspNetCoreInstrumentation() 自动采集指标和链路
    • Serilog + OpenTelemetry Exporter 采集日志
    1. 用 OpenTelemetry SDK
    2. 导出到 Grafana 生态
    3. Grafana 统一展示:一个仪表盘同时查看指标、日志、调用链。

✅ 常见错误 & 避坑指南:

  • ❌ “只采集 Metrics” → 应三件套齐全。
  • ❌ “OTLP 端口配置错误” → Tempo 默认端口 4317。
  • ❌ “Grafana 数据源未配置” → 需手动添加 Prometheus/Loki/Tempo。

✅ 加分项/扩展知识:

  • 提到 OpenTelemetry Collector(统一接收、处理、导出遥测数据)。
  • 提到 Grafana Agent(轻量级数据采集器)。
  • 提到 仪表盘模板(如 Kubernetes Mixin、微服务模板)。

🧩 第 20 题:Serverless 怎么选?

✅ 题目重述:

在 .NET 微服务中,如何实现“Serverless 部署”?请说明使用 Azure Functions 或 AWS Lambda 托管 .NET 微服务的优缺点及适用场景。

✅ 考察意图:

  • 是否理解 Serverless 的核心价值(无服务器运维、按需付费)
  • 是否掌握 Azure Functions 和 AWS Lambda 的 .NET 集成
  • 是否能根据场景选择合适方案

✅ 理想答案结构:

  1. 什么是 Serverless?

    • ✅ 零运维(不用管服务器、K8s)
    • ✅ 自动扩缩容(从 0 到 1000 实例秒级扩展)
    • ✅ 低成本(无流量时不花钱)
    • 定义:开发者只写函数代码,云平台自动管理服务器、扩缩容、运维。
    • 计费模式:按执行次数 + 执行时长付费,闲置不收费。
    • 核心价值
  2. Azure Functions(微软亲儿子,.NET 最佳体验)

    • ❌ 绑定 Azure 生态(非 Azure 项目不适用)
    • ❌ 冷启动延迟(约 1~5 秒,Premium 计划可缓解)
    • ✅ .NET 原生支持(最新 .NET 8 已支持)
    • ✅ Visual Studio 集成(一键调试/发布)
    • ✅ 无缝集成 Azure 服务(Event Grid、Service Bus、Cosmos DB)
    • 创建步骤
      func init MyFunctionApp --dotnet
      cd MyFunctionApp
      func new --name OrderProcessor --template "HTTP trigger"
    • 编写函数
      public static class OrderProcessor
      {
          [FunctionName("OrderProcessor")]
          public static async Task<IActionResult> Run(
              [HttpTrigger(AuthorizationLevel.Function, "post", Route = "orders"
      )] HttpRequest req,
              ILogger log)

          {
              log.LogInformation("Processing order...");
              var requestBody = await new StreamReader(req.Body).ReadToEndAsync();
              return new OkObjectResult("Order processed!");
          }
      }
    • 优点
    • 缺点
    • 适用场景:事件驱动(如 Blob 上传触发处理)、Webhook 处理、定时任务。
  3. AWS Lambda(多语言,生态广)

    • ❌ 冷启动更慢(.NET 尤其明显,约 3~10 秒)
    • ❌ 调试复杂(需 AWS Toolkit 或 SAM CLI)
    • ❌ Vendor Lock-in(深度绑定 AWS)
    • ✅ 多语言支持(.NET/Python/Node.js/Go...)
    • ✅ 庞大生态(API Gateway、DynamoDB、S3 触发器)
    • ✅ 全球可用区
    • 创建步骤
      dotnet new lambda.EmptyFunction --name MyLambdaFunction
      dotnet lambda deploy-function MyLambdaFunction
    • 编写函数
      public class Function
      {
          public async Task<stringFunctionHandler(string input, ILambdaContext context)
          {
              context.Logger.LogLine($"Processing: {input}");
              return $"Processed: {input}";
          }
      }
    • 优点
    • 缺点
    • 适用场景:S3 文件处理、API Gateway 后端、DynamoDB 流触发。
  4. Serverless vs 微服务容器化(K8s)对比

    维度
    Serverless(Functions)
    微服务(K8s 容器)
    运维复杂度
    ✅ 零运维
    ❌ 需管理 K8s 集群
    扩缩容速度
    ✅ 秒级(0 → 1000 实例)
    ⚠️ 分钟级(需调度 Pod)
    成本
    ✅ 无流量不收费
    ❌ 常驻 Pod 即使空闲也计费
    冷启动
    ❌ 有延迟(1~10 秒)
    ✅ 无(Pod 常驻)
    适用场景
    事件驱动、突发流量、短任务
    长连接、复杂业务、高稳定性
  5. 面试回答模板(结构化表达)

    “Serverless 是无服务器架构,开发者只关注函数代码,云平台自动扩缩容。

    在 .NET 中:

    我们选 Azure Functions,因为项目在 Azure 上,且 .NET 体验最佳。但核心服务仍用 K8s 容器,避免冷启动影响用户体验。”

    • 多语言支持,生态庞大
    • 适合 S3/API Gateway 场景
    • 缺点:.NET 冷启动更慢,调试复杂
    • 原生 .NET 支持,Visual Studio 无缝集成
    • 适合事件驱动(如 Blob 触发、Service Bus 消息)
    • 缺点:冷启动延迟,绑定 Azure
    1. Azure Functions
    2. AWS Lambda

✅ 常见错误 & 避坑指南:

  • ❌ “Serverless 适合所有场景” → 不适合长连接、高稳定性要求的服务。
  • ❌ “冷启动可以忽略” → 对用户体验敏感的场景(如 API)需优化。
  • ❌ “Serverless 一定更便宜” → 高流量场景可能比 K8s 更贵。

✅ 加分项/扩展知识:

  • 提到 Azure Functions Premium Plan(预热实例,减少冷启动)。
  • 提到 AWS Lambda SnapStart(.NET 8 支持,加速冷启动)。
  • 提到 KEDA(Kubernetes Event-driven Autoscaling) —— 在 K8s 上实现 Serverless 扩缩容。

🐳 第 21 题:如何为 .NET 微服务编写 Dockerfile?

✅ 题目重述:

请为一个 ASP.NET Core 微服务编写生产级 Dockerfile,并说明关键优化点。

✅ 考察意图:

  • 是否掌握多阶段构建(Multi-stage Build)
  • 是否理解安全最佳实践(非 root 用户)
  • 是否会添加健康检查、精简镜像

✅ 理想答案结构:

  1. 为什么需要优化 Dockerfile?

    • 减少镜像体积 → 加快拉取和部署
    • 提升安全性 → 避免 root 权限运行
    • 增强可观测性 → 添加健康检查
  2. 生产级 Dockerfile 示例

    # === 阶段1:构建 ===
    FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
    WORKDIR /src
    COPY . .
    RUN dotnet restore
    RUN dotnet publish -c Release -o /app --no-restore

    # === 阶段2:运行 ===
    FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
    WORKDIR /app
    COPY --from=build /app .

    # 安全:使用非 root 用户
    RUN adduser --disabled-password --gecos '' appuser && chown -R appuser /app
    USER appuser

    # 健康检查(供 K8s 使用)
    HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
        CMD curl -f http://localhost:80/health || exit 1


    # 暴露端口
    EXPOSE80

    # 启动命令
    ENTRYPOINT ["dotnet""OrderService.dll"]
  3. 关键优化点详解

    • --no-restore → 避免重复 restore。
    • 不安装额外工具(如 curl 需单独安装)。
    • HEALTHCHECK → 供 K8s 判断容器是否健康。
    • USER appuser → 避免容器内提权攻击。
    • sdk 镜像仅用于构建,aspnet 镜像用于运行 → 减少最终镜像体积(从 1.8GB → 200MB)。
    • 多阶段构建
    • 非 root 用户
    • 健康检查
    • 精简依赖
  4. .NET 特定优化

    • 使用 --self-contained false(默认)→ 依赖基础镜像的运行时。
    • 使用 DOTNET_RUNNING_IN_CONTAINER=true → 优化 .NET 在容器中的行为。
  5. 面试回答模板

    “我为 .NET 微服务编写的 Dockerfile 遵循生产级最佳实践:

    示例中,最终镜像仅包含运行时和发布文件,体积约 200MB,启动时间 < 1s。”

    1. 多阶段构建:用 sdk 镜像构建,aspnet 镜像运行,体积减少 90%。
    2. 安全加固:创建 appuser 并切换,避免 root 权限。
    3. 健康检查:添加 HEALTHCHECK,供 K8s 使用。
    4. 精简优化:不安装无关工具,使用 --no-restore 加速构建。

✅ 常见错误 & 避坑指南:

  • ❌ “用 sdk 镜像直接运行” → 镜像体积过大。
  • ❌ “不添加 HEALTHCHECK” → K8s 无法判断服务健康。
  • ❌ “用 root 用户运行” → 安全风险。

✅ 加分项/扩展知识:

  • 提到 Docker BuildKit(加速构建):
    DOCKER_BUILDKIT=1 docker build -t myapp .
  • 提到 多架构支持(如 Linux ARM64):
    FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
  • 提到 .dockerignore(排除无关文件):
    **/.git
    **/.vs
    **/bin
    **/obj

🐳 第 22 题:如何用 K8s 部署 .NET 微服务?

✅ 题目重述:

请编写 Kubernetes YAML 文件,部署一个 .NET 微服务(包含 Deployment、Service、Ingress)。

✅ 考察意图:

  • 是否掌握 K8s 核心对象(Deployment、Service、Ingress)
  • 是否理解标签选择器(Label Selector)机制
  • 是否会配置资源限制和健康检查

✅ 理想答案结构:

  1. Deployment(管理 Pod 副本)

    # deployment.yaml
    apiVersion:apps/v1
    kind:Deployment
    metadata:
    name:order-service
    labels:
        app:order-service
    spec:
    replicas:3
    selector:
        matchLabels:
          app:order-service
    template:
        metadata:
          labels:
            app:order-service
        spec:
          containers:
          -name:order-service
            image:myregistry.azurecr.io/order-service:latest
            ports:
            -containerPort:80
            env:
            -name:ASPNETCORE_ENVIRONMENT
              value:"Production"
            resources:
              limits:
                memory:"512Mi"
                cpu:"500m"
              requests:
                memory:"256Mi"
                cpu:"250m"
            livenessProbe:
              httpGet:
                path:/health
                port:80
              initialDelaySeconds:10
              periodSeconds:5
            readinessProbe:
              httpGet:
                path:/health
                port:80
              initialDelaySeconds:5
              periodSeconds:3
  2. Service(暴露服务)

    # service.yaml
    apiVersion:v1
    kind:Service
    metadata:
    name:order-service
    spec:
    selector:
        app:order-service
    ports:
    -protocol:TCP
        port:80
        targetPort:80
    type:ClusterIP# 或 LoadBalancer
  3. Ingress(外部访问)

    # ingress.yaml
    apiVersion:networking.k8s.io/v1
    kind:Ingress
    metadata:
    name:order-service-ingress
    annotations:
        nginx.ingress.kubernetes.io/rewrite-target:/
    spec:
    rules:
    -host:orders.myapp.com
        http:
          paths:
          -path:/
            pathType:Prefix
            backend:
              service:
                name:order-service
                port:
                  number:80
  4. 关键配置说明

    • 资源限制:避免 Pod 占用过多资源。
    • 健康检查livenessProbe(是否重启)、readinessProbe(是否接收流量)。
    • 标签选择器:Deployment → Pod,Service → Pod 通过 app: order-service 关联。
  5. 面试回答模板

    “我用三个 YAML 文件部署 .NET 微服务:

    关键点:

    • 健康检查路径 /health(需在 .NET 中实现)
    • 资源限制避免 Pod 飙升
    • 标签选择器确保 Service 正确关联 Pod”
    1. Deployment:定义 3 个副本,设置资源限制和健康检查(liveness/readiness)。
    2. Service:通过 selector 关联 Pod,暴露端口 80。
    3. Ingress:配置域名 orders.myapp.com,路由到 Service。

✅ 常见错误 & 避坑指南:

  • ❌ “不设置资源限制” → Pod 可能被 K8s 驱逐。
  • ❌ “健康检查路径错误” → Pod 无限重启。
  • ❌ “Service selector 不匹配 Pod labels” → 服务无法访问。

✅ 加分项/扩展知识:

  • 提到 HorizontalPodAutoscaler(HPA)(自动扩缩容)。
  • 提到 ConfigMap/Secret(外部化配置)。
  • 提到 Init Containers(初始化任务,如数据库迁移)。

🐳 第 23 题:如何实现 K8s 自动扩缩容(HPA)?

✅ 题目重述:

如何为 .NET 微服务配置 Kubernetes HPA(Horizontal Pod Autoscaler)?请说明基于 CPU 和自定义指标的配置。

✅ 考察意图:

  • 是否理解 HPA 的工作原理
  • 是否会配置 CPU/内存指标
  • 是否了解自定义指标(如 QPS)

✅ 理想答案结构:

  1. HPA 是什么?

    • 根据指标(CPU、内存、自定义)自动调整 Pod 副本数。
    • 目标:应对流量高峰,节省资源。
  2. 基于 CPU 的 HPA

    # hpa-cpu.yaml
    apiVersion:autoscaling/v2
    kind:HorizontalPodAutoscaler
    metadata:
    name:order-service-hpa
    spec:
    scaleTargetRef:
        apiVersion:apps/v1
        kind:Deployment
        name:order-service
    minReplicas:1
    maxReplicas:10
    metrics:
    -type:Resource
        resource:
          name:cpu
          target:
            type:Utilization
            averageUtilization:70# CPU 使用率 > 70% 时扩容
  3. 基于自定义指标(如 QPS)的 HPA

    • 需安装 Prometheus Adapter 和 Custom Metrics API
    • 配置:
      # hpa-custom.yaml
      apiVersion:autoscaling/v2
      kind:HorizontalPodAutoscaler
      metadata:
      name:order-service-hpa
      spec:
      scaleTargetRef:
          apiVersion:apps/v1
          kind:Deployment
          name:order-service
      minReplicas:1
      maxReplicas:10
      metrics:
      -type:Pods
          pods:
            metric:
              name:http_requests_per_second# 需在 Prometheus 中定义
            target:
              type:AverageValue
              averageValue:100# 每个 Pod > 100 QPS 时扩容
  4. 在 .NET 中暴露自定义指标

    • 使用 OpenTelemetry + Prometheus Exporter:
      services.AddOpenTelemetry()
          .WithMetrics(metrics => metrics
              .AddAspNetCoreInstrumentation()
              .AddPrometheusExporter());
    • 暴露端点:http://<pod-ip>:9090/metrics
  5. 面试回答模板

    “我为 .NET 微服务配置 HPA 分两种:

    示例中,当每个 Pod QPS > 100 时,HPA 自动扩容,峰值可到 10 个副本。”

    • 用 OpenTelemetry 暴露 http_requests_per_second 指标。
    • 通过 Prometheus Adapter 导入 K8s。
    • 配置 HPA 监控该指标。
    1. 基于 CPU:设置 averageUtilization: 70,CPU > 70% 时自动扩容。
    2. 基于自定义指标(如 QPS)

✅ 常见错误 & 避坑指南:

  • ❌ “不设置 min/max replicas” → 可能扩到无限或缩到 0。
  • ❌ “自定义指标未暴露” → HPA 无法获取数据。
  • ❌ “指标名称错误” → 检查 Prometheus 中的指标名。

✅ 加分项/扩展知识:

  • 提到 KEDA(Kubernetes Event-driven Autoscaler) → 支持事件驱动扩缩容(如 Kafka 队列长度)。
  • 提到 Vertical Pod Autoscaler(VPA) → 自动调整 CPU/内存请求。
  • 提到 HPA 行为调优(如 behavior.scaleDown.stabilizationWindowSeconds)。

🐳 第 24 题:如何用 ConfigMap 和 Secret 管理配置?

✅ 题目重述:

在 Kubernetes 中,如何使用 ConfigMap 和 Secret 管理 .NET 微服务的配置?请给出挂载为文件和环境变量的示例。

✅ 考察意图:

  • 是否理解 ConfigMap(明文) vs Secret(密文)
  • 是否会挂载为文件或环境变量
  • 是否能结合 .NET Configuration 系统

✅ 理想答案结构:

  1. ConfigMap(存储非敏感配置)

    # configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: app-config
    data:
      appsettings.json: |
        {
          "Logging": {
            "LogLevel": "Debug"
          },
          "FeatureFlags": {
            "NewCheckout": true
          }
        }
  2. Secret(存储敏感配置)

    # secret.yaml
    apiVersion:v1
    kind:Secret
    metadata:
    name:app-secret
    type:Opaque
    data:
    ConnectionStrings__DefaultConnection:<base64-encoded-connection-string>
    Jwt__Secret:<base64-encoded-jwt-secret>
  3. 挂载为文件(推荐)

    # deployment.yaml
    spec:
    containers:
    -name:order-service
        volumeMounts:
        -name:config-volume
          mountPath:/app/config
        -name:secret-volume
          mountPath:/app/secrets
    volumes:
    -name:config-volume
        configMap:
          name:app-config
    -name:secret-volume
        secret:
          secretName:app-secret
    • 在 .NET 中读取:
      builder.Configuration
          .AddJsonFile("/app/config/appsettings.json")
          .AddJsonFile("/app/secrets/secrets.json"); // 需将 Secret 转为 JSON 文件
  4. 挂载为环境变量

    # deployment.yaml
    spec:
    containers:
    -name:order-service
        env:
        -name:ConnectionStrings__DefaultConnection
          valueFrom:
            secretKeyRef:
              name:app-secret
              key:ConnectionStrings__DefaultConnection
        -name:Logging__LogLevel
          valueFrom:
            configMapKeyRef:
              name:app-config
              key:Logging__LogLevel
    • .NET 自动绑定环境变量(__ 替换为 :)。
  5. 面试回答模板

    “我用 ConfigMap 存非敏感配置(如日志级别),Secret 存敏感数据(如连接字符串)。

    两种挂载方式:

    推荐挂载为文件,因为:

    • 支持复杂 JSON 结构
    • 变更后无需重启 Pod(需配合 subPath 或工具)”
    1. 挂载为文件:ConfigMap/Secret → Volume → 容器内文件 → .NET 读取 JSON。
    2. 挂载为环境变量:直接注入环境变量 → .NET 自动绑定(__ 转 :)。

✅ 常见错误 & 避坑指南:

  • ❌ “用 Secret 存非敏感数据” → Secret 有额外加密开销。
  • ❌ “环境变量名不匹配 .NET 配置” → 需用 __ 分隔(如 ConnectionStrings__Default)。
  • ❌ “挂载文件后不读取” → 需在 .NET 中 AddJsonFile()

✅ 加分项/扩展知识:

  • 提到 Reloader(自动重启 Pod 当 ConfigMap/Secret 变更)。
  • 提到 External Secrets Operator(从 AWS Secrets Manager/Azure Key Vault 同步 Secret)。
  • 提到 Helm 管理 ConfigMap/Secret(模板化)。

🐳 第 25 题:如何实现 K8s 服务的滚动更新和回滚?

✅ 题目重述:

如何配置 Kubernetes Deployment 实现滚动更新?如何回滚到上一版本?

✅ 考察意图:

  • 是否理解滚动更新策略(RollingUpdate)
  • 是否会配置 maxSurge/maxUnavailable
  • 是否掌握回滚命令

✅ 理想答案结构:

  1. 滚动更新配置

    # deployment.yaml
    spec:
    strategy:
        type:RollingUpdate
        rollingUpdate:
          maxSurge:1        # 允许超出期望副本数的最大值(如 3+1=4)
          maxUnavailable:0# 更新时不可用副本最大值(0=无停机)
    template:
        metadata:
          labels:
            app:order-service
            version:v2# 更新镜像时修改此标签
        spec:
          containers:
          -name:order-service
            image:myregistry/order-service:v2# 更新此版本
  2. 执行更新

    # 修改 deployment.yaml 后
    kubectl apply -f deployment.yaml

    # 或直接更新镜像
    kubectl set image deployment/order-service order-service=myregistry/order-service:v2
  3. 监控更新状态

    kubectl rollout status deployment/order-service
    kubectl get pods -l app=order-service # 查看新旧 Pod 交替
  4. 回滚到上一版本

    kubectl rollout undo deployment/order-service
    kubectl rollout history deployment/order-service # 查看历史版本
  5. 面试回答模板

    “我通过配置 strategy: RollingUpdate 实现零停机更新:

    更新时:

    回滚:kubectl rollout undo,秒级恢复。”

    • maxSurge: 1:允许临时多 1 个 Pod。
    • maxUnavailable: 0:确保始终有 3 个可用 Pod。
    1. 修改 image 或 template.labels.version
    2. kubectl apply 或 kubectl set image
    3. kubectl rollout status 监控进度。

✅ 常见错误 & 避坑指南:

  • ❌ “不设置 rollingUpdate 策略” → 默认策略可能造成停机。
  • ❌ “maxUnavailable 设置过大” → 用户可能遇到 503 错误。
  • ❌ “回滚时不检查历史版本” → 可能回滚到错误版本。

✅ 加分项/扩展知识:

  • 提到 Blue-Green Deployment with Service Selector(通过切换 Service 标签实现)。
  • 提到 Canary Deployment with Istio/Flagger
  • 提到 Argo Rollouts(高级渐进式交付)。


🐳 第 26 题:请列举 5 个常用 Docker 命令并说明其作用。

✅ 题目重述:

在日常开发和部署中,你最常用的 Docker 命令有哪些?请列举并说明用途。

✅ 考察意图:

  • 是否有实际 Docker 使用经验
  • 是否理解镜像、容器、仓库等核心概念
  • 是否能区分构建、运行、调试等不同场景命令

✅ 理想答案结构:

  1. docker build -t <镜像名> .

    • 作用:根据当前目录的 Dockerfile 构建镜像。
    • 示例docker build -t myapp:latest .
  2. docker run -d -p 8080:80 --name mycontainer myapp:latest

    • 作用:以后台模式运行容器,映射端口,指定容器名。
    • 示例docker run -d -p 8080:80 --name order-svc myapp:latest
  3. docker ps / docker ps -a

    • 作用:查看正在运行的容器 / 查看所有容器(包括已停止)。
    • 示例docker ps → 查看当前运行的服务。
  4. docker logs <容器名或ID>

    • 作用:查看容器日志,用于调试。
    • 示例docker logs order-svc --tail 50 -f(查看最后50行并持续跟踪)
  5. docker exec -it <容器名> /bin/bash

    • 作用:进入运行中的容器执行命令(如调试、查配置)。
    • 示例docker exec -it order-svc /bin/bash

✅ 常见错误 & 避坑指南:

  • ❌ 混淆 docker run 和 docker start → run 是创建+启动,start 是启动已停止容器。
  • ❌ 忘记 -d 后台运行 → 容器前台运行会阻塞终端。
  • ❌ 不指定 --name → 容器名随机,难管理。

✅ 加分项/扩展知识:

  • docker-compose up -d:一键启动多容器应用(如 .NET + Redis + SQL Server)。
  • docker image prune:清理无用镜像。
  • docker system df:查看 Docker 磁盘使用情况。

🐳 第 27 题:Kubernetes 的核心组件有哪些?请简要说明其作用。

✅ 题目重述:

请描述 Kubernetes 集群的核心组件及其功能。

✅ 考察意图:

  • 是否理解 K8s 架构(控制平面 vs 数据平面)
  • 是否掌握 Master/Node 组件职责
  • 是否能说出关键组件如 API Server、Scheduler 等

✅ 理想答案结构:

Kubernetes 集群分为 控制平面(Control Plane) 和 数据平面(Data Plane)

▶ 控制平面(Master 节点):

  1. API Server

    • 集群的“前端”,所有操作(kubectl、UI、控制器)都通过它。
    • 提供 REST API,验证并处理请求。
  2. etcd

    • 分布式键值存储,保存集群所有状态(如 Deployment、Pod 配置)。
    • K8s 的“数据库”。
  3. Scheduler

    • 决定 Pod 调度到哪个 Node 上(基于资源、亲和性等策略)。
  4. Controller Manager

    • 运行控制器(如 Deployment Controller、Node Controller),确保集群状态符合期望。

▶ 数据平面(Worker 节点):

  1. kubelet

    • Node 上的“代理”,负责启动/停止容器,向 API Server 上报状态。
  2. kube-proxy

    • 维护网络规则,实现 Service 的负载均衡和网络代理。
  3. Container Runtime(如 containerd、Docker):

    • 实际运行容器的引擎(Docker 已被 containerd 取代)。

✅ 常见错误 & 避坑指南:

  • ❌ “Docker 是 K8s 必需组件” → K8s 1.24+ 默认使用 containerd。
  • ❌ “Scheduler 负责网络” → 网络是 kube-proxy 和 CNI 插件的职责。
  • ❌ “etcd 可有可无” → etcd 是集群状态存储,必须高可用。

✅ 加分项/扩展知识:

  • 提到 Cloud Controller Manager(对接云厂商 API,如 LoadBalancer)。
  • 提到 DNS(CoreDNS):集群内服务发现。
  • 提到 CNI 插件(如 Calico、Flannel):负责 Pod 网络。

🐳 第 28 题:Kubernetes 中的最小调度单元是什么?它和容器的关系是什么?

✅ 题目重述:

Kubernetes 中最小的可部署和管理单元是什么?它包含什么?和容器的关系是?

✅ 考察意图:

  • 是否理解 Pod 是 K8s 最小单元
  • 是否知道 Pod 可包含多个容器
  • 是否理解“同生共死”的共享上下文

✅ 理想答案结构:

  1. 最小单元是 Pod

    • Pod 是 K8s 中最小的部署和调度单元
    • 一个 Pod 可以包含一个或多个容器(通常是一个主容器 + 辅助容器)。
  2. Pod 和容器的关系

    • 共享网络:Pod 内所有容器共享同一个 IP 和端口空间。
    • 共享存储:可通过 volume 共享文件系统。
    • 同生共死:Pod 被调度到 Node 上,所有容器一起启动/停止。
  3. 典型场景

    • 主容器(如 .NET App) + 辅助容器(如日志收集器、监控代理)。
    • 示例:ASP.NET Core + Nginx(反向代理)放在同一个 Pod。

✅ 常见错误 & 避坑指南:

  • ❌ “容器是 K8s 最小单元” → 容器必须放在 Pod 中。
  • ❌ “一个 Pod 只能有一个容器” → 可多个,但需合理设计。
  • ❌ “Pod 内容器可独立扩缩容” → Pod 是原子单元,扩缩容以 Pod 为单位。

✅ 加分项/扩展知识:

  • 提到 Init Containers:在主容器启动前运行的初始化容器。
  • 提到 Sidecar Pattern:如 Istio Proxy、Dapr Sidecar。
  • 提到 Pod Security Context:设置容器运行权限。

🐳 第 29 题:请描述 Pod 的生命周期(从创建到销毁)。

✅ 题目重述:

一个 Pod 从被创建到最终销毁,会经历哪些状态?请简述其生命周期。

✅ 考察意图:

  • 是否理解 Pod 状态流转(Pending → Running → Succeeded/Failed)
  • 是否知道 Init Containers、Readiness/Liveness Probe 的作用时机
  • 是否能解释 CrashLoopBackOff 等常见状态

✅ 理想答案结构:

Pod 生命周期状态流转:

  1. Pending

    • Pod 已被 API Server 接受,但尚未调度到 Node,或镜像正在拉取。
    • 常见原因:资源不足、镜像拉取慢。
  2. ContainerCreating

    • Scheduler 已分配 Node,kubelet 正在创建容器(拉镜像、启容器)。
  3. Running

    • 所有容器已启动,且至少一个容器仍在运行。
    • 如果配置了 readinessProbe,需通过后才接收流量。
  4. Succeeded

    • Pod 中所有容器正常退出(如 Job/CronJob 完成)。
  5. Failed

    • Pod 中至少一个容器异常退出(非 0 状态码)。
  6. Unknown

    • kubelet 失联,状态未知(如 Node 宕机)。

⚠️ 常见异常状态:

  • CrashLoopBackOff:容器反复崩溃重启(如程序启动失败)。
  • ImagePullBackOff:镜像拉取失败(如镜像名错误、私有仓库未授权)。

✅ 常见错误 & 避坑指南:

  • ❌ “Running 状态 = 可接收流量” → 需通过 readinessProbe
  • ❌ “Pod 失败后自动修复” → 需靠 Deployment 等控制器重建。
  • ❌ “忽略 Init Containers 状态” → Init Containers 失败会导致 Pod 卡在 Init:Error

✅ 加分项/扩展知识:

  • 提到 Pod Conditions(如 PodScheduledContainersReady)。
  • 提到 Startup Probe(K8s 1.18+,用于慢启动应用)。
  • 提到 kubectl describe pod <pod-name> 查看事件和状态详情。

🐳 第 30 题:如何查看 K8s 集群中所有 Pod 的状态?如何进入 Pod 执行命令?

✅ 题目重述:

请写出查看 Pod 状态和进入 Pod 执行命令的 kubectl 命令。

✅ 考察意图:

  • 是否掌握日常运维命令
  • 是否会调试运行中的 Pod
  • 是否理解命名空间(Namespace)概念

✅ 理想答案结构:

  1. 查看所有 Pod 状态

    # 查看默认命名空间的 Pod
    kubectl get pods

    # 查看所有命名空间的 Pod
    kubectl get pods -A

    # 查看指定命名空间的 Pod(如 production)
    kubectl get pods -n production

    # 查看 Pod 详细状态(事件、IP、Node)
    kubectl describe pod <pod-name> -n <namespace>
  2. 进入 Pod 执行命令

    # 进入 Pod 的 shell(需容器内有 bash/sh)
    kubectl exec -it <pod-name> -n <namespace> -- /bin/bash

    # 在 Pod 中执行单条命令(如查看环境变量)
    kubectl exec <pod-name> -n <namespace> -- env

    # 如果 Pod 有多个容器,需指定容器名
    kubectl exec -it <pod-name> -c <container-name> -- /bin/bash

✅ 常见错误 & 避坑指南:

  • ❌ 忘记 -n 指定命名空间 → 默认查 default 命名空间。
  • ❌ 容器内无 bash → 改用 shkubectl exec -it <pod> -- sh
  • ❌ Pod 未 Running → 无法 exec,需先查状态。

✅ 加分项/扩展知识:

  • kubectl get pods -o wide:显示 Node、IP 等额外信息。
  • kubectl logs -f <pod> -c <container>:跟踪指定容器日志。
  • kubectl top pod:查看 Pod 资源使用(需 Metrics Server)。

🐳 第 31 题:Kubernetes 中的 Service 有什么作用?有哪些类型?

✅ 题目重述:

为什么需要 Service?它有哪些类型?分别适用于什么场景?

✅ 考察意图:

  • 是否理解 Service 解决 Pod IP 不稳定的问题
  • 是否掌握 ClusterIP、NodePort、LoadBalancer 的区别
  • 是否会为 .NET 微服务选择合适的 Service 类型

✅ 理想答案结构:

  1. Service 的作用

    • 为一组 Pod 提供稳定的网络端点(IP + Port)。
    • 通过标签选择器(Label Selector)动态关联 Pod。
    • 实现负载均衡和服务发现。
  2. Service 类型

    类型
    作用
    适用场景
    ClusterIP
    集群内部访问(默认类型)
    微服务间调用(如 Order → Payment)
    NodePort
    通过 Node IP + 端口(30000-32767)从集群外部访问
    开发测试、无 LB 环境
    LoadBalancer
    云厂商提供外部负载均衡器(如 AWS ELB、Azure Load Balancer)
    生产环境对外暴露服务
    ExternalName
    将 Service 映射到外部 DNS 名称(如 database.example.com)
    访问外部服务
  3. .NET 微服务场景

    • 内部服务间调用 → ClusterIP
    • 对外 API → LoadBalancer(生产)或 NodePort(测试)

✅ 常见错误 & 避坑指南:

  • ❌ “Service IP 是 Pod IP” → Service IP 是虚拟 IP,由 kube-proxy 实现转发。
  • ❌ “NodePort 可用于生产” → 端口范围受限,无健康检查,不推荐。
  • ❌ “LoadBalancer 在本地 Minikube 无效” → Minikube 需用 minikube tunnel

✅ 加分项/扩展知识:

  • 提到 Headless ServiceclusterIP: None)→ 用于 StatefulSet 或 DNS 直接解析 Pod IP。
  • 提到 Ingress vs Service → Ingress 管理 L7 路由,Service 管理 L4 负载均衡。
  • 提到 Service Mesh(如 Istio)可替代部分 Service 功能。

🐳 第 32 题:什么是 ConfigMap 和 Secret?它们有什么区别?

✅ 题目重述:

请解释 ConfigMap 和 Secret 的用途和区别。

✅ 考察意图:

  • 是否理解配置管理的重要性
  • 是否能区分敏感与非敏感数据
  • 是否知道 Secret 的加密机制

✅ 理想答案结构:

  1. ConfigMap

    • 存储非敏感配置数据(如日志级别、功能开关、应用设置)。
    • 数据以明文存储(Base64 编码 ≠ 加密)。
    • 示例:appsettings.json、环境变量配置。
  2. Secret

    • 存储敏感数据(如密码、Token、证书)。
    • 数据以 Base64 编码存储(不是加密,仅防明文查看)。
    • 可启用 Encryption at Rest(需配置 K8s 加密提供程序)。
  3. 核心区别

    特性
    ConfigMap
    Secret
    数据类型
    非敏感配置
    敏感数据
    存储格式
    明文(Base64 编码)
    Base64 编码(可启用静态加密)
    默认大小限制
    1MB
    1MB
    使用场景
    appsettings、环境变量
    数据库密码、API Key、证书
  4. 安全提醒

    • ❗ Secret 的 Base64 不是加密,需配合 RBAC + Encryption at Rest。
    • 推荐使用 External Secrets Operator 对接云厂商密钥管理服务(如 Azure Key Vault)。

✅ 常见错误 & 避坑指南:

  • ❌ “Secret 是加密的” → 默认只是 Base64 编码,需额外配置加密。
  • ❌ “ConfigMap 可存密码” → 严重安全风险。
  • ❌ “不设置 RBAC 权限” → 任何用户可读取 Secret。

✅ 加分项/扩展知识:

  • 提到 Immutable ConfigMap/Secret(K8s 1.21+)→ 防止意外修改。
  • 提到 Projected Volume → 将多个 ConfigMap/Secret 挂载到同一目录。
  • 提到 环境变量引用 → valueFrom.configMapKeyRef / secretKeyRef

🐳 第 33 题:如何在 K8s 中实现配置热更新(不重启 Pod)?

✅ 题目重述:

当 ConfigMap 或 Secret 更新时,如何让 .NET 应用感知到新配置而无需重启 Pod?

✅ 考察意图:

  • 是否理解配置热更新的挑战
  • 是否掌握 .NET 的 IOptionsMonitor<T> 机制
  • 是否知道 K8s 的挂载限制

✅ 理想答案结构:

  1. 问题本质

    • K8s 中,ConfigMap/Secret 挂载为文件时,更新后文件内容会自动刷新(约 1 分钟延迟)。
    • 但 .NET 应用默认在启动时读取配置,不会自动重载
  2. 解决方案

    • 步骤 1:挂载为文件(非环境变量)
      volumeMounts:
      - name: config-volume
        mountPath: /app/config
      volumes:
      - name: config-volume
        configMap:
          name: app-config
    • 步骤 2:在 .NET 中使用 IOptionsMonitor<T>
      public class MyService
      {
          private readonly IOptionsMonitor<MySettings> _settings;
          public MyService(IOptionsMonitor<MySettings> settings) => _settings = settings;

          public void DoWork()
          {
              var currentSettings = _settings.CurrentValue; // 总是获取最新值
          }
      }
    • 步骤 3:配置文件重载(可选)
      builder.Configuration.AddJsonFile("/app/config/appsettings.json", optional: false, reloadOnChange: true);
  3. 注意事项

    • ❗ 挂载为环境变量无法热更新(环境变量在容器启动时注入,不可变)。
    • ❗ reloadOnChange: true 在容器中可能不生效 → 推荐用 IOptionsMonitor<T>

✅ 常见错误 & 避坑指南:

  • ❌ “更新 ConfigMap 后 Pod 会自动重启” → 不会,除非用 Reloader 等工具。
  • ❌ “用 IOptions<T> 而非 IOptionsMonitor<T>” → IOptions<T> 是单例,不感知变更。
  • ❌ “挂载为环境变量期望热更新” → 环境变量不可变。

✅ 加分项/扩展知识:

  • 提到 Reloader(开源工具,监听 ConfigMap/Secret 变更并滚动更新 Pod)。
  • 提到 自定义 Controller 实现配置推送(如通过 HTTP API 通知应用)。
  • 提到 Dapr Configuration API → 自动推送配置变更到应用。

🐳 第 34 题:什么是 Namespace?它的作用是什么?

✅ 题目重述:

请解释 Kubernetes Namespace 的概念和用途。

✅ 考察意图:

  • 是否理解多租户/环境隔离
  • 是否会使用命名空间组织资源
  • 是否知道默认命名空间

✅ 理想答案结构:

  1. Namespace 是什么?

    • K8s 中的虚拟集群,用于逻辑隔离资源(Pod、Service、ConfigMap 等)。
    • 同一集群内,不同 Namespace 的资源名称可重复。
  2. 核心作用

    • 环境隔离devstagingprod 命名空间。
    • 团队/项目隔离team-ateam-b
    • 权限控制:通过 RBAC 限制用户只能访问特定 Namespace。
    • 资源配额:限制 Namespace 的 CPU/内存用量。
  3. 常用 Namespace

    • default:未指定命名空间的资源默认在此。
    • kube-system:K8s 系统组件(如 CoreDNS、kube-proxy)。
    • kube-public:公共资源(如集群信息)。
    • kube-node-lease:Node 心跳信息。
  4. 操作命令

    # 创建命名空间
    kubectl create namespace production

    # 切换默认命名空间(需 kubens 或修改 kubeconfig)
    kubectl config set-context --current --namespace=production

    # 查看某命名空间的资源
    kubectl get all -n production

✅ 常见错误 & 避坑指南:

  • ❌ “所有资源放 default 命名空间” → 生产环境应隔离。
  • ❌ “命名空间能完全安全隔离” → 需配合 NetworkPolicy + RBAC。
  • ❌ “删除命名空间会立即删除所有资源” → 会优雅终止 Pod,可能耗时。

✅ 加分项/扩展知识:

  • 提到 ResourceQuota 和 LimitRange → 限制命名空间资源使用。
  • 提到 NetworkPolicy → 限制命名空间间网络通信。
  • 提到 Helm Release 命名空间隔离 → 每个环境独立 Release。

🐳 第 35 题:如何排查一个 Pod 一直处于 Pending 状态的问题?

✅ 题目重述:

如果一个 Pod 卡在 Pending 状态,你会如何排查?请列出步骤和命令。

✅ 考察意图:

  • 是否有实际 K8s 运维经验
  • 是否掌握常用排查命令
  • 是否能分析资源、调度、镜像等问题

理想答案结构:

排查步骤:

  1. 查看 Pod 详细信息

    kubectl describe pod <pod-name> -n <namespace>
    • 重点看 Events 部分,通常有明确错误信息。
  2. 常见原因及解决方案

    • 错误:pod has unbound immediate PersistentVolumeClaims
    • 解决:检查 PVC/PV 是否绑定。
    • 错误:0/3 nodes are available: 3 node(s) didn't match Pod's node affinity
    • 解决:检查 nodeSelector 或 affinity 配置。
    • 错误:Failed to pull imageImagePullBackOff
    • 解决:检查镜像名、私有仓库凭证(imagePullSecrets)。
    • 错误:Insufficient cpu/memory
    • 解决:增加 Node 资源,或减少 Pod 的 requests
    • 资源不足
    • 镜像拉取失败
    • 节点选择器不匹配
    • 持久卷挂载失败
    • 查看集群资源状态

      # 查看节点资源使用
      kubectl describe nodes

      # 查看 PVC 状态
      kubectl get pvc -n <namespace>

    ✅ 常见错误 & 避坑指南:

    • ❌ 只用 kubectl get pods → 无法看到错误详情。
    • ❌ 忽略 Events 中的警告 → Events 是排查关键。
    • ❌ 不检查资源配额 → Namespace 可能有 ResourceQuota 限制。

    ✅ 加分项/扩展知识:

    • 提到 kubectl get events --sort-by='.lastTimestamp' → 查看最新事件。
    • 提到 Node Allocatable → 节点可分配资源 = 总资源 - 系统预留。
    • 提到 Taints and Tolerations → 节点有污点但 Pod 无容忍。


    群贤毕至

    访客