本人的工程實踐項目是設計一個類似12306的網上售票系統,本文將分析該項目的同時對軟件架構進行初步設計。
項目信息
題目基本要求
-
參考12306站點進行售票系統建模設計,盡可能接近覆蓋真實線上系統,實現的功能有但不限於:
- 用戶信息注冊
- 查詢余票: 根據時間,車次,站點區間,座次(一等座,二等座,硬卧,硬座…)查詢余票
- 售票: 支持一次購買同一車次的多張車票(多人),支持訂單30分鍾內鎖定,超時釋放。支付接口可以mock。
- 退票: 支持一個用戶賬戶下的批量退票
- 改簽: 同一用戶一張車票只能改簽一次
-
所有讀寫接口延遲要求 <= 500ms
-
單機支持到500qps的並發請求
軟件架構
MVC
MVC架構,即 Model-View-Controller(模型-視圖-控制器)。
- 控制器:負責轉發請求,對請求進行處理。
- 視圖:圖形界面設計。
- 模型:程序應有的功能(實現算法等)、數據管理和數據庫設計。
隨着時代的發展,前端也越來復雜,為了更好地工程化,前后端分離的架構更加流行。可以認為是把 V 層從 MVC 中抽離出來成為單獨的項目,后端就只剩下 M 層和 C 層。本項目中,前端為移動客戶端,包括安卓和 iOS 兩部分,后端包括模型和控制器兩層。
對於后端部分,可以繼續細分,分為三層。
- Controller:控制器,負責處理路由、參數校驗、請求轉發。
- Service:服務層,定義業務邏輯和業務流程。
- DAO:負責數據的持久化工作。
微服務
在模塊化思想的指導下目前主要有兩種軟件架構模式,即傳統單體集中式(Monolithic)架構與微服務(Microservice)架構。本項目使用微服務架構,整個系統由一系列獨立的微服務共同組成。每個微服務單獨部署,跑在自己的進程中,也就是說每個微服務可以有一個自己獨立的運行環境和軟件堆棧。
按照功能,本項目可以划分為以下幾個微服務。
- 用戶服務
- 購票服務
- 訂單服務
- 支付服務
軟件架構風格與策略
C/S
Client/Server(C/S)和Browser/Server(B/S)是我們常用的對軟件的網絡結構特點的表述方式,但它們背后蘊含着一種普遍存在的軟件架構風格,即客戶-服務模式的架構風格。
在客戶-服務模式中,客戶是主動的,服務是被動的。例如在本項目中,用戶使用客戶端查詢車票,客戶端向服務器發送查詢請求,服務器處理好請求后,將結果傳回客戶端。這種方式具有典型的模塊化特征,降低了系統中客戶端和服務端之間的耦合度,提高了服務構件的可重用性。
CRUD
CRUD是 Create、Retrieve、Update、Delete 的縮寫,是四種數據庫持久化信息的基本操作。同時 CRUD 也是一種圍繞中心化管理系統關鍵數據的軟件架構風格。
在本項目中,核心數據根據功能需求可以分為用戶信息、車次信息、車票信息等,購票系統的功能都需要圍繞這些關鍵數據進行開發。所以,本項目也符合 CRUD 架構風格,軟件整體以數據為中心。
接口API
本項目主要提供 HTTP 接口,接口定義遵循 RESTful 設計風格。
本項目中部分接口 API 如下:
接口名稱 | 接口地址 | 請求方式 | 請求參數 | 響應信息 |
---|---|---|---|---|
用戶注冊 | /user/register | POST | username, password | code, msg 是否注冊成功 |
用戶登錄 | /user/login | POST | username, password | code, msg 是否登錄成功 |
獲取所有站點信息 | /search/allstations | GET | ||
查詢余票 | /search/remainder | GET | startCity, endCity, date, type | 余票信息 |
項目的不同視圖
軟件架構模型是通過一組關鍵視圖來描述的,同一個軟件架構,由於選取的視角不同可以得到不同的視圖,這樣一組關鍵視圖搭配起來可以完整地描述一個邏輯自洽的軟件架構模型。一般來說,我們常用的幾種視圖有分解視圖、依賴視圖、泛化視圖、執行視圖、實現視圖、部署視圖和工作任務分配視圖。
分解視圖
實現視圖
項目實現的代碼目錄結構大致如下
├── rpc grpc相關的接口和協議文件
│ ├── pay pay服務器的rpc代碼, 同理如果是user服務應該在該文件夾下建立user文件夾
│ ├── proto .proto文件存放
│ ├── client grpc客戶端, grpc服務再server中自己實現
├── server 每個微服務項目
│ ├── candidate 候補服務器
│ ├── controller 控制層,數據的接受的校驗
│ ├── service 服務層,業務邏輯
│ ├── model 模型層,與數據庫連接
│ ├── redis 緩存連接
│ ├── setting 配置服務
│ ├── config 配置文件存放
│ ├── pay 支付服務器
├── reticket 退票服務器
├── search 搜索
│ ├── dynamic 動態搜索
│ ├── static 靜態搜索
├── ticket 購票服務器
├── user 用戶服務器
├── ticketPool 線程池服務,主要是對內提供服務
部署視圖
數據庫設計
用戶
屬性名 | 類型 | 注釋 |
---|---|---|
id | int | 用戶ID |
username | varchar | 用戶名 |
password | varchar | 密碼 |
name | varchar | 姓名 |
id_type | int | 證件類型 |
id_number | int | 證件號碼 |
sex | int | 性別 |
varchar | ||
passenger_type | int | 乘客類型(成人/學生) |
register_time | datetime | 注冊時間 |
聯系人
屬性名 | 類型 | 注釋 |
---|---|---|
id | int | 聯系人信息ID |
user_id | int | 用戶ID |
contact_name | int | 聯系人姓名 |
contact_number | varchar | 聯系人電話 |
contact_id_type | int | 聯系人證件類型 |
contact_id_number | varchar | 聯系人證件號碼 |
contact_passenger_type | int | 聯系人乘客類型 |
車次
屬性名 | 類型 | 注釋 |
---|---|---|
id | int | 車次ID |
name | varchar | 車次名稱 |
train_type | int | 車次類型(K/D/G) |
starting_station_id | int | 起點站ID |
terminal_station_id | int | 終點站ID |
starting_station_name | int | 起點站名稱 |
terminal_station_name | int | 終點站名稱 |
starting_time | datetime | 車次出發時間 |
terminal_time | datetime | 車次到達時間 |
站點
屬性名 | 類型 | 注釋 |
---|---|---|
id | int | 站點ID |
name | varchar | 站點名稱 |
city | varchar | 城市名稱 |
車次區間
屬性名 | 類型 | 注釋 |
---|---|---|
id | int | 區間ID |
train_id | int | 車次ID |
station_id | int | 站點ID |
order | int | 站點順序 |
訂單
屬性名 | 類型 | 注釋 |
---|---|---|
id | int | 訂單ID |
user_id | int | 訂單創建者ID |
train_id | int | 車次ID |
train_date | date | 車次出發日期 |
starting_station_id | int | 出發站ID |
terminal_station_id | int | 到達站ID |
price | int | 總金額(分) |
is_paid | int | 是否已支付 |
paid_time | datetime | 支付時間 |
created_at | datetime | 創建時間 |
訂單詳情
屬性名 | 類型 | 注釋 |
---|---|---|
id | int | 訂單詳情ID |
order_id | int | 訂單ID |
passenger_name | int | 乘客姓名 |
passenger_id_type | int | 乘客證件類型 |
passenger_id_number | varchar | 乘客身份證號 |
passenger_type | int | 乘客類型 |
seat_type | int | 座位類型 |
carriage_number | int | 車廂號 |
seat_number | int | 座位號(排) |
seat_location | char | 座位位置(ABCDEF) |
車票信息
屬性名 | 類型 | 注釋 |
---|---|---|
id | int | 車票ID |
train_id | int | 車次ID |
starting_station_name | varchar | 出發站名稱 |
terminal_station_name | varchar | 到達站名稱 |
starting_time | datetime | 出發日期時間 |
seat_type | int | 座位類型 |
carriage_number | int | 車廂號 |
seat_number | int | 座位號(排) |
軟件運行環境及技術選型
運行環境:使用 Docker 容器化技術部署。
主要技術:
- Gin:Go 語言輕量級 Web 框架
- gRPC:基於 Protobuf 的跨語言開源 RPC 框架
- MySQL:關系型數據庫
- Redis:Key-Value 數據庫
概念原型核心工作機制示例
- 用戶未登錄時,可以以游客身份使用系統,此時只可以進行查詢操作。
- 用戶注冊后,成為注冊用戶。
- 注冊用戶登錄后,可以使用用戶信息管理、查詢、購票、改簽、退票等功能。
- 購票操作需要填寫乘客信息和一些選項,購買成功后進入待支付狀態。
- 支付成功后,訂單完成,出票。