这个是我工作了 1.5 年的一个小总结

我在 TAG 的职责

  • 负责 Clinical 微服务开发和维护(TAG 是大型医疗集团,旗下 Aspen Dental 有 1400+ 门店,使用自研系统,需要持续维护和迭代)

    • 采用 Model-Service-Repository 设计模式,优化代码结构,提高可维护性
    • 日常维护多个 .NET 微服务,修复 bug,开发新业务功能
  • 负责 Monolith 维护 (也是 .NET) 和 Bug 修复

    • 阅读和理解遗留代码,定位并修复问题
    • 将 Clinical 相关功能从 Monolith 拆分到微服务
  • 数据库相关工作

    • Monolith 用 SQL Server,微服务用 PostgreSQL
    • 根据 PM 需求开发新功能或调整数据
  • 跨团队协作

    • 帮后端队友做 Code Review (团队里唯一非 Senior)
    • 帮前端队友解答后端相关问题,协助前后端联调
    • 帮 PM 做技术研究(SPIKE)
    • 需要时支援其他 team

我在 TAG 的技术栈

  • Frontend: 能读懂 Angular 和 React(微前端)
  • Backend: C#, .NET 6 到 9 (Monolith 是 .NET 6, 其他微服务基本上都是 .NET 9), GraphQL (是的我们有 GraphQL layer, 但我个人并不喜欢), gRPC
  • Database: PostgreSQL, SQL Server, AlloyDB, Firestore (GCP)
  • ORM: Dapper, Entity Framework (主要用的还是 Dapper, Monolith用的是 Entity Framework)
  • Cloud: GCP (Pub/Sub, AlloyDB, DMS, BigQuery)
  • DevOps: Docker, Kubernetes, Terraform, Spinnaker, Liquibase
  • Monitoring: Grafana
  • Other Tools: LaunchDarkly, Nuget, Git, GitHub

我自己主导的项目

虽然我是初入职场,但能力还是可以的,所以除了日常维护我们组的微服务,我也有一些自己开发的项目,为公司带来收益

TAG Notifications

从零搭建的完整服务,从数据库设计到微服务开发全程独立完成。用于患者 recall exam (也就是复诊) 管理——当患者来到诊所时,系统会根据历史 procedure 记录提醒进行复检,提升诊所服务质量和营收。

下面是整个 data flow 的设计图

┌─────────────┐         
│ Monolith │──publish──┐
└─────────────┘ │

┌─────────────┐ ┌─────────────┐ ┌──────────────────┐
│ Schedule │────▶│ Pub/Sub │────▶│ Notification │
│ MS │ │ (GCP) │ │ Subscriber │
└─────────────┘ └─────────────┘ └────────┬─────────┘
▲ │
┌─────────────┐ │ │
│ Other MS │──publish──┘ │
└─────────────┘ ▼
┌─────────────┐
┌─────────────┐ ┌─────────────┐ │ AlloyDB │
│ Frontend │────▶│ Notification│───────▶│ (PostgreSQL)│
└─────────────┘ │ MS │ └─────────────┘
└─────────────┘ ▲

┌─────────────┐ │
│ Nightly │──────────────┘
│ Cron Job │
└─────────────┘

1. 数据库设计

使用 AlloyDB + PostgreSQL 作为数据存储,通过 Liquibase 管理 schema 变更。独立设计数据库 schema,与 Senior 和 Tech Lead 多次讨论修改。在完成 MS 和 Cron Job 开发后,根据需求设计 index 优化性能。



2. Nightly Cron Job (定时任务)

Cron Job 主要负责两件事

  • Populate database: 从 Monolith 拿取需要的数据,populate 所需的 notification
  • 每日增量同步: 每天晚上根据 checkpoint 从 Monolith 更新所需数据,确保与 Monolith 保持一致(Monolith 是 source of truth)

由于 Monolith 数据量是千万级别,学习并应用了多种优化技术

  • Batch operation: 无法一次读完所有数据,将 table 数据分批读取
  • Parallel programming: 设置 concurrent worker,每个 batch 读出后用空闲 thread 进行 bulk upsert,这样就可以不需要等待 upsert 直接进入下一个 batch
  • Task 并行: 让互不冲突的 task 同时运行

通过这些优化,可以在 10 秒内处理 100,000 条数据。



3. Notification Subscriber (发布-订阅)

  • Subscriber 是一个独立的 Worker,专门处理 GCP Pub/Sub subscription,监听从 Monolith 和其他 team 发来的 event,实时更新数据库,确保用户在白天可以获得最准确的数据。

  • 之所以没有在 MS 里集成 Subscriber,是因为这个服务需要高并发且流量很大 (因为是在类似 Visit Manager 里被使用),如果在 MS 里处理,流量上来就得 scale MS,这显然不合理。独立出 Subscriber 可以单独 scale,实现服务解耦。

