“叮铃铃”,“叮铃铃”,早上七八点,你还在温暖的被窝里和闹钟“斗智斗勇”。
突然,你意识到已经快迟到了,于是像个闪电侠一样冲进卫生间,速洗漱,急穿衣,左手抄起手机,右手拿起面包,边穿衣边啃早餐。
这个时候,通勤的老难题又摆在了你面前:要不要吃完这口面包、刷牙和洗脸,还是先冲出门赶车?
好不容易做出了一个艰难的决定——放下面包,快步冲出门。你拿出手机,点开了熟悉的地铁乘车 App 或公交地铁乘车码小程序。
然后,一张二维码在屏幕上亮了起来,这可是你每天通勤的“敲门砖”。
你快步走到地铁站,将手机二维码扫描在闸机上,"嗖"的一声,闸机打开,你轻松通过,不再需要排队买票,不再被早高峰的拥挤闹心。
你走进地铁车厢,挤到了一个角落,拿出手机,开始计划一天的工作。
正如上文所说,人们只需要一台手机,一个二维码就可以完成上班通勤的所有事项。
那这个便捷的公交或地铁乘车系统是如何设计的呢?它背后的技术和架构是怎样支撑着你我每天的通勤生活呢?
今天让我们一起揭开这个现代都市打工人通勤小能手的面纱,深入探讨乘车系统的设计与实现。
在这个文章中,小❤将带你走进乘车系统的世界,一探究竟,看看它是如何在短短几年内从科幻电影中走出来,成为我们日常生活不可或缺的一部分。
乘车系统的用户量非常大,据《中国主要城市通勤检测报告-2023》数据显示,一线城市每天乘公交&地铁上班的的人数普遍超过千万,平均通勤时间在 45-60 分钟,并集中在早高峰和晚高峰时段。
所以,设计一个热点数据分布非均匀、人群分布非均匀的乘车系统时,需要考虑如下几点:
交互时序图如下:
1. 用户注册和登录: 用户首先需要在手机应用上注册并登录系统,提供个人信息,包括用户名、手机号码、支付方式等。
2. 查询乘车信息: 用户可以使用手机应用查询公交车/地铁的路线和票价信息,用户可以根据自己的出行需求选择合适的线路。
3. 生成乘车二维码: 用户登录后,系统会生成一个用于乘车的二维码,这个二维码可以在用户手机上随时查看。这个二维码是城市公交系统的通用乘车二维码,同时该码关联到用户的账户和付款方式,用户可以随时使用它乘坐任何一辆公交车或地铁。
交互 UML 状态图如下:
以上是一些在公交车&地铁乘车系统中需要设计的数据库表及其字段的基本信息,后续可根据具体需求和系统规模,还可以进一步优化表结构和字段设计,以满足性能和扩展性要求。
详细设计除了要设计出表结构以外,我们还针对两个核心问题进行讨论:
根据交通部门给的公交&地铁路线,我们可以绘制如下站点图:
假设图中的站点有 A-F,涉及到的交通工具有地铁 1 号线和 2 路公交,用户的起点和终点分别为 A、F 点。我们可以使用 Dijkstra 算法来求两点之间的最短路径,具体步骤为:
步骤 | 已遍历集合 | 未遍历集合 |
---|---|---|
1 | 选入A,此时最短路径 A->A = 0,再以 A 为中间点,开始寻找下一个邻近节点 | {B、C、D、E、F},其中与 A 相邻的节点有 B 和 C,AB=6,AC=3。接下来,选取较短的路径节点 C 开始遍历 |
2 | 选取C,A->C=3,此时已遍历集合为{A、C},以 A 和 C 为中间点,开始寻找下一个邻近节点 | {B、D、E、F},其中与 A、C 相邻的节点有 B 和 D,AB=6,ACD=3+4=7。接下来,选取较短的路径节点 B 开始遍历 |
3 | 选取B,A->B=6,此时已遍历集合为{A、C、B},A 相邻的节点已经遍历结束,开始寻找和 B、C 相近的节点 | {D、E、F},其中与 B、C 相邻的节点有 D,节点 D 在之前已经有了一个距离记录(7),现在新的可选路径是 ABD=6+5=11。显然第一个路径更短,于是将 D 的最近距离 7 加入到集合中 |
4 | 选取D,A->D=7,此时已遍历集合为{A、C、B、D},寻找 D 相邻的节点 | {E、F},其中 DE=2,DF=3,选取最近路径的节点 E 加入集合 |
5 | 选取 E,A->E=7+2=9,此时已遍历集合为{A、C、B、D、E},继续寻找 D 和 E 相近的节点 | {F},其中 DF=3,DEF=2+5=7,于是F的最近距离为7+3=10. |
6 | 选取F,A->F=10,此时遍历集合为{A、C、B、D、E、F} | 所有节点已遍历结束,从 A 点出发,它们的最近距离分别为{A=0,C=3,B=6,D=7,E=9,F=10} |
在用户查询路线之前,交通部门会把公交 & 地铁的站点经纬度信息输入到路线管理系统,并根据二维的空间经纬度编码存储对应的站点信息。
我们设定西经为负,南纬为负,所以地球上的经度范围就是[-180, 180],纬度范围就是[-90,90]。如果以本初子午线、赤道为界,地球可以分成 4 个部分。
根据这个原理,我们可以先将二维的空间经纬度编码成一个字符串,来唯一标识用户或站点的位置信息。再通过 Redis 的 GeoHash 算法,来获取用户出发点附近的所有站点信息。
GeoHash 算法的原理是将一个位置的经纬度换算成地址编码字符串,表示在某个矩形区域,通过这个算法可以快速找到同一个区域的所有站点。
一旦获得了起始地点的经纬度,系统就可以根据附近的站点信息,调用路线管理系统来查找最佳的公交或地铁路线。
一旦用户选择了一条路线,导航引擎启动并提供实时导航指引。导航引擎可能会使用地图数据和 GPS 定位来指导用户前往起止站点。
乘车码是通过 QR 码(Quick Response Code)技术生成的,它比传统的 Bar Code 条形码能存更多的信息,也能表示更多的数据类型,如图所示:
二维码的生成非常简单,拿 Go 语言来举例,只需引入一个三方库:
import "github.com/skip2/go-qrcode"
func main() {
qr,err:=qrcode.New("https://mp.weixin.qq.com",qrcode.Medium)
if err != nil {
log.Fatal(err)
} else {
qr.BackgroundColor = color.RGBA{50,205,50,255} //定义背景色
qr.ForegroundColor = color.White //定义前景色
qr.WriteFile(256,"./wechatgzh_qrcode.png") //转成图片保存
}
}
以下是该功能用户和系统之间的交互、二维码信息存储、以及高并发请求处理的详细说明:
总之,通过 QR 码技术生成乘车码,后台系统需要具备高并发处理的能力,包括负载均衡、缓存和频率限制等策略,以确保用户能够快速获得有效的乘车二维码。
同时,二维码信息需要被安全地存储和管理,比如:加密存储以保护用户的隐私和付款信息。
不清楚如何限流的,可以看我之前的这篇文章:若我问到高可用,阁下又该如何应对呢?
除此之外,公交车或地铁的定位和到站时间计算可能还涉及定位设备、GPS 系统、NoSQL 数据库、用户 TCP 连接管理系统等核心组件,并通过实时数据采集、位置处理、到站时间计算和信息推送等流程来为用户提供准确的乘车信息。
同时,自动支付也是为了方便用户的重要功能,可以通过与第三方支付平台的集成来实现。
公交车/地铁乘车系统的未来发展可以包括以下方向:
在设计和发展过程中,也要不断考虑用户体验、性能和安全,确保系统能够满足不断增长的需求。
由于篇幅有限,文章就到此结束了。