1. 项目背景与核心价值公交线路查询系统是城市公共交通信息化建设的基础设施之一。随着城市规模扩大和公交网络复杂化传统纸质线路图和简单电子查询已无法满足市民出行需求。这个基于SpringBoot的系统正是为解决以下痛点而生实时性差传统查询方式更新周期长无法及时反映线路调整交互体验弱静态查询界面不支持多条件组合检索数据孤岛各公交公司数据独立缺乏统一查询入口扩展困难老旧系统架构难以对接智能调度等新型功能模块我在参与某省会城市智慧交通项目时发现即使是一线城市其官方公交APP的线路查询响应时间也经常超过3秒。这促使我设计了这个高性能的解决方案实测平均响应时间控制在800ms以内。2. 系统架构设计2.1 技术选型决策后端框架SpringBoot 2.7 MyBatis-Plus组合选型理由自动配置特性快速搭建REST API与MyBatis-Plus的代码生成器配合开发效率提升40%避坑点需要显式配置spring-boot-starter-actuator的暴露端点避免生产环境信息泄露数据存储主库MySQL 8.0线路基础信息缓存Redis 6热点查询结果特殊设计采用zset结构存储站点关联线路实现O(log(N))复杂度的反向查询空间数据处理PostGIS扩展用于距离计算示例SQLSELECT * FROM stops WHERE ST_Distance(location, ST_Point(116.404, 39.915)) 5002.2 微服务拆分策略虽然单体架构也能实现功能但考虑到后续可能对接实时到站预测采用以下服务划分线路服务route-service管理线路基础数据站点服务stop-service处理站点地理信息查询服务search-service聚合查询逻辑用户服务user-service收藏夹等个性化功能注意服务间通信采用Spring Cloud OpenFeign需要特别注意超时设置。实测表明公交查询场景下readTimeout应≥3000ms3. 核心功能实现细节3.1 多条件组合查询前端传参示例{ startStop: 北京西站, endStop: 中关村, maxTransfers: 1, departureTime: 08:30 }后端处理逻辑构建线路关系图邻接表结构应用改进的Dijkstra算法节点权重 行驶时间 换乘惩罚系数×换乘次数时间维度处理区分平峰/高峰时段车速系数结果排序策略首选最少换乘次选最短时间最后按步行距离排序3.2 地理围栏触发利用Redis GEO实现周边站点查询// 添加站点坐标 redisTemplate.opsForGeo().add(stops_geo, new Point(116.404, 39.915), 西直门站); // 查询500米内站点 Circle within new Circle(116.404, 39.915, Metrics.KILOMETERS.getMultiplier() * 0.5); RedisGeoCommands.GeoRadiusCommandArgs args GeoRadiusCommandArgs.newGeoRadiusArgs() .includeDistance() .sortAscending(); GeoResultsRedisGeoCommands.GeoLocationString results redisTemplate.opsForGeo().radius(stops_geo, within, args);性能对比纯MySQL地理查询~120msRedis GEO查询~15ms4. 性能优化实战4.1 缓存设计三原则热点缓存对TOP 20%的高频查询线路做预加载分级缓存一级Redis缓存完整查询结果TTL 5分钟二级本地Caffeine缓存线路基础数据TTL 1小时防穿透策略布隆过滤器拦截非法站点ID空结果缓存特殊值缓存4.2 数据库优化索引设计示例CREATE TABLE bus_routes ( id BIGINT PRIMARY KEY, route_name VARCHAR(50) NOT NULL, /* 其他字段 */ SPATIAL INDEX idx_route_path (route_path) ) ENGINEInnoDB; -- 复合索引用于换乘查询 CREATE INDEX idx_stop_sequence ON route_stops(stop_id, route_id, sequence);踩坑记录初期未对sequence字段建索引导致换乘查询时出现Using filesort响应时间从800ms骤增至3s5. 特殊场景处理5.1 大站快车逻辑处理特快线路的算法增强// 在路径权重计算时加入快车系数 if (route.isExpress()) { timeCost * 0.6; // 快车时间系数 }需同步在前端结果展示时添加快车标识并提示本线路在工作日早晚高峰开行大站快车5.2 末班车预警在查询结果中动态计算SELECT last_departure_time, TIMESTAMPDIFF(MINUTE, NOW(), CONCAT(CURDATE(), , last_departure_time)) AS remaining_minutes FROM route_schedules WHERE route_id ? AND direction ?前端根据remaining_minutes值显示不同颜色的预警提示30分钟绿色10-30分钟橙色10分钟红色闪烁6. 生产环境部署要点6.1 监控配置Prometheus监控指标示例- name: bus.query.latency help: 线路查询耗时百分位 buckets: [100, 300, 500, 1000, 3000] - name: bus.cache.hit_rate help: 缓存命中率Grafana看板应重点关注P99查询延迟缓存命中率趋势换乘查询占比6.2 弹性扩缩容策略根据查询量动态调整常规时段2个查询服务实例早晚高峰自动扩容至5个实例夜间时段缩容至1个实例HPA配置示例metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 607. 实际踩坑经验坐标系统一致性教训某城市公交数据使用GCJ-02坐标系而地图API使用WGS-84解决方案在数据接入层统一转换避免出现500米偏移线路环形处理特殊场景环线公交的起点终点处理方案在路径算法中标记isLoop属性前端展示时特殊处理时刻表异常发现部分线路的末班车时间早于首班车修复增加数据校验规则CHECK(last_departure first_departure)高并发测试模拟早高峰压力测试时发现MySQL连接池爆满优化调整HikariCP配置spring.datasource.hikari.maximum-pool-size20 spring.datasource.hikari.connection-timeout3000这个项目让我深刻体会到交通系统的可靠性要求远高于常规业务系统。有一次线上故障导致查询服务中断15分钟立即收到200市民投诉。因此我们在SLA中承诺99.95%的可用性这要求从架构设计到日常运维都要有极致追求。