☰
旅游系统三端同源架构:Spring Cloud Alibaba + Vue/UniApp 实战
2026/10/8 4:00:15 网站建设 项目流程

简介:这是一套完整的旅游行业全栈项目源码,面向计算机专业学生、毕业设计与课程设计学习者及Java+Vue全栈初学者,提供Web端、App端与微信小程序三端协同的实战开发范例。项目基于Spring Cloud Alibaba微服务架构,整合Spring Boot、MyBatis、Vue 2/3及UniApp,涵盖用户中心、景点管理、订单支付、行程规划等核心业务模块,代码经严格测试运行稳定,功能完整可复现,答辩评审平均分达96分,适合作为大创、工程实训、学科竞赛或技术练手的高质量参考基线。资源包共2012个文件,含57个Java后端服务类、1869个Markdown文档(含详细设计说明、接口规范与部署指南)、58个XML配置文件、6个SQL建表脚本及4个PDF设计报告,整体117.89MB,结构清晰、注释充分,便于理解微服务拆分逻辑与跨端交互机制。已有42人下载学习,附带作者一对一答疑支持,可助力快速掌握分布式系统开发流程与多端协同实践要点。

1. 三端同源:为什么旅游项目必须用 Spring Cloud Alibaba + Vue/UniApp 架构落地?

你手头有个旅游项目,要同时上线 Web 端(PC/移动端浏览器)、App(Android/iOS)和微信小程序——不是三个独立项目,而是同一套业务逻辑、同一套用户体系、同一套订单与支付流程。这时候如果还用“Spring Boot 单体 + 三个前端各自写一套接口”,半年后你会在会议室里听见运维说:“小程序改个字段,App 要发版,Web 端又报 404,三方联调花了三天,结果发现是订单状态枚举值没对齐。”这不是玄学,是真实踩过的坑。

这个标题里的技术组合,本质是一套可收敛、可演进、可隔离的三端协同架构方案:后端用 Spring Cloud Alibaba(Nacos 注册中心 + Sentinel 流控 + Seata 分布式事务 + OpenFeign 远程调用)构建微服务骨架,把用户中心、订单、支付、景点、库存等模块拆成独立可灰度的服务;Spring Boot + MyBatis 做单服务内扎实的数据层,保证 SQL 可控、缓存可调、分页可测;前端则用 Vue 写 Web 端(兼顾 SEO 和复杂交互),用 UniApp 一套代码编译出 App 和微信小程序——不是“能跑”,而是“能稳、能调、能查、能扩”。

它解决的不是“能不能做出来”,而是“上线后能不能扛住五一抢票洪峰”“运营临时加个拼团活动要不要重写三端”“小程序审核被拒时 App 能不能照常迭代”。适合正在从单体转向微服务、但又不想一步上 Kubernetes 的中小型旅游 SaaS 团队,也适合需要快速验证 MVP 并同步铺开多渠道获客的创业公司。下面,我们就从零开始,把这套架构真正跑通、调稳、压得住。


2. 后端基建:用 Spring Cloud Alibaba 搭建可伸缩的旅游微服务骨架

旅游系统天然具备高并发、强一致性、多数据源、长事务链路等特点:用户查景点 → 加购物车 → 下单 → 扣库存 → 发通知 → 更新积分 → 推送消息。任何一个环节失败,都可能引发资损或体验断层。单体架构下靠数据库事务兜底已不现实,必须靠微服务治理能力来兜底。Spring Cloud Alibaba 正是当前 Java 生态中落地成本最低、文档最全、社区最稳的选型——它不追求“最先进”,但求“最可靠”。

2.1 服务拆分策略:按业务域而非技术层切分

很多团队一上来就按“用户服务、订单服务、支付服务”硬拆,结果发现登录要查用户、查订单、查优惠券,跨服务调用爆炸。我们更推荐按旅游核心业务域+数据自治原则来划分:

服务名核心职责数据库关键依赖
auth-serviceJWT 登录、OAuth2 微信授权、权限校验auth_db无
user-service用户资料、收货地址、会员等级、积分流水user_dbauth-service(鉴权)
scene-service景点信息、门票规格、库存快照、预约时段scene_db无
order-service创建订单、状态机驱动(待支付→已支付→出票→已完成)、分布式事务协调order_dbuser-service,scene-service,pay-service
pay-service支付网关对接(微信/支付宝)、异步回调验签、退款原子性保障pay_dborder-service(通过 MQ 解耦)

