从第一版原型到能在郑州商圈跑通交易,我和团队反复在吃喝玩乐与便民服务之间寻找平衡。问题不是功能多,而是场景复杂:商户异构数据、地理位置精度、支付合规,以及用户断网下的业务连续性。于是我们选择先做一个垂直切片:附近商家+当日特惠+一键下单,端到端验证流水线再扩展其他服务。这种做法避免了过早架构化的风险,也让后续模块接入时有真实流量数据作为参考。
技术栈有明确倾向:移动端用 Flutter 做界面与多平台一致性,关键原生能力用 Kotlin/Swift 封装;服务端用 Go 微服务,gRPC 做内部通信,REST 对外。持久层以 PostgreSQL 为交易主库,ElasticSearch 做模糊与权重搜索,Redis 承担会话、限流与地理索引(sorted set + geohash)。这种组合在性能与开发效率间比较合适,不过要注意索引策略与写放大问题,会影响锁竞争。
定位与地图不是简单的 SDK 接入。我遇到过高峰时段地图 API 返回超限,导致附近商家丢失。解决办法是:本地缓存瓦片与POI快照,后端按S2 cell聚合商户并做等级缓存;当API失败时,使用最近快照回退并异步补偿。实践教会我,离线优先比事后补救更能保护用户体验。
支付与幂等性是生产事故高发点。一次促销导致回调重复,用户被扣两次。我们基于 Redis 的分布式锁(结合唯一幂等键)改造支付处理,外加事务表记录状态机,最终用补偿式事务完成回滚。另一个经验:应在开发期就跑完整的回调链路测试,模拟通知延迟与重试,别等真问题上线才发现边界条件。
性能调优既要宏观也要微观。后端用 pprof 定位 CPU 热点,发现 JSON 反序列化占比高后改用 protobuf 作为 gRPC 负载格式;移动端用 Flutter DevTools 和 isolate 把大 JSON 解析移出 UI 线程,卡顿明显减少。缓存策略上,对实时性要求低的活动页采用边缘 CDN + 二级缓存;对附近查询用 Redis geospatial 索引,复杂筛选再落 ES。
运维上我们走容器化与 GitOps:Docker 镜像小而专,Kubernetes 编排,ArgoCD 做持续部署,Helm 管理配置。监控套件选 Prometheus+Grafana,链路追踪用 Jaeger。一次高并发的消息堆积是由 Kafka 分区数与消费者数不匹配引起的,扩容分区虽然能临时缓解,根本在于消费逻辑要幂等且能并行。
本地化体验细节不能省:郑州地铁线路、商圈营业时间、节假日促销节奏,都需要数据层的规则表达。我们把规则引擎放在配置中心,非侵入式下发给前端与推送服务。用户画像与推荐模块也更多依赖实时事件流,Kafka + Flink 做近实时聚合,比批处理更能捕捉短时热点。
我的建议是:先把端到端关键路径跑通,再做横向扩展;对外部依赖做退路与试验;测量优先于猜想。接下来会把更多观测点埋到客户端,尝试按会话维度打点以便更精细地回溯问题,但这需要权衡埋点开销与隐私合规,这点还得边做边调整。
咨询在线QQ客服