Dapr分布式运行时实战:用Sidecar模式构建云原生微服务

Dapr 分布式运行时实战:用 Sidecar 模式构建云原生微服务

作者:Crown_22 | 云原生 & 分布式系统开发者 | 技术分享


前言

微服务架构下,每个服务都要处理服务发现、消息队列、状态管理、分布式锁、可观测性等横切关注点。这些逻辑跟业务无关,却占了大量代码量。

Dapr(Distributed Application Runtime)的核心理念:把分布式系统的通用能力抽离为 Sidecar 进程,通过 HTTP/gRPC API 调用,让业务代码零侵入地获得这些能力

本文将从零构建一个基于 Dapr 的微服务系统,涵盖状态管理、发布订阅、服务间调用、Actor 模式和可观测性。


在这里插入图片描述

一、Dapr 架构原理

1.1 Sidecar 模式

┌─────────────────────┐      ┌─────────────────────┐
│    应用进程          │      │    Dapr Sidecar      │
│                     │      │                      │
│  ┌───────────────┐  │ HTTP │  ┌────────────────┐  │
│  │  业务代码      │◄─┼──────┼─►│ State Store    │  │
│  │  (无SDK依赖)   │  │ :3500│  │ Pub/Sub        │  │
│  └───────────────┘  │      │  │ Service Invoke │  │
│                     │      │  │ Bindings       │  │
└─────────────────────┘      │  └───────┬────────┘  │
                             │          │           │
                             └──────────┼───────────┘
                                        │
                        ┌───────────────┼───────────────┐
                        ▼               ▼               ▼
                   ┌─────────┐   ┌──────────┐   ┌──────────┐
                   │  Redis  │   │ RabbitMQ │   │ CosmosDB │
                   └─────────┘   └──────────┘   └──────────┘

1.2 核心构建块

构建块 功能 API
Service-to-Service 服务间调用 + 服务发现 GET/POST /v1.0/invoke/{service}/{method}
State Management 状态存储(KV) GET/PUT/DELETE /v1.0/state/{store}
Pub/Sub 发布订阅消息 POST /v1.0/publish/{topic}
Bindings 外部系统绑定 POST /v1.0/bindings/{name}
Actors 虚拟 Actor 模式 PUT/POST /v1.0/actors/{type}/{id}
Observability 可观测性 自动注入 trace/metrics
Secrets 密钥管理 GET /v1.0/secrets/{store}/{key}

二、环境搭建

2.1 安装 Dapr CLI

# 安装 Dapr CLI
wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash

# 初始化 Dapr(开发模式,自动配置 Redis)
dapr init

# 验证安装
dapr --version
# Output: CLI version: 1.14.0  Runtime version: 1.14.0

# 检查组件
dapr components

2.2 组件配置

# ~/.dapr/components/statestore.yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: ""
# ~/.dapr/components/pubsub.yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: pubsub
spec:
  type: pubsub.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: ""

三、服务间调用实战

3.1 订单服务

# order_service.py
import json
import uuid
from datetime import datetime
from flask import Flask, request, jsonify

app = Flask(__name__)

# Dapr 配置
DAPR_HTTP_PORT = 3500
STATE_STORE = "statestore"
CATALOG_APP_ID = "catalog-service"

def dapr_invoke(app_id: str, method: str, data: dict = None) -> dict:
    """通过 Dapr 调用其他服务"""
    import requests
    url = f"http://localhost:{
     
     DAPR_HTTP_PORT}/v1.0/invoke/{
     
     app_id}/method/{
     
     method}"
    if data:
        resp = requests.post(url, json=data)
    else:
        resp = requests.get(url)
    return resp.json() if resp.status_code == 200 else None

def dapr_save_state(key: str, value: dict):
    """保存状态到 Dapr State Store"""
    import requests
    url = f"http://localhost:{
     
     DAPR_HTTP_PORT}/v1.0/state/{
     
     STATE_STORE}"
    data = [{
   
   "key": key, "value": value}]
    requests.post(url, json=data)

def dapr_get_state(key: str) -> dict:
    """从 Dapr State Store 获取状态"""
    import requests
    url = f"http://localhost:{
     
     DAPR_HTTP_PORT}/v1.0/state/{
     
     STATE_STORE}/{
     
     key}"
    resp = requests.get(url)
    return resp.json() if resp.status_code == 200 else None

@app.route("/orders", methods=["POST"])
def create_order():
    """创建订单"""
    data = request.json
    order_id = str(uuid.uuid4())
    
    # 1. 通过 Dapr 调用商品服务获取商品信息
    items_with_info = []
    for item in data["items"]:
        product = dapr_invoke(CATALOG_APP_ID, f"products/{
     
     item['product_id']}")
        if not product:
            return jsonify({
   
   "error": f"商品 {
     
     item['product_id']} 不存在"}), 400
        
        # 检查库存
        if product["stock"] < item["quantity"]:
            return jsonify({
   
   "error": f"商品 {
     
     product['name']} 库存不足"}), 400
        
        items_with_info.append({
   
   
            "product_id": item["product_id"],
            "product_name": product["name"],
            "unit_price": product["price"],
            "quantity": item["quantity"]
        })
    
    # 2. 计算总金额
    total = sum(i["unit_price"] * i["quantity"] for i in items_with_info)
    
    # 3. 创建订单对象
    order = {
   
   
        "id": order_id,
        "customer_id": data["customer_id"],
        "items": items_with_info,
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值