提示:order-service是唯一允许跨库写入的服务,但它不直接操作其他库,而是通过 Feign 调用或 RocketMQ 事件驱动。所有服务默认只读本库,写操作必须走本服务 API。

2.2 Nacos 注册中心:不只是服务发现,更是配置动态中枢

Nacos 不仅管服务注册,更要承担环境差异化配置管理。旅游项目常需区分:测试环境(模拟支付)、预发环境(对接沙箱)、生产环境(真支付+短信实发)。我们把application.yml拆成三层:

# bootstrap.yml(启动即加载,不可热更) spring: application: name: order-service cloud: nacos: discovery: server-addr: ${NACOS_ADDR:127.0.0.1:8848} namespace: ${NACOS_NAMESPACE:public} # 按环境隔离命名空间 config: server-addr: ${NACOS_ADDR:127.0.0.1:8848} file-extension: yaml group: DEFAULT_GROUP namespace: ${NACOS_NAMESPACE:public}

在 Nacos 控制台创建配置项order-service.yaml(Data ID),内容示例:

# 生产环境配置(group=PROD) spring: datasource: url: jdbc:mysql://prod-rds:3306/order_db?useSSL=false&serverTimezone=Asia/Shanghai username: prod_user password: ENC(XXXXX) # 使用 Nacos Config 加密插件 seata: enabled: true tx-service-group: my_test_tx_group sentinel: flow: rules: - resource: /api/order/create count: 500 grade: 1 # QPS 限流

参数说明:namespace是环境隔离关键,每个环境(dev/test/prod)建独立 namespace;group用于业务线隔离(如TRAVEL_GROUP);file-extension: yaml保证配置结构清晰;ENC()表示敏感字段已加密,需在bootstrap.yml中配置nacos.config.context-path=/nacos并启用加密插件。

2.3 Sentinel 流控:旅游大促场景下的第一道防线

五一/国庆前 3 天,scene-service的/api/scene/detail接口 QPS 可能从 200 突增至 12000。硬扛?DB 连接池打满,下游服务雪崩。Sentinel 提供实时流控、熔断降级、热点参数限流三板斧。我们在scene-service中添加依赖:

<!-- pom.xml --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2022.0.4.0</version> <!-- 注意:必须与 Spring Boot 版本匹配,见后文避坑 --> </dependency>

然后在application.yml中配置控制台地址:

spring: cloud: sentinel: transport: dashboard: sentinel-dashboard:8080 # 自建 Sentinel 控制台 eager: true # 启动时立即连接,避免首次请求才初始化

在代码中定义资源:

// SceneController.java @GetMapping("/detail") @SentinelResource(value = "scene-detail", blockHandler = "handleBlock") public Result<SceneDetailDTO> getSceneDetail(@RequestParam Long sceneId) { return Result.success(sceneService.getDetail(sceneId)); } public Result<SceneDetailDTO> handleBlock(Long sceneId, BlockException ex) { log.warn("scene-detail 被限流,sceneId={}", sceneId, ex); return Result.fail("景点信息获取繁忙,请稍后再试"); }

逻辑说明:@SentinelResource将方法标记为受保护资源;blockHandler指定被限流时的兜底逻辑;Sentinel 控制台可动态设置规则(QPS/线程数/异常比例),无需重启服务。我们线上规则:/api/scene/detailQPS > 3000 时返回handleBlock,> 5000 时触发熔断(5 秒内拒绝所有请求)。

2.4 Seata 分布式事务:确保“下单扣库存”不超卖

旅游订单最怕“已支付但库存没扣”或“扣了库存但支付失败”。Seata AT 模式(Automatic Transaction)能在不改业务代码的前提下,通过代理数据源自动记录 undo_log,实现全局事务一致性。

第一步:在order-service和scene-service的pom.xml中引入 Seata 客户端:

<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>2022.0.4.0</version> </dependency>

第二步:在application.yml中配置 Seata:

seata: enabled: true tx-service-group: my_test_tx_group # 必须与 Nacos 中 seata-server 配置一致 service: vgroup-mapping: my_test_tx_group: default grouplist: default: seata-server:8091 config: type: nacos nacos: server-addr: ${NACOS_ADDR:127.0.0.1:8848} group: SEATA_GROUP namespace: ${NACOS_NAMESPACE:public} registry: type: nacos nacos: application: seata-server server-addr: ${NACOS_ADDR:127.0.0.1:8848} group: SEATA_GROUP namespace: ${NACOS_NAMESPACE:public}

