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 核心构建块构建块功能APIService-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/metricsSecrets密钥管理GET /v1.0/secrets/{store}/{key}二、环境搭建2.1 安装 Dapr CLI# 安装 Dapr CLIwget-qhttps://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 components2.2 组件配置# ~/.dapr/components/statestore.yamlapiVersion:dapr.io/v1alpha1kind:Componentmetadata:name:statestorespec:type:state.redisversion:v1metadata:-name:redisHostvalue:localhost:6379-name:redisPasswordvalue:""# ~/.dapr/components/pubsub.yamlapiVersion:dapr.io/v1alpha1kind:Componentmetadata:name:pubsubspec:type:pubsub.redisversion:v1metadata:-name:redisHostvalue:localhost:6379-name:redisPasswordvalue:""三、服务间调用实战3.1 订单服务# order_service.pyimportjsonimportuuidfromdatetimeimportdatetimefromflaskimportFlask,request,jsonify app=Flask(__name__)# Dapr 配置DAPR_HTTP_PORT=3500STATE_STORE="statestore"CATALOG_APP_ID="catalog-service"defdapr_invoke(app_id:str,method:str,data:dict=None)-dict:"""通过 Dapr 调用其他服务"""importrequests url=f"http://localhost:{DAPR_HTTP_PORT}/v1.0/invoke/{app_id}/method/{method}"ifdata:resp=requests.post(url,json=data)else:resp=requests.get(url)returnresp.json()ifresp.status_code==200elseNonedefdapr_save_state(key:str,value:dict):"""保存状态到 Dapr State Store"""importrequests url=f"http://localhost:{DAPR_HTTP_PORT}/v1.0/state/{STATE_STORE}"data=[{"key":key,"value":value}]requests.post(url,json=data)defdapr_get_state(key:str)-dict:"""从 Dapr State Store 获取状态"""importrequests url=f"http://localhost:{DAPR_HTTP_PORT}/v1.0/state/{STATE_STORE}/{key}"resp=requests.get(url)returnresp.json()ifresp.status_code==200elseNone@app.route("/orders",methods=["POST"])defcreate_order():"""创建订单"""data=request.json order_id=str(uuid.uuid4())# 1. 通过 Dapr 调用商品服务获取商品信息items_with_info=[]foritemindata["items"]:product=dapr_invoke(CATALOG_APP_ID,f"products/{item['product_id']}")ifnotproduct:returnjsonify({"error":f"商品{item['product_id']}不存在"}),400# 检查库存ifproduct["stock"]item["quantity"]:returnjsonify({"error":f"商品{product['name']}库存不足"}),400items_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"]foriinitems_with_info)# 3. 创建订单对象order={"id":order_id,"customer_id":data["customer_id"],"items":items_with_info,