ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

microservices-demo 系列解析:Shippingservice 物流/配送微服务的 gRPC 报价与订单履约实现

microservices-demo 系列解析:Shippingservice 物流/配送微服务的 gRPC 报价与订单履约实现 microservices-demo 系列解析Shippingservice 物流/配送微服务的 gRPC 报价与订单履约实现【免费下载链接】microservices-demoSample cloud-first application with 10 microservices showcasing Kubernetes, Istio, and gRPC.项目地址: https://gitcode.com/GitHub_Trending/mi/microservices-demo导读Shippingservice 是 microservices-demo在线精品店示例中负责物流履约的微服务它并不真正发货而是以模拟的方式提供三项核心能力运费报价price quote、跟踪号tracking ID生成以及订单履约/配送流程的完整体验。本文以仓库中 src/shippingservice/README.md 为骨架深入其 Go 源码、protobuf 定义、测试用例与 Kubernetes 清单帮助你掌握该服务从本地构建、镜像打包、单元测试到部署运行的完整链路并理解它与 checkoutservice 之间的 gRPC 调用关系。服务定位与整体架构Shipping Service 在 10 个微服务组成的电商链路中处于下单后段当用户结算时checkoutservice 会调用本服务完成两件事——先计算运费再发货并取得跟踪号。整个调用链可概括为frontend → checkoutservice → shippingserviceGetQuote 报价 └→ shippingserviceShipOrder 发货/跟踪号从 protos/demo.proto 的接口定义可以看到Shippingservice 暴露了非常精简的两个 RPCservice ShippingService { rpc GetQuote(GetQuoteRequest) returns (GetQuoteResponse) {} rpc ShipOrder(ShipOrderRequest) returns (ShipOrderResponse) {} } message GetQuoteRequest { Address address 1; repeated CartItem items 2; } message GetQuoteResponse { Money cost_usd 1; } message ShipOrderRequest { Address address 1; repeated CartItem items 2; } message ShipOrderResponse { string tracking_id 1; } message Address { string street_address 1; string city 2; string state 3; string country 4; int32 zip_code 5; }其中Money采用整数 units 纳秒 nanos的标准表示法如$-1.75 units-1, nanos-750,000,000避免浮点精度问题这个 proto 文件由仓库根目录的 protos/demo.proto 统一维护并通过 genproto.sh 生成 Go 代码到 src/shippingservice/genproto 目录generated code 由 protoc-gen-go 生成请勿手工编辑。本地依赖还原与构建依赖管理Go modulesREADME 中提到使用dep ensure --vendor-only将依赖还原到vendor/目录这是项目早期基于 dep 工具的做法。当前仓库已迁移到 Go modulesgo.mod 声明了模块路径github.com/GoogleCloudPlatform/microservices-demo/src/shippingservice、Go 版本 1.25.0 及工具链 go1.26.5核心依赖包括google.golang.org/grpcv1.83.0 —— gRPC 框架google.golang.org/protobufv1.36.11 —— protobuf 运行时github.com/sirupsen/logrusv1.9.4 —— 结构化日志cloud.google.com/go/profilerv0.6.0 —— Stackdriver/Cloud Profiler因此在当前代码库中本地开发等价地使用标准命令即可# 进入服务目录 cd src/shippingservice # 下载依赖go.mod / go.sum 已在仓库中 go mod download # 如需重新生成 gRPC 代码仓库已内置 genproto 产物一般无需执行 ./genproto.sh说明dep ensure --vendor-only与go mod download二选一即可前者仅适用于旧版 dep 工作流后者为当前仓库的实际形态。Docker 镜像构建README 给出的构建命令为# 在 src/shippingservice 目录下执行 docker build ./对应的 Dockerfile 采用两阶段构建值得逐层解读# 阶段一编译 ARG BUILDPLATFORMlinux/amd64 FROM --platform$BUILDPLATFORM golang:1.26.5-alpine AS builder WORKDIR /src COPY go.mod go.sum ./ RUN go mod download # 利用层缓存先还原依赖 COPY . . # 支持 skaffold debug 传入编译参数 ARG SKAFFOLD_GO_GCFLAGS RUN GOOS${TARGETOS} GOARCH${TARGETARCH} CGO_ENABLED0 \ go build -ldflags-s -w -gcflags${SKAFFOLD_GO_GCFLAGS} -o /go/bin/shippingservice . # 阶段二精简运行镜像 FROM gcr.io/distroless/static WORKDIR /src COPY --frombuilder /go/bin/shippingservice /src/shippingservice ENV APP_PORT50051 ENV GOTRACEBACKsingle EXPOSE 50051 ENTRYPOINT [/src/shippingservice]要点CGO_ENABLED0distroless/static产出无 glibc 依赖的静态二进制镜像体积小、无 shell 层契合安全基线ENV APP_PORT50051与EXPOSE 50051声明了服务端口与 Kubernetes 清单保持一致GOTRACEBACKsingle配合 skaffold debug 定位 Go 协程故障。单元测试README 给出的测试命令go test .仓库内 shippingservice_test.go 提供了 8 组针对核心逻辑的单元测试是理解服务行为最好的活的文档测试函数验证内容TestGetQuote非空购物车2 个商品、数量 13应返回$8.99units8, nanos990000000TestGetQuoteEmptyCart空购物车返回$0.00units0, nanos0TestShipOrderShipOrder返回的跟踪号长度为 18 个字符TestTrackingIdFormat跟踪号匹配正则^[A-Z]{2}-\d-\d$TestTrackingIdUniqueness50 次生成至少得到 2 个不同跟踪号TestCreateQuoteFromFloat浮点金额 →{Dollars, Cents}转换0.0→0.0、8.99→8.99、100.01→100.1 等表驱动用例TestCreateQuoteFromCount数量 0 → 零报价数量非 0 → 非零报价TestQuoteStringQuote{8, 99}的字符串化为$8.99核心业务实现解析报价逻辑按商品数量定价GetQuote 的实现 首先累加购物车中所有商品的Quantity再交给 quote.go 中的纯函数计算func CreateQuoteFromCount(count int) Quote { if count 0 { return CreateQuoteFromFloat(0) } return CreateQuoteFromFloat(8.99) // 固定运费 8.99 美元 }func CreateQuoteFromFloat(value float64) Quote { units, fraction : math.Modf(value) return Quote{ uint32(units), uint32(math.Trunc(fraction * 100)), } }定价策略非常直白购物车为空报价 0否则一律 $8.99 固定运费——这正是演示项目中印象式impression of运费计算的体现。最终金额通过MoneyUSD 币种 Units/Nanos 字段编码进GetQuoteResponse返回由 checkoutservice 接收后再交给 currencyservice 做汇率换算见 checkoutservice 的 quoteShipping 调用。跟踪号生成确定性 随机性组合ShipOrder 的实现 用收货地址拼接出 salt再调用 tracker.go 中的CreateTrackingIdfunc CreateTrackingId(salt string) string { return fmt.Sprintf(%c%c-%d%s-%d%s, getRandomLetterCode(), // 2 个大写字母 getRandomLetterCode(), len(salt), // 地址长度 getRandomNumber(3), // 3 位随机数字 len(salt)/2, // 地址长度的一半 getRandomNumber(7), // 7 位随机数字 ) }生成的跟踪号格式如XX-LL-NNN-LLLLLL-NNNNNNN其长度恒为 18 字符与测试TestShipOrder断言一致。getRandomLetterCode()通过65 rand.Intn(25)生成大写字母 A–Z 的码点getRandomNumber(digits)逐位拼接指定位数的随机数字串。由于掺入了随机部分即使 salt 相同也能产生足够多样的跟踪号TestTrackingIdUniqueness验证了这一性质满足notional lookup of shipment delivery status的演示需求。服务端装配gRPC、健康检查与可观测性main.go 的启动流程体现了本仓库 Go 微服务的通用范式port : defaultPort // 50051 if value, ok : os.LookupEnv(PORT); ok { port value } lis, err : net.Listen(tcp, port) srv : grpc.NewServer() svc : server{} pb.RegisterShippingServiceServer(srv, svc) healthcheck : health.NewServer() healthpb.RegisterHealthServer(srv, healthcheck) reflection.Register(srv) srv.Serve(lis)几个值得注意的工程点端口可配默认监听50051可通过环境变量PORT覆盖gRPC 健康检查注册了grpc_health_v1服务Kubernetes 的 readiness/liveness probe 都基于此见下文清单gRPC reflection注册 reflection 服务便于 grpcurl 等工具在线探测服务方法可观测性开关通过DISABLE_TRACING、DISABLE_PROFILER、DISABLE_STATS三个环境变量控制 tracingOpenTelemetry 待实现见代码 TODO、Stackdriver profilerinitProfiling 会带退避重试最多 3 次与 stats 的启停JSON 结构化日志logrus 配置为 JSONFormatter输出字段映射为timestamp/severity/message便于接入云日志系统。Kubernetes 部署形态kubernetes-manifests/shippingservice.yaml 中定义了三种资源kustomize 目录 kustomize/base/shippingservice.yaml 与 helm-chart 模板 helm-chart/templates/shippingservice.yaml 提供等价声明可任选一种部署方式Deployment单容器server镜像shippingservice暴露 50051 端口通过环境变量注入PORT50051与DISABLE_PROFILER1在集群中关闭云 profilerProbesreadiness 与 liveness 均使用 gRPC 探针指向 50051 端口periodSeconds: 5资源配额requests cpu 100m / memory 64Milimits cpu 200m / memory 128Mi安全上下文runAsNonRoot: true、fsGroup: 1000容器内allowPrivilegeEscalation: false、drop: [ALL]、readOnlyRootFilesystem: trueServiceClusterIP 类型port 50051 → targetPort 50051供集群内其他服务尤其是 checkoutservice通过shippingservice:50051访问ServiceAccount名为shippingservice对应 Deployment 中的serviceAccountName。checkoutservice 侧通过环境变量SHIPPING_SERVICE_ADDR建立 gRPC 连接checkoutservice/main.go随后依次调用GetQuoteL314与ShipOrderL387把报价与跟踪号组装进最终下单响应。常见问题与注意事项旧命令 vs 新依赖体系README 中的dep ensure --vendor-only属于历史工作流当前仓库使用 Go modules请以go mod download为准两者不可混用。端口冲突本机同时启动多个 microservices-demo 服务时若 50051 被占用可通过PORT环境变量覆盖但需同步修改依赖方checkoutservice 的SHIPPING_SERVICE_ADDR的地址。profiler 依赖 GCP非 GCP 环境会走重试退避最终放弃此时建议设置DISABLE_PROFILER1K8s 清单中已默认关闭。浮点金额报价结果一律以Money{currency_code, units, nanos}传递请勿直接以 float 形式跨服务传递金额避免精度丢失。跟踪号仅作演示ShipOrder并不触发真实物流动作返回的 tracking ID 仅用于前端展示与状态查询的印象与仓库产品需求文档中模拟配送流程的定位一致。小结Shippingservice 以约 200 行 Go 代码 9 组单元测试完成了运费报价、跟踪号生成、gRPC 装配与健康检查等微服务骨架的全部要素是学习如何在 microservices-demo 中编写一个标准 Go gRPC 服务的绝佳范本。阅读源码时建议按此顺序先看 protos/demo.proto 的接口契约再对照 quote.go 与 tracker.go 的纯函数逻辑最后结合 main.go 与 shippingservice_test.go 理解装配与验证方式即可快速上手并类比到仓库内其他 Go 微服务如 productcatalogservice、checkoutservice。【免费下载链接】microservices-demoSample cloud-first application with 10 microservices showcasing Kubernetes, Istio, and gRPC.项目地址: https://gitcode.com/GitHub_Trending/mi/microservices-demo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表