2. OCI微服务架构基础
在 OCI 上落地微服务,第一步不是打开控制台创建资源,而是先把“服务边界”想清楚。微服务拆分决定了后续的部署单元、团队边界和故障域;OCI 计算与容器服务选型决定了这些单元跑在哪里;OKE 集群负责承载与编排;服务发现与注册则让这些单元在动态伸缩、滚动发布、实例漂移的情况下仍能互相找到。这四件事是一条连续的决策链,任何一环选错,后面的治理成本都会成倍上升。
一、微服务拆分原则:按业务能力与数据所有权切分
拆分的第一原则是围绕业务能力(Business Capability),而不是围绕技术分层。把“订单、库存、支付、通知”拆成四个服务,比把“Controller 层、Service 层、DAO 层”拆成三个服务更合理,因为前者对应独立的业务变化节奏,后者只是同一业务的技术切片,拆开后反而增加跨服务调用。
第二原则是数据所有权单一。每个微服务应独占自己的数据存储,其他服务只能通过 API 访问,不能直连对方数据库。例如订单服务拥有 orders 表,库存服务拥有 inventory 表,下单时订单服务调用库存服务的扣减接口,而不是直接 UPDATE inventory。这条原则是后续独立部署、独立扩缩容的前提。
第三原则是高内聚、低耦合,且粒度适中。判断粒度是否合适,可以问三个问题:这个服务能否由一个小团队(6~8 人)独立负责?它的发布是否不需要与其他服务协调?它的故障是否可以被隔离而不引发全局雪崩?如果答案都是“是”,粒度基本合理。拆分过细会带来分布式事务、链路追踪和运维复杂度,拆分过粗则失去独立演进能力。
第四原则是面向变化频率与伸缩需求。秒杀场景下订单写入压力远高于用户资料查询,把两者拆开可以只对订单服务扩容。反之,若两个模块总是一起变更、一起扩容,就应考虑合并。
二、OCI 计算与容器服务选型
OCI 提供多种承载微服务的方式,选型取决于团队对运维的掌控意愿和负载特征。常见选项对比如下:
| 服务 | 形态 | 适用场景 | 运维负担 |
|---|---|---|---|
| Compute VM / Instance Pool | 虚拟机 | 传统应用、需自定义内核或特殊网络 | 高,需自行管理 OS 与补丁 |
| Container Instances | 无服务器容器 | 短时任务、简单容器、无需编排 | 低,按容器计费 |
| OKE(Container Engine for Kubernetes) | 托管 Kubernetes | 标准微服务集群、需自动扩缩与自愈 | 中,控制面由 OCI 托管 |
| Functions | FaaS | 事件驱动、突发、无状态小逻辑 | 极低,按调用计费 |
对于本课程讨论的微服务治理与服务通信,OKE 是主力选型:它提供标准 Kubernetes API,支持 Deployment、Service、Ingress、HPA,并可与 OCI 的负载均衡、VCN、IAM、日志服务集成。若某个服务只是定时清理任务,用 Functions 或 Container Instances 更经济;若服务需要特定内核模块,则用 Compute VM。
三、OKE 集群部署微服务
OKE 集群由控制面(Control Plane)和工作节点池(Node Pool)组成。控制面由 OCI 托管,包含 kube-apiserver、etcd、scheduler、controller-manager;节点池是运行 Pod 的计算实例,可选择 VM 或裸金属,并支持按需伸缩。
部署一个微服务的典型流程是:先构建镜像并推送到 OCIR(OCI Container Registry),再编写 Deployment 与 Service 清单,最后通过 kubectl apply 提交。以下是一个订单服务的 Deployment 示例(示例参数,非实测结果):
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: shop
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order
image: iad.ocir.io/tenancy/order-service:1.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
关键点有三处:readinessProbe 决定 Pod 何时被加入 Service 端点,未就绪的实例不会接收流量;resources.requests 影响调度与 HPA 计算;replicas 与 HPA 配合实现弹性。部署后可用 kubectl get pods -n shop -o wide 观察状态,用 kubectl describe pod 排查镜像拉取或探针失败。
四、服务发现与注册的基本机制
Kubernetes 的服务发现是声明式 + 动态端点模型。核心对象是 Service:它为一组 Pod 提供稳定的虚拟 IP(ClusterIP)和 DNS 名称。Pod 创建、销毁、扩缩容时,Endpoints 控制器会自动更新后端地址列表,调用方无需感知实例变化。
DNS 解析规则为 <service>.<namespace>.svc.cluster.local。例如 order-service.shop.svc.cluster.local 会解析到 ClusterIP,再由 kube-proxy 或 eBPF 转发到具体 Pod。跨命名空间调用需写全限定名,同命名空间可简写为 order-service。
注册机制上,Kubernetes 不依赖独立注册中心,而是通过 Label Selector + Endpoints/EndpointSlice 实现“注册”。Pod 就绪后自动进入 EndpointSlice,失活后自动摘除。若需要更细粒度的流量治理(灰度、熔断、重试),可在 OKE 上叠加 Service Mesh(如 Istio 或 OCI 服务网格),由 Sidecar 接管服务间通信。
理解这张图后,可以把服务发现归纳为三句话:Pod 是动态的,Service 是稳定的,EndpointSlice 是实时的。调用方只依赖 Service 名称,Kubernetes 负责把请求送到当前健康的实例上。这也解释了为什么在 OKE 中不应把 Pod IP 写进配置文件——Pod 重建后 IP 会变化,而 Service DNS 始终有效。
kubectl get endpoints -n shop 是否有后端地址。综合来看,OCI 微服务架构的落地顺序是:先按业务能力与数据所有权拆分服务,再根据负载与运维意愿选择 OKE 作为主要承载平台,用 Deployment + Service 完成部署与暴露,最后依靠 Kubernetes 原生的 EndpointSlice 机制实现服务发现与注册。当治理需求超出原生能力时,再引入 Service Mesh 补充灰度、熔断与可观测性。这条路径既利用了 OCI 托管控制面的稳定性,也保留了 Kubernetes 生态的标准化优势。