技术要点

  • 用 Terraform 创建 GCP subscription 和 dead letter queue
  • 研究并确定所需的 event,针对不同 event 写了不同的 message handler
  • 应用 Cron Job 中学到的优化: 互不冲突的 task 同时运行
  • 加 Redis 缓存静态数据,减少数据库查询



4. Notification MS (微服务)

一个标准的 .NET 9 微服务,为前端、GraphQL team 和其他 MS team 提供所需的 API。



总结
通过这个项目学到了很多,包括数据库设计和 PostgreSQL 的使用、parallel programming 和 Cron Job 开发(通过 GCP Log Explorer + Stopwatch 进行速度测试)、GCP Pub/Sub 的使用并处理不同的 Messaage,以及如何将 PM 比较宽泛的需求落地成具体的技术方案(Notification 概念简单,但实现复杂)。


最重要的是,这个服务设计了很强的扩展性。不止我们 Clinical team 在用,其他 team 也会依赖这个服务并提出自己的 notification 需求,不同的 stakeholder 也可以为自己的 brand 提出不同的要求。所以这算是我比较大的一个项目,并且正在持续完善整个服务。


TAG LaunchDarkly

  • 之所以做这个项目,是因为我一部分负责的工作是 pilot project(试点项目),就是在一部分 facility 中先试用新功能。之前我们控制 pilot 是用 Monolith 的数据库,有专门的 pilot project 和 pilot facility 表,但问题在于 Monolith 数据库不能随便 deploy,要等每周固定时间。这样就导致新的 pilot project 需要等到下周才能上线,影响业务敏捷性。

  • 正好那时候前端刚采用了 LaunchDarkly 作为 feature flag 控制,我的 manager 就让我研究后端怎么用 LaunchDarkly 作为 modern solution 进行 pilot 控制。

技术实现
我设计并实现了一个 Feature Flag NuGet Package,包含两部分

  • Abstraction package: 避免 vendor lock-in,统一 API 设计 (意思就是如果将来从 Launchdarkly 换成其他 feature flag 产品,都需要 implement 这个 package)
  • Implementation package: 使用 LaunchDarkly,采用 Factory Pattern + Lazy Client Initialization 优化性能

成果
这个 package 被多个 team 采用,服务全国 2000+ dental facilities。各 team 可以独立管理和上线 pilot project,不用等 database release。现在还和 Metric team 合作,可以在他们那边看到 pilot project 的 adoption rate。


总结
通过这个项目学会了怎么写 NuGet package(类似 npm package),以及怎么设计低耦合的软件


我学会的东西

如何设计微服务

在我们 Clinical team,采用 Model-Service-Repository 模式构建 C# 微服务,以提升代码的可维护性和扩展性:

  • Model: 定义数据结构,Request 或 Response 的结构
  • Repository: 负责数据库操作,封装 SQL 查询,提供数据访问接口(使用 Dapper 写和数据库交互的逻辑)
  • Service: 负责核心业务逻辑,调用 Repository 获取和修改数据

对于 Repository 和 Service,需要建立对应的 Interface,用来定义方法签名和写注释说明方法的用途。


如何使用 IaC (Terraform)

之前团队都是用 GCP Console 手动创建资源,不好管理也难以回溯。我自己学习了 Terraform, 就可以在不影响 Devops 的情况下

  • 创建 Pub/Sub subscription 和 dead letter queue
  • 写 GCP DMS template,用于数据迁移

之前团队用 SSIS 做数据迁移(从 Monolith SQL Server 迁移到 AlloyDB),非常复杂而且没有很多人知道怎么做。所以在写 PubSub template 的同时我研究了 GCP DMS (Database Migration Service),并且组合了 Terraform 提供的 DMS tempalte,让其他 team 可以更方便地进行数据迁移。


如何提高 API Performance

在 Aspen,我们用两种方式衡量 API 性能: 用 Grafana 监控 response time 等指标,以及做 stress testing 了解 API 在高负载下的表现。


性能优化方面主要是 SQL query optimization、caching strategies(如 Redis 缓存静态数据)、和 Senior 做 Code Review 讨论 API 设计。


如何从零开始做东西

不管是做 MS 还是 NuGet Package,最重要的是做一个 template 出来,可以让别人复用。这样后续的项目可以基于 template 快速开始,不需要从头配置。