
作者|陳聰(有馬)
出品|阿裡巴巴新零售淘系技術部
導讀:在新零售時代,如何提升線下業務的可用性是一個極其重要的命題,本文從阿裡巴巴未來酒店:Flyzoo Hotel 項目出發,介紹了在過程中對這個命題的通用思考,與具體落地的解決方案。
在阿裡未來酒店項目中,筆者首次接觸了不少線下業務,因為業務的需要,其中大部分是由線下( Android )裝置來達成的,如 CheckIn 與 CheckIn 裝置,電梯與梯控裝置,客房門與門控裝置,早餐與早餐核銷裝置等。
在提高業務可用性的問題上,經曆手淘多年的發展,雖然積累了大量可供選擇的高可用中間件,但對于酒店這類線下為主的業務,由于線下相比線上,在業務形态與裝置環境上有着較大的不同,自然會影響到解題的思路,以及解法的 trade-off,進而會推演出不同的思路與方案。
本文主要介紹對于線下裝置可用性方向上的思考,以及基于此而落地的架構與解法,希望能達到一定的抛磚引玉的效果。
1、當我們談論線下可用性的時,在讨論什麼
線下業務中,對于那部分以線下裝置為核心的業務而言,提高業務可用性的核心是提高裝置可用性,更确切而言,是減少裝置對使用者可感覺的,業務功能不可用的時長。
而如何提升的方向,可從線下業務與技術相比線上的不同來着手分析。
1.1 業務上的不同思考
在業務上,線下相比線上主要有如下3個不同點:
1.裝置專一業務、業務專一功能
- 即 CheckIn /門控/梯控等裝置隻裝對應 App,隻負責對應業務,隻提供對應功能。
- 一旦 App 功能不可用,就會演變成整個裝置不可用
2.使用者使用裝置的時間是離散和随機的。
- 事實上,大部分時間是沒被使用的,但此時裝置還是通電通網的
3.使用者容忍度差,遇到問題時需盡快解決和解釋
- 畢竟不像線上業務,購物車挂了還能看商品詳情,或者玩别的App
由上述特點,我們認為:
1.提升裝置主 App(以及相關核心依賴)的可用性至關重要。
- 同時, 業務上也需準備周到的降級方案(如機器 checkin -> 人工 checkin ,人臉開門 -> 房卡開門)
2.在使用者使用裝置提供的業務前,我們有很多時機來檢查、感覺,甚至解決問題。
- 如能提前解決,則在使用者視角而言是沒有發生問題的。
- 若不能,也可提前告知使用者,準備降級,這會比被使用者主動發現問題的體驗更好
3.為了加快排查與解決問題的速度,要為問題排查準備可及時擷取的,充足的問題上下文。
- 特别的,酒店這種全場景人臉的線下業務,還需要大量圖像和深度的上下文
1.2 技術上的不同與思考
技術上,由于線下裝置的資源完全可被利用、控制、保障
進而有不少與線上不同的地方,如:
- 裝置永久線上(不線上時,也不存在運維一說,隻能去現場了)
- 裝置空間無限(即在用完磁盤前,空間都是這個業務的)
- 處理能力獨占(除系統服務,主要就是自己的 App 了)
- 無需考慮耗電, 無需考慮裝置碎片化, App 可快速更新
- 系統能力可深度定制,如可在 OS 層提供程序保活的能力,OS 層的資料安全保護等
- 等等...
是以線上可用性與穩定性的某些方向與優化,可能線上下不是那麼重要, 如熱更新、啟動速度、本地日志大小控制&壓縮、減少日志對性能的部分損耗等
而更需考慮的是:
如何在不影響業務 App 運作的情況下,去用(比線上)更多的資源(計算/存儲/網絡)來交換可用性。
1.3 分解目标
綜上推理,提高線下裝置可用性可進一步分解為
通過充分利用裝置資源來達成
- 提前預防問題
- 快速排查問題
2、架構層的解決方案- ShadowKnight
基于上述思路和兩個核心子目标,我們設計了 ShadowKnight(以下簡稱 SK )這款架構,來幫助業務更簡單地達成這兩個子目标。
下文介紹下該架構的設計思路與方案。
2.1 如何提前預防問題
該目标通過三步完成:
1.建立狀态(State)的标準與基礎設施
- 業務可快速與友善地将感興趣的終端狀态暴露給架構 (如目前攝像頭是否可用、LED 燈是否可用、門控狀态機目前狀态、門控目前藍牙鑰匙資訊等)。
- 架構按照排程政策周期性地将裝置目前狀态同步到雲端(diff or 全量),并展示到 Web 上。
- 業務可基于此快速診斷裝置
2.基于統一的 State 标準,建構統一的,業務可配置的雲端(釘釘)報警
- 業務可基于此更快速與便利地得知裝置的問題發生
3.建立能力( Skill )的标準與基礎設施
- 業務可快速與友善地将感興趣的終端能力暴露給架構 (如應用重新開機,攝像頭拍照,應用重裝,日志拉取、更新鑰匙等)。
- 架構和雲端打通,可通過雲端接口或Web互動來執行端側Skill,并擷取結果。
- 報警觸發時,可以自動(基于 State 提前配置)或手動地執行一系列Skill去快速解決問題
此外,為了盡量降低架構複雜度,業務暴露 State/Skill 隻需要标注注解或實作接口,而具體的注冊或發現由 SK 的 gradle 插件在編譯時分析與生成位元組碼完成。
2.1.1 兩種不同的 State 暴露方式
針對不同場景,SK 設計了兩類狀态暴露方式以滿足不同場景需求。
健康檢查即狀态
業務可通過實作架構的 HealthCheck 接口(有 Major、Minor 兩種來滿足不同細分場景),來暴露狀态。
架構會基于可配置的排程政策,定期調用這些健康檢查執行個體,擷取結果,并在合适的時機合并、上報狀态。
舉個例子:
@HealthChecker("sk.check.minor.camera")
public class CameraHealthChecker implements MinorHealthCheckElement {
@Override
public void acceptMinorCheck(@NonNull HealthCheckVisitor healthCheckVisitor) {
// ...實作具體的檢查邏輯,獲得結果checkResult
healthCheckVisitor.submitCheckResult(this, checkResult, null);
}
适合那些需要發起特定調用才能拿到的狀态,并且可能有一定成本或者需要一定時間。如門控燈是否可用,藍牙開鎖鍊路是否通暢,磁盤空間剩餘大小,攝像頭目前能否擷取到深度&RGB資料等。
字段即狀态
業務可以直接将類中已存在的字段,将值作為 State 值暴露給架構,架構會自動觀測字段的變化,并在合适的時機合并上報狀态。
@StateWatcher
public class DoorMachine {
// 通過給業務類中已存在的字段的set方法标注注解來暴露
@KnightState(value = "sk.door.machine.state")
private void setStateWrapper(@NonNull StateWrapper stateWrapper) {
this.stateWrapper = stateWrapper;
}
}
适合業務對自己類中,已有字段感興趣的場景。比如門控狀态機目前狀态、裝置目前房間号、門控目前鑰匙版本等。
同時該暴露 State 的方案成本更低,能降低不少架構複雜度。
2.2 如何快速排查問題
下面介紹對針對,快速排查問題,這個子目标的思路與解法。
為了設計對應的方案,首先需要分析下問題排查的特點。
2.2.1 問題排查的特點
個人認為問題排查可能有以下3個特點:
1.問題上下文越豐富,排查越容易,但過于豐富時,難度又會上升(如很難從成堆的日志中找到真正有用的那條)
2.不需要排查問題時,豐富的上下文是無用資源,而且還可能要為他們存儲買單。
以酒店門控裝置為例,300台合計一天産生 120 GB 左右的相關日志 (文本+照片+深度)
3.增加上下文的豐富度會帶來開發成本的提升
2.2.2 架構的解決方案
基于此, SK 的解決方案是
1.給業務提供一個幾乎大小不限的高效日志系統,使之可盡可能地多打日志來提升上下文豐富度。
特别的,針對人臉場景,還提供了富日志功能,即單條的日志入參可同時包含文本、圖檔、深度等。
此外,日志系統也會自動打通 State ,進而可以回溯問題發生時的狀态快照
2.日志系統将日志以結構化的方式存儲在邊緣裝置 DB 上。
當想排查問題時,通過在後端或平台頁面上輸入基于問題編寫的 sql 以及其他參數,基于skill,向終端發起一次日志查詢,查詢結果會傳回到 OSS 上。
第2步解決了3個關鍵問題
1.實時性問題,因為裝置永久線上
2.無用資源問題,因為邊緣存儲
3.上下文過多時帶來的排查效率降低問題,因為依靠sql表達能力,可将查詢結果收縮到隻和問題有關的内容。
同時問題的排查 sql 可以作為模闆進行儲存,加速下次排查
最後,為了降低由于要增加上下文,而帶來的開發成本(寫很多日志代碼),SK 提供了基于編譯時位元組碼生成的 AOP 日志的功能來解決
業務可給方法标注注解,運作時,架構會自動将方法上下文轉換為結構化的日志落庫,case 如下:
@Analyzable(useJSON = true)
public void onUnlockFailedAndFinish(FHLockError error) {
// ...業務邏輯
}
2.3 整體鍊路
綜上,以酒店為例,SK 的整體鍊路(橙色部分表示SK提供的部分)如下:
這裡值得一提的是,在酒店中,所有終端裝置的系統架構都是主App + 守護程序的雙程序架構方案,進而讓裝置的運維與業務分離, 具體而言
主 App 負責業務邏輯,以及向 SK 架構注入以業務為主的 State 與 Skill
守護程序負責運維,進而向SK架構注入以運維/ OS /硬體相關的 State 與 Skill ,同時所有 OS 級别的定制 Api 都在這層使用,進而解耦業務 App 與定制化的 OS
2.4 端側架構
下圖是 SK 的端側架構設計,⼀
共分為 7 個子產品。
SK-Protocol:包含 SK 所有注解和上述子產品的核心接口,并提供基于接口依賴注入和執行個體擷取的能力。
進而業務二方包隻需依賴它就行,而 SK 的内部子產品間也可以靠它保持解耦的同時,完成互相調用
SK-Plugin:編譯時的 gradle 插件工程,基于 ASM 提供了 State 與 Analysis 子產品中相關功能的位元組碼增強功能,以及編譯時資訊收集,生成名為 K 的 class 位元組碼,注入Common 包
SK-Common:提供了網絡等上下行功能的注入與實作,進而可讓架構不耦合于酒店環境。以及基于 K-Class 向上提供查詢能力
SK-State:提供了健康檢查,字段檢測,狀态的 merge 與上報等功能。
SK-Analysis:提供問題排查相關能力。最下層是 storage 層,提供 db 管理和富檔案存儲能力,上層是 logger 層,提供 4 類日志接口
SK-Skill:提供了 Skill 管理、執行、調用、結果回傳等功能
SK-Starter:提供 App 編譯時隻需依賴他就能依賴全家桶,以及開發時一行代碼初始化SK所有子產品的功能,來降低接入成本
2.5 架構之上
以 SK 架構為基礎,在上層我們還建構了幾個重要的功能與平台,如訓練資料回流、業務開放、人臉排查等,在酒店中發揮了重要的功能。
2.5.1 人臉排查平台
首先和測試團隊合作,基于 SK-Skill & Analysis 打造了人臉排查平台,實作了基本可以在1min 内排查所有場景人臉的問題。
核心功能是可以在可視化頁面上基于限定條件精準拉取與顯示問題發生時的人臉相關可視化上下文,并帶有業務語義與資訊。
2.5.2 人臉資料回流
然後和 iDST 以及測試團隊合作,基于 SK-Skill & Analysis 打造了人臉資料回流功能,可以每日自動拉取門控上所有訓練角度來說有效的照片以及深度,同時還帶上了詳細的識别資訊,作為訓練資料。
2.5.3 業務功能開放
基于 SK-Skill ,對合作方暴露各類裝置或業務能力,如電梯排程,門控分數調整,裝置發現與測試等。
2.6 酒店實踐
在酒店中,所有的線下 Android 終端裝置均接入了 SK 架構,主要在入場和線上兩個階段産生了一定的作用
2.6.1 入場階段
入場階段,核心作用是保障了所有( Android )裝置硬體與軟體的可用性,幫助與加速業務的進場與上線。
這個階段,由于酒店定制硬體較多,且定制與改造較大,導緻裝置的軟硬體不夠成熟,期間産生種類繁多的全量或随機的問題,如藍牙天線、門控燈帶、攝像頭軟硬體、連接配接線、記憶體洩露、rom 日志、rom 崩潰等等。
我們主要基于 SK 的 State 能力,快速與自動化地發現與定位了大量上述問題,并輔助解決,同時基于 SK 的 Skill 能力去快速實作運維相關需求。
2.6.2 線上階段
線上階段,主要作用是兩點
1.分鐘級别排查業務&裝置相關問題
特别的,通過利用人臉排查平台,以及排查模闆( sql )的積累讓酒店無技術背景的從業人員能獨立排查大部分問題,進而解放技術同學的時間與精力
2.對于未解決問題的提前發現&預防&自動解決
上線後,還有不少合作廠商還未完全解決的問題,會小機率發生在酒店裝置中,在該類問題在徹底解決前,部分通過 SK 的來自動發現與自動解決/規避,部分通過自動發現後降級人工解決
3、結尾
新零售時代,越來越多的公司與團隊會更加重視與發力各類線下業務,而提升線下終端可用性必然是業務對技術非常重要與基礎的要求,希望本文在這個問題上可以給讀到此處的你帶來一點幫助或啟發。