第三步:在order-service的下单方法上加@GlobalTransactional:

// OrderServiceImpl.java @GlobalTransactional @Override public Order createOrder(CreateOrderDTO dto) { // 1. 创建订单主表(order_db) Order order = orderMapper.insert(dto); // 2. 调用 scene-service 扣减库存(远程 Feign) sceneClient.deductStock(dto.getSceneId(), dto.getQuantity()); // 3. 发送 MQ 通知支付服务(异步解耦) rocketMQTemplate.syncSend("order_created_topic", order); return order; }

参数说明:@GlobalTransactional是 Seata 全局事务入口;tx-service-group是逻辑分组名,必须与 Seata Server 的registry.conf中配置一致;vgroup-mapping映射到物理集群(此处为default);undo_log表需在每个业务库中手动建表(Seata 官方提供 DDL 脚本)。


3. 前端统一:Vue + UniApp 如何真正实现“一套代码,三端发布”

“一套代码三端运行”不是口号,而是工程约束下的妥协艺术。Vue 负责 Web 端(需 SEO、PWA、复杂图表),UniApp 负责 App 和小程序(需原生能力、离线包、热更新)。二者共用同一套 TypeScript 接口定义、状态管理、工具函数,但渲染层彻底分离——这才是可持续的“同源”。

3.1 接口层抽象:用 Axios + TypeScript 定义统一 API 合约

我们不把 API 请求分散在各组件里,而是建立src/api/目录,按业务域组织:

src/api/ ├── index.ts // 全局 axios 实例 + 拦截器 ├── auth/ // 登录、授权相关 │ ├── login.ts │ └── wechat.ts ├── order/ // 订单相关 │ ├── create.ts │ └── list.ts └── scene/ // 景点相关 ├── detail.ts └── search.ts

src/api/index.ts定义基础实例:

// axios 配置统一管理 import axios from 'axios' import { ElMessage } from 'element-plus' // Web 端用 Element Plus // import { uni } from '@dcloudio/uni-app' // UniApp 端用 uni const service = axios.create({ baseURL: import.meta.env.VUE_APP_API_BASE_URL || '/api', // Web 端走反向代理,UniApp 端走真实域名 timeout: 10000, }) // 请求拦截:自动携带 token service.interceptors.request.use( (config) => { const token = uni.getStorageSync('token') || localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }, (error) => Promise.reject(error) ) // 响应拦截:统一错误处理 service.interceptors.response.use( (response) => { const { code, data, msg } = response.data if (code === 200) { return data } else { ElMessage.error(msg || '请求失败') throw new Error(msg) } }, (error) => { if (error.response?.status === 401) { // token 过期,跳转登录页 uni.navigateTo({ url: '/pages/login/login' }) } return Promise.reject(error) } ) export default service

逻辑说明:baseURL区分环境——Web 端开发时用/api(由 vite.config.ts 代理到后端),生产时替换为真实域名;UniApp 端通过manifest.json中的H5和MP-WEIXIN字段分别配置不同 baseUrl;uni.getStorageSync和localStorage封装成统一取 token 方法,避免平台判断散落各处。

3.2 状态管理:Pinia + 跨平台持久化方案

Vuex 已淘汰,Pinia 是 Vue 3 官方推荐。但 UniApp 不支持createPinia(),需用兼容方案。我们采用Pinia + 自定义持久化插件:

// src/stores/index.ts import { createPinia } from 'pinia' const pinia = createPinia() // 跨平台持久化插件(Web 用 localStorage,UniApp 用 uni.setStorage) pinia.use(({ store }) => { const key = `pinia:${store.$id}` const data = uni.getStorageSync(key) || localStorage.getItem(key) if (data) { store.$patch(JSON.parse(data)) } store.$subscribe((mutation) => { const json = JSON.stringify(store.$state) uni.setStorageSync(key, json) localStorage.setItem(key, json) }) }) export default pinia

在main.ts(Web)和main.js(UniApp)中分别挂载:

// main.ts(Web) import { createApp } from 'vue' import App from './App.vue' import pinia from './stores' createApp(App).use(pinia).mount('#app') // main.js(UniApp) import { createSSRApp } from 'vue' import App from './App.vue' import pinia from './stores' export function createApp() { const app = createSSRApp(App) app.use(pinia) return { app, } }

参数说明:pinia.use()注册插件,监听$state变化并同步到存储;uni.getStorageSync和localStorage.getItem同时调用,避免平台判断;$patch直接还原状态,比$hydrate更可控;key 命名带pinia:前缀,便于调试清理。

3.3 UniApp 多端适配:条件编译 + 原生能力桥接

UniApp 的#ifdef条件编译是双刃剑——用得好,一套代码覆盖三端;用不好,代码里全是/* #ifdef APP-PLUS */ ... /* #endif */,维护成本爆炸。我们约定三条铁律:

  1. UI 层尽量用uni-app组件(<uni-list>、<uni-card>),它们内部已做平台适配;
  2. 原生能力封装成 Service,如定位、分享、扫码,对外暴露统一接口;
  3. 路由和生命周期差异,用 Composition API 抽离。

示例:封装微信分享(仅小程序)和 App 分享(仅 App):

// src/utils/share.ts export function shareToFriend(options: { title: string; path: string }) { // 小程序分享 if (uni.getSystemInfoSync().platform === 'mp-weixin') { uni.showShareMenu({ withCredentials: true, menus: ['shareAppMessage'], }) uni.onShareAppMessage(() => ({ title: options.title, path: options.path, imageUrl: '/static/logo.png', })) } // App 分享(调用原生插件) else if (uni.getSystemInfoSync().platform === 'app') { const SharePlugin = uni.requireNativePlugin('SharePlugin') SharePlugin.share({ title: options.title, content: '来自XX旅游App', url: `https://www.xxx.com/${options.path}`, }) } }

逻辑说明:uni.getSystemInfoSync().platform返回mp-weixin/app/h5,比process.env.UNI_PLATFORM更可靠;uni.onShareAppMessage是小程序专属 API,必须在onLoad中注册;uni.requireNativePlugin加载自定义原生插件,需提前在nativePlugins中配置。

3.4 Web 端 SEO 与性能优化:Vue Router + SSR 预渲染

旅游项目强依赖搜索曝光,Web 端必须支持 SEO。Vue 3 + Vite 默认是 CSR(客户端渲染),搜索引擎爬虫看到的是空<div id="app"></div>。我们采用Prerender SPA Plugin 预渲染静态页面(轻量、免服务器 SSR):

npm install --save-dev prerender-spa-plugin

在vite.config.ts中配置:

import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import PrerenderSPAPlugin from 'prerender-spa-plugin' import { join } from 'path' export default defineConfig({ plugins: [ vue(), process.env.NODE_ENV === 'production' && new PrerenderSPAPlugin({ staticDir: join(__dirname, 'dist'), routes: ['/', '/scene/123', '/order/list', '/about'], postProcess: (context) => { // 移除预渲染页面中的 script 标签(避免重复执行) context.html = context.html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '') return context }, }), ], })

参数说明:routes列出需预渲染的路径(首页、景点详情页、订单页等);postProcess清理 script 标签,防止 JS 重复执行;生成的dist/index.html等文件是完整 HTML,含<title>和<meta>,可被百度/谷歌抓取;注意:动态路由(如/scene/:id)需提前知道所有 ID,或改用vue-router的history模式 + Nginx 重写。


4. 避坑指南:Spring Cloud Alibaba + Vue/UniApp 项目中最常翻车的 5 个点

这套架构看似成熟,但实际落地时,80% 的阻塞问题都集中在几个经典坑位。以下是我带三个旅游项目踩出来的血泪经验,按现象→原因→解决三步法整理,每一条都对应真实线上故障。

4.1 现象:Nacos 服务注册成功,但 Feign 调用始终 404

原因:spring-cloud-starter-alibaba-nacos-discovery与spring-cloud-openfeign版本不兼容。常见于 Spring Boot 2.7.x 升级到 3.0.x 后,Nacos 客户端未同步升级,导致DiscoveryClient返回的服务实例列表为空。
解决:严格按 Spring Cloud Alibaba 官方版本对照表 选择依赖。例如 Spring Boot 2.7.18 对应spring-cloud-alibaba-dependencies2021.0.5.0;Spring Boot 3.0.15 对应 2022.0.4.0。切记不要混用spring-cloud-starter-openfeign和spring-cloud-starter-alibaba-sentinel的旧版。

4.2 现象:UniApp 打包微信小程序后,uni.getSystemInfoSync().model返回undefined

原因:微信开发者工具基础库版本过低(< 2.27.0),而getSystemInfoSync在新版中才稳定返回model字段。线上真机正常,但开发者工具模拟器失效,导致条件编译逻辑错乱。
解决:在微信开发者工具 → 设置 → 主题 → 基础库版本,手动切换为最新稳定版(如 2.30.2);同时在代码中增加容错:const model = uni.getSystemInfoSync().model || 'unknown',避免undefined导致后续逻辑崩溃。

4.3 现象:MyBatis 查询返回null,但日志显示 SQL 正确且有数据

原因:实体类字段名与数据库列名不匹配,且未开启mapUnderscoreToCamelCase=true。例如数据库列scene_name,实体类字段sceneName,MyBatis 默认不会自动映射。
解决:在mybatis-config.xml或application.yml中强制开启驼峰转换:

mybatis: configuration: map-underscore-to-camel-case: true

或在@Select注解中显式指定resultMap,避免依赖自动映射。

4.4 现象:Vue 页面路由跳转后,window.scrollTo(0,0)不生效

原因:Vue Router 4 的scrollBehavior默认返回false(禁用滚动),且router.push()是异步操作,scrollTo执行时机早于 DOM 渲染完成。
解决:在router/index.ts中配置:

const router = createRouter({ scrollBehavior: (to, from, savedPosition) => { if (savedPosition) { return savedPosition } else { return { top: 0 } } }, })

并在组件onMounted中使用nextTick:

onMounted(() => { nextTick(() => { window.scrollTo(0, 0) }) })

4.5 现象:Seata 全局事务中,scene-service扣库存成功,但order-service回滚时undo_log未删除

原因:undo_log表引擎为 MyISAM(不支持事务),导致 Seata 的DELETE FROM undo_log语句无法回滚,残留脏数据引发后续事务解析失败。
解决:确认undo_log表引擎为 InnoDB:

ALTER TABLE undo_log ENGINE=InnoDB;

并在application.yml中显式指定:

seata: store: db: db-type: mysql driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://xxx:3306/seata?useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456

注意:Seata Server 和所有业务服务的undo_log表结构、引擎、字符集必须完全一致。


5. 三端联调与灰度发布:让旅游项目真正“稳着上线”

架构搭好了,代码写完了,但真正的考验在联调和发布阶段。旅游项目没有“小流量验证”的奢侈——五一前一周,任何一次线上故障都可能损失百万级订单。我们必须把联调做成标准化流水线,把发布变成可逆、可观测、可秒级回滚的动作。

5.1 联调环境设计:四环境隔离 + 接口 Mock 保底

我们不设dev/test/staging/prod四套物理环境,而是用Nacos Namespace + 数据库 Schema + 域名前缀实现逻辑隔离:

环境Nacos NamespaceDB Schema域名用途
devdevtravel_devdev.api.xxx.com开发者本地联调,Mock 数据
testtesttravel_testtest.api.xxx.comQA 全链路测试,对接真实支付沙箱
prepretravel_prepre.api.xxx.com运营验收、老板演示,对接短信/微信模板真实通道
prodprodtravel_prodapi.xxx.com线上,限流规则全开

关键在于dev环境的保底机制:当后端服务未启动时,前端不报 500,而是返回 Mock 数据。我们在vite.config.ts中配置代理:

// vite.config.ts export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:8080', // 优先代理到本地后端 changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), // 代理失败时 fallback 到 mock onProxyReq: (proxyReq, req, res) => { if (req.url.includes('/api/') && !process.env.VUE_APP_MOCK_OFF) { // 启用 mock res.writeHead(200, { 'Content-Type': 'application/json' }) res.end(JSON.stringify(mockData[req.url] || { code: 200, data: {} })) } } } } } })

逻辑说明:onProxyReq在代理请求发出前拦截,若后端不可达(如curl -I http://localhost:8080返回非 200),则直接返回mockData对象;mockData是一个 JSON 文件,按路径预置典型响应(如/api/scene/detail?id=123返回模拟景点详情);VUE_APP_MOCK_OFF环境变量控制开关,上线前设为true。

5.2 灰度发布策略:基于 Nacos 配置 + Spring Cloud Gateway 路由分流

我们不用 K8s 的 Service Mesh,而是用Spring Cloud Gateway + Nacos 配置中心实现低成本灰度:

  1. 在gateway-service的application.yml中配置路由规则:
spring: cloud: gateway: routes: - id: order-service-gray uri: lb://order-service predicates: - Header=X-Gray-Flag, true filters: - StripPrefix=1 - id: order-service-prod uri: lb://order-service predicates: - Path=/api/order/** filters: - StripPrefix=1
  1. 在 Nacos 中新建配置gateway-routes.yaml,内容为:
gray: enabled: true users: ["13800138000", "13900139000"] # 灰度手机号白名单 percent: 5 # 5% 流量灰度
  1. 在 Gateway 的 GlobalFilter 中读取配置,动态打标:
@Component public class GrayRouteFilter implements GlobalFilter { @Value("${gray.enabled:false}") private boolean grayEnabled; @Autowired private ConfigService configService; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { if (!grayEnabled) return chain.filter(exchange); String phone = exchange.getRequest().getHeaders().getFirst("X-User-Phone"); if (phone != null && isGrayUser(phone)) { exchange.getRequest().mutate() .headers(h -> h.set("X-Gray-Flag", "true")) .build(); } return chain.filter(exchange); } private boolean isGrayUser(String phone) { try { String config = configService.getConfig("gray-config", "DEFAULT_GROUP", 3000); JSONObject obj = JSON.parseObject(config); JSONArray users = obj.getJSONArray("users"); if (users != null && users.contains(phone)) return true; // 百分比灰度 int percent = obj.getIntValue("percent"); return new Random().nextInt(100) < percent; } catch (Exception e) { return false; } } }

参数说明:X-Gray-Flag是 Gateway 识别灰度路由的关键 Header;isGrayUser()先查白名单,再按百分比随机;configService.getConfig()从 Nacos 动态拉取配置,无需重启;灰度期间,order-service新老版本可同时部署,Gateway 自动分流。

5.3 线上监控闭环:从日志、链路到业务指标的三级告警

旅游系统不能只看 CPU 和内存,必须监控业务水位。我们建立三级监控:

层级工具监控项告警阈值告警方式
基础设施Prometheus + GrafanaJVM 内存、GC 次数、线程数Old GC > 3 次/分钟企业微信机器人
链路追踪SkyWalking接口 P99 延迟、SQL 慢查询、Feign 调用失败率/api/order/createP99 > 2s;失败率 > 1%钉钉群 + 电话
业务指标自研埋点 + ELK每分钟下单数、支付成功率、景点库存售罄率下单数 < 10/分钟(非大促期);支付成功率 < 95%企业微信 + 短信

关键动作:在order-service的@GlobalTransactional方法中,手动上报业务事件:

// OrderServiceImpl.java @GlobalTransactional public Order createOrder(CreateOrderDTO dto) { long start = System.currentTimeMillis(); try { // ... 业务逻辑 // 上报成功事件 eventProducer.send("order_created", Map.of( "scene_id", dto.getSceneId(), "quantity", dto.getQuantity(), "amount", dto.getAmount() )); return order; } catch (Exception e) { // 上报失败事件 eventProducer.send("order_create_failed", Map.of( "scene_id", dto.getSceneId(), "error_code", e.getClass().getSimpleName() )); throw e; } finally { long cost = System.currentTimeMillis() - start; // 上报耗时指标(发送到 SkyWalking) MetricsTimer.record("order_create_cost", cost); } }

逻辑说明:eventProducer是 Kafka 生产者,将事件写入order_eventTopic,由 Flink 实时计算转化率;MetricsTimer.record()是 SkyWalking 的自定义指标埋点,可在 UI 中查看order_create_cost的 P95/P99 分布;所有告警规则在 Grafana 中配置,阈值可随时调整,无需改代码。

我带的第一个旅游项目上线时,因没做业务指标监控,在支付回调超时后 2 小时才发现问题——用户付了钱,但订单状态卡在“待支付”,客服电话被打爆。现在,只要支付成功率掉到 94%,我的手机就会响,同时自动触发curl -X POST https://api.xxx.com/health/payback强制重试失败回调。这种“机器先于人感知”的能力,才是架构落地的终极价值。

希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询