測:云開發(fā)實(shí)戰(zhàn)體驗(yàn)與避坑指南)
這幾年云開發(fā)平臺(tái)層出不窮但真正能把“云開發(fā)”這個(gè)概念在國內(nèi)落地成一套完整體系的騰訊云 CloudBase 算其中一個(gè)。我前后在幾個(gè)項(xiàng)目里用過 CloudBase包括小程序后端、H5 活動(dòng)頁、還有內(nèi)部工具系統(tǒng)從最開始“圖省事試試”到后來把它寫進(jìn)技術(shù)選型方案中間踩過不少坑也真香過很多次。這篇就把我對騰訊云 CloudBase 的完整評(píng)價(jià)寫出來不吹不黑全是實(shí)際用過之后的體感適合正在糾結(jié)要不要上云開發(fā)、或者剛接觸 CloudBase 想搞清楚它到底能干什么的開發(fā)者參考。1. 先用大白話搞清楚 CloudBase 到底是個(gè)啥1.1 云開發(fā)模式的本質(zhì)把后端技術(shù)棧變成云服務(wù)以前我們做一個(gè)帶后端的項(xiàng)目常規(guī)路徑是這樣的買服務(wù)器、裝操作系統(tǒng)、配 Nginx、裝數(shù)據(jù)庫、寫后端接口、處理鑒權(quán)、部署上線然后還要擔(dān)心流量大了怎么辦、數(shù)據(jù)庫掛了怎么恢復(fù)。這一套下來光環(huán)境搭建就能消耗一兩天更別提后續(xù)維護(hù)。CloudBase 想做的事情就是把這些“基礎(chǔ)設(shè)施”全部變成開箱即用的云服務(wù)。你不再需要關(guān)心服務(wù)器在哪、用的什么系統(tǒng)、數(shù)據(jù)庫怎么安裝只需要在控制臺(tái)開通一個(gè)環(huán)境就能直接使用云數(shù)據(jù)庫、云函數(shù)、云存儲(chǔ)、靜態(tài)托管這些能力。前端的代碼可以直接調(diào)用后端能力身份認(rèn)證、權(quán)限控制這些也都有現(xiàn)成的方案。我自己的理解是這就像以前家里用水要自己挖井、自己裝水泵現(xiàn)在打開水龍頭就有水。云開發(fā)的本質(zhì)就是把這個(gè)“供水系統(tǒng)”交給專業(yè)團(tuán)隊(duì)維護(hù)你只需要關(guān)心業(yè)務(wù)本身。騰訊云 CloudBase 把數(shù)據(jù)庫、函數(shù)計(jì)算、對象存儲(chǔ)、托管這些能力打包在一起讓開發(fā)者用一套 SDK 就能打通前后端。1.2 它和云服務(wù)器 CVM 的本質(zhì)區(qū)別很多人在搜“騰訊云怎么開放所有端口”“騰訊云如何申請二級(jí)域名”這類問題大概率是買過騰訊云的云服務(wù)器 CVM習(xí)慣了“自己裝環(huán)境、自己配網(wǎng)絡(luò)”的思路。但 CloudBase 和 CVM 完全是兩種東西。CVM 給你是一臺(tái)空機(jī)器裝什么你說了算但對應(yīng)的安全組、防火墻、端口、環(huán)境變量、進(jìn)程守護(hù)全要自己管。CloudBase 給你是打包好的能力你用的時(shí)候不需要關(guān)心端口開沒開、環(huán)境變量配在哪只需要調(diào)用它提供的接口和 SDK。我見過一些朋友剛開始用 CloudBase下意識(shí)去找“開放所有端口”的功能結(jié)果找了半天也沒找到最后來問我。其實(shí)這就是思路沒切換過來。CloudBase 的默認(rèn)域名、調(diào)用方式都是平臺(tái)幫你規(guī)劃好的你不需要也沒辦法去“開放端口”反而省了很多事。這個(gè)區(qū)別理解了CloudBase 的設(shè)計(jì)邏輯就通了一半。1.3 適合誰、不適合誰用了一段時(shí)間后我的判斷是這樣的適合使用 CloudBase 的場景不適合使用 CloudBase 的場景微信小程序/公眾號(hào)后端復(fù)雜微服務(wù)架構(gòu)H5 活動(dòng)頁、營銷頁面強(qiáng)計(jì)算、高性能密集型任務(wù)快速驗(yàn)證產(chǎn)品 MVP已有龐大自建服務(wù)需要深度定制前端為主的小團(tuán)隊(duì)有嚴(yán)格的私有化部署要求內(nèi)部工具、輕量后臺(tái)需要復(fù)雜 SQL 查詢和事務(wù)的業(yè)務(wù)簡單說如果你的核心訴求是“快速把產(chǎn)品做出來跑起來”CloudBase 非常合適如果你的核心訴求是“對每一層基礎(chǔ)設(shè)施都有絕對掌控力”那還是老老實(shí)實(shí)用 CVM 自建吧。后面我所有的評(píng)價(jià)都是基于“它適合的場景”來聊的。2. 核心能力逐個(gè)拆解到底好不好用2.1 云數(shù)據(jù)庫文檔型模型的上手體驗(yàn)與坑CloudBase 的數(shù)據(jù)庫是文檔型數(shù)據(jù)庫格式上類似 MongoDB每條記錄是一個(gè) JSON 對象集合就是一張“表”。對于前端開發(fā)來說這個(gè)模型很友好因?yàn)椴僮鞯臄?shù)據(jù)本身就是 JavaScript 對象前端拿到就能直接用省掉了 ORM 映射那一層。它可以做到在前端直接讀寫數(shù)據(jù)庫前提是配置好安全規(guī)則。比如一個(gè)公開的留言板你可以設(shè)置“所有人可讀僅創(chuàng)建者可寫”這樣前端代碼里一句db.collection(messages).add({...})就能寫入數(shù)據(jù)不需要自己寫后端接口。但這里我要重點(diǎn)提醒一個(gè)坑文檔型數(shù)據(jù)庫雖然在靈活性和上手速度上很占優(yōu)勢但如果你習(xí)慣了 MySQL 那種多表 join在 CloudBase 里會(huì)非常痛苦。它本身不支持跨集合 join需要你提前設(shè)計(jì)好數(shù)據(jù)冗余或者在云函數(shù)里手動(dòng)做多次查詢再合并。我第一個(gè)用 CloudBase 做的項(xiàng)目是一個(gè)帶評(píng)論功能的資訊類小程序一開始按關(guān)系型數(shù)據(jù)庫的思路設(shè)計(jì)把用戶信息和評(píng)論分兩個(gè)集合結(jié)果查評(píng)論列表的時(shí)候發(fā)現(xiàn)要循環(huán)查用戶表代碼寫得很別扭。后來改成把用戶昵稱、頭像冗余到評(píng)論記錄里一次查詢就搞定性能也好了不少。還有一點(diǎn)要注意就是數(shù)據(jù)庫索引。CloudBase 控制臺(tái)支持創(chuàng)建索引但要主動(dòng)去配。如果集合數(shù)據(jù)量大了又沒建索引查詢會(huì)明顯變慢費(fèi)用也會(huì)漲。我建議不管數(shù)據(jù)量大小先把常用的查詢字段索引建好這個(gè)習(xí)慣能省很多事。2.2 云函數(shù)后端邏輯怎么跑冷啟動(dòng)問題云函數(shù)算得上 CloudBase 的“后端引擎”。你可以用 Node.js 寫函數(shù)把不能暴露在前端的業(yè)務(wù)邏輯、需要鑒權(quán)的操作、多集合的事務(wù)性處理都放在這里。函數(shù)聲明方式很簡單導(dǎo)出main方法就行exports.main async (event, context) { // event 是調(diào)用時(shí)傳入的參數(shù) // context 包含函數(shù)運(yùn)行環(huán)境信息 const { name } event; return { code: 0, data: hello ${name} }; };部署之后前端可以通過 SDK 調(diào)用const res await app.callFunction({ name: hello, data: { name: CloudBase } });也可以在控制臺(tái)配置 HTTP 訪問路徑用普通axios或者fetch直接請求curl -X POST https://your-env-id.service.tcloudbase.com/hello \ -H Content-Type: application/json \ -d {name: CloudBase}這個(gè)“HTTP 訪問服務(wù)”能力我特別建議大家用起來。它意味著云函數(shù)不只是小程序?qū)偃魏?Web 項(xiàng)目、第三方系統(tǒng)都能通過普通的 HTTP 請求對接。說回云函數(shù)本身最大的體感問題是冷啟動(dòng)。當(dāng)你的服務(wù)一段時(shí)間沒有請求進(jìn)來下一次請求到達(dá)時(shí)平臺(tái)需要重新拉起一個(gè)運(yùn)行實(shí)例這個(gè)過程會(huì)帶來額外延遲。我實(shí)測下來冷啟動(dòng)時(shí)接口響應(yīng)偶爾會(huì)到 1 到 3 秒平時(shí)熱啟動(dòng)基本在 100 毫秒左右。如果你的業(yè)務(wù)對響應(yīng)延遲非常敏感比如實(shí)時(shí)聊天、在線協(xié)作建議提前做個(gè)?;畈呗员热缬枚〞r(shí)觸發(fā)器每隔幾分鐘調(diào)一次關(guān)鍵函數(shù)把實(shí)例“暖”起來。雖然多花一點(diǎn)點(diǎn)調(diào)用次數(shù)費(fèi)用但體驗(yàn)會(huì)好很多。2.3 云存儲(chǔ)與靜態(tài)托管前端資源的最后一公里云存儲(chǔ)這塊就像一個(gè)自帶 CDN 的對象存儲(chǔ)主要是放圖片、視頻、文件之類。前端可以通過 SDK 直接上傳和下載也可以生成臨時(shí)鏈接給用戶訪問。我特別常用的是“匿名上傳 安全規(guī)則限制”的組合比如頭像上傳前端拿到臨時(shí)憑證后直接傳不需要經(jīng)過云函數(shù)轉(zhuǎn)發(fā)省流量也省時(shí)間。靜態(tài)托管則適合部署純前端項(xiàng)目。把打包后的 HTML、CSS、JS 傳上去平臺(tái)自動(dòng)給你一個(gè)默認(rèn)域名還能配置自定義域名。我自己比較喜歡用它來部署文檔站、后臺(tái)管理頁面這些純前端的東西省掉了 Nginx 配置的麻煩。不過要提醒的是國內(nèi)云廠商的解析機(jī)制是共通的如果你想用自己買的域名綁定靜態(tài)托管或者云函數(shù)通常需要按服務(wù)商要求完成對應(yīng)配置。這不是 CloudBase 獨(dú)有的問題但我第一次配的時(shí)候確實(shí)折騰了一會(huì)兒。建議提前準(zhǔn)備好可用域名綁定過程會(huì)順暢很多。2.4 身份認(rèn)證匿名登錄、自定義登錄的取舍CloudBase 自帶一套身份認(rèn)證體系支持匿名登錄、郵箱密碼登錄、手機(jī)號(hào)登錄還支持自定義登錄。在這個(gè)基礎(chǔ)上安全規(guī)則才能區(qū)分“所有人”和“某個(gè)用戶”。匿名登錄這個(gè)設(shè)計(jì)我一開始沒太理解后來發(fā)現(xiàn)它真的有用。用戶打開小程序還沒授權(quán)手機(jī)號(hào)的時(shí)候你可以先讓他匿名登錄拿到一個(gè)臨時(shí)的用戶標(biāo)識(shí)等他要下單、要發(fā)布內(nèi)容的時(shí)候再引導(dǎo)他綁定手機(jī)號(hào)。這個(gè)流程既不影響體驗(yàn)又能把關(guān)鍵操作與用戶身份關(guān)聯(lián)起來。安全規(guī)則是這套體系的關(guān)鍵。它用 JSON 形式聲明“誰能讀、誰能寫”比如{ read: true, write: doc._openid auth.openid }意思是這個(gè)集合所有人可讀但只有記錄創(chuàng)建者自己能寫。這個(gè)配置我踩過坑之前有個(gè)項(xiàng)目給某個(gè)集合配了寬泛的寫權(quán)限結(jié)果線上被人刷了一堆垃圾數(shù)據(jù)。從那以后我對安全規(guī)則的審核就特別仔細(xì)尤其是客戶端直連數(shù)據(jù)庫的權(quán)限一定要最小心。3. 實(shí)操全流程一個(gè)留言板應(yīng)用從零到上線前面聊的都是概念這一節(jié)我完整走一遍流程拿 CloudBase 做一個(gè)帶數(shù)據(jù)庫的留言板包含云函數(shù)、數(shù)據(jù)庫集合、前端調(diào)用三個(gè)部分。這套流程我實(shí)際跑過很多遍照著做基本不會(huì)出錯(cuò)。3.1 創(chuàng)建環(huán)境和安裝工具第一步在騰訊云控制臺(tái)里搜索“云開發(fā) CloudBase”進(jìn)入產(chǎn)品頁后點(diǎn)擊“開通”然后創(chuàng)建一個(gè)環(huán)境。環(huán)境可以理解成一個(gè)隔離空間所有數(shù)據(jù)庫、函數(shù)、存儲(chǔ)都在環(huán)境下面。環(huán)境 ID 是一串類似my-app-xxxxx的字符串后面所有調(diào)用都要用到它。第二步安裝命令行工具。CloudBase 提供了 CLI本地開發(fā)和部署會(huì)方便很多npm install -g cloudbase/cli tcb login登錄成功后在項(xiàng)目目錄下執(zhí)行tcb init按提示選擇剛才創(chuàng)建的環(huán)境。初始化之后項(xiàng)目里會(huì)出現(xiàn)functions目錄每個(gè)子目錄就是一個(gè)云函數(shù)。3.2 建集合和寫云函數(shù)在控制臺(tái)的“數(shù)據(jù)庫”頁面新建一個(gè)集合名字叫messages用于存留言數(shù)據(jù)。集合不用預(yù)先定義字段因?yàn)槲臋n型數(shù)據(jù)庫是動(dòng)態(tài)結(jié)構(gòu)的直接往里寫就行。然后創(chuàng)建一個(gè)云函數(shù)我給它起名addMessage。在functions/addMessage/index.js里寫const cloud require(cloudbase/node-sdk); exports.main async (event, context) { const app cloud.init({ env: cloud.SYMBOL_CURRENT_ENV }); const db app.database(); const { content, nickName } event; if (!content) { return { code: 1, message: content 不能為空 }; } const res await db.collection(messages).add({ content, nickName: nickName || 匿名用戶, _openid: context.auth context.auth.openid, createdAt: db.serverDate() }); return { code: 0, data: res.id }; };再建一個(gè)查詢云函數(shù)getMessagesconst cloud require(cloudbase/node-sdk); exports.main async (event, context) { const app cloud.init({ env: cloud.SYMBOL_CURRENT_ENV }); const db app.database(); const res await db.collection(messages) .orderBy(createdAt, desc) .limit(20) .get(); return { code: 0, data: res.data }; };部署這兩個(gè)函數(shù)tcb fn deploy addMessage tcb fn deploy getMessages這里用到了cloudbase/node-sdk在函數(shù)目錄下執(zhí)行npm install安裝即可。需要注意_openid這個(gè)字段在云函數(shù)里不一定自動(dòng)注入所以要手動(dòng)從context.auth里取前端調(diào)用時(shí)平臺(tái)會(huì)帶上身份信息。3.3 前端聯(lián)調(diào)與 HTTP 訪問如果前端是小程序直接用官方封裝好的wx.cloud調(diào)用如果是 H5 項(xiàng)目安裝cloudbase/js-sdknpm install cloudbase/js-sdk初始化import cloudbase from cloudbase/js-sdk; const app cloudbase.init({ env: your-env-id });寫入一條留言await app.callFunction({ name: addMessage, data: { content: 第一條留言, nickName: 測試用戶 } });查詢留言const res await app.callFunction({ name: getMessages, data: {} }); console.log(res.result.data);如果你不想用 SDK也可以給云函數(shù)配置 HTTP 訪問路徑。在控制臺(tái)的“云函數(shù) → HTTP 訪問服務(wù)”里添加路徑比如/getMessages之后直接請求對應(yīng) URL 就可以了。這個(gè)方式對第三方系統(tǒng)對接很友好。3.4 日志查看與本地調(diào)試調(diào)試云函數(shù)最直接的方式是去控制臺(tái)看日志。CloudBase 的云函數(shù)日志會(huì)打印每一次調(diào)用的輸入、輸出和console.log內(nèi)容。我排查問題基本都是先在代碼里多打幾個(gè)日志然后去控制臺(tái)看。本地調(diào)試可以用tcb fn run addMessage --param {content:實(shí)時(shí)測試}這個(gè)命令會(huì)直接調(diào)用云端函數(shù)并把結(jié)果打印出來不用寫前端頁面就能驗(yàn)證邏輯。這個(gè)功能我?guī)缀趺總€(gè)函數(shù)都會(huì)用效率比反復(fù)改前端代碼高很多。4. 用了一段時(shí)間后的真實(shí)評(píng)價(jià)優(yōu)點(diǎn)、槽點(diǎn)、避坑清單4.1 讓我覺得順手的地方先說優(yōu)點(diǎn)。第一是上手速度快。一個(gè)只有前端經(jīng)驗(yàn)的開發(fā)者花半天了解一下數(shù)據(jù)庫和安全規(guī)則就能寫出帶后端的完整應(yīng)用。這點(diǎn)對獨(dú)立開發(fā)者和前端團(tuán)隊(duì)意義太大了。第二是微信生態(tài)的深度整合。CloudBase 和微信小程序、公眾號(hào)的配合是天然優(yōu)勢很多能力和微信登錄體系是無縫銜接的。如果你本來就是做微信小程序CloudBase 幾乎是最省力的后端選擇。第三是免費(fèi)額度夠起步用。新用戶開通后有免費(fèi)額度做原型、做學(xué)習(xí)項(xiàng)目完全夠用。等業(yè)務(wù)量上來后再切換付費(fèi)套餐前期成本壓力很小。騰訊云開發(fā)者社區(qū)里也有不少實(shí)戰(zhàn)案例遇到問題搜一下基本能找到解法。4.2 讓我皺眉的地方槽點(diǎn)也不是沒有。最讓我糾結(jié)的是供應(yīng)商鎖定。一旦業(yè)務(wù)深度依賴 CloudBase 的數(shù)據(jù)庫、函數(shù)、存儲(chǔ)后面想遷回自建服務(wù)器或者換到別的平臺(tái)工作量會(huì)非常大。所以如果在項(xiàng)目啟動(dòng)階段就知道未來可能有復(fù)雜的自建需求我建議慎重或在架構(gòu)上做一些抽象把對平臺(tái)的調(diào)用封裝起來。第二個(gè)槽點(diǎn)是計(jì)費(fèi)。按量付費(fèi)的模式下流量費(fèi)用和數(shù)據(jù)操作次數(shù)累積起來并不便宜尤其是 C 端產(chǎn)品用戶量大了以后月賬單可能會(huì)超出預(yù)算。我建議在項(xiàng)目初期就做好費(fèi)用監(jiān)控給環(huán)境設(shè)置預(yù)算告警避免月底收到賬單才反應(yīng)過來。第三個(gè)槽點(diǎn)是復(fù)雜業(yè)務(wù)受限。文檔型數(shù)據(jù)庫不適合強(qiáng)事務(wù)、強(qiáng)關(guān)聯(lián)的業(yè)務(wù)場景云函數(shù)的運(yùn)行時(shí)長和資源也有上限。如果你已經(jīng)預(yù)見到核心業(yè)務(wù)會(huì)用大量復(fù)雜 SQLCloudBase 可能不是最優(yōu)解。4.3 常見問題排查速查表報(bào)錯(cuò)/現(xiàn)象可能原因解決方法調(diào)用云函數(shù)提示找不到環(huán)境env ID 寫錯(cuò)或未初始化到控制臺(tái)確認(rèn)環(huán)境 ID檢查cloudbase.init參數(shù)數(shù)據(jù)庫寫入無權(quán)限安全規(guī)則限制檢查集合安全規(guī)則確認(rèn)登錄狀態(tài)云函數(shù)請求響應(yīng)特別慢冷啟動(dòng)配置定時(shí)觸發(fā)器保活或接受低頻場景下偶發(fā)延遲前端請求跨域報(bào)錯(cuò)未配置合法域名在控制臺(tái)添加域名白名單或用云函數(shù)代理請求靜態(tài)托管資源 404路徑大小寫或目錄結(jié)構(gòu)問題確認(rèn) dist 目錄上傳完整文件路徑大小寫敏感費(fèi)用異常上漲循環(huán)調(diào)用或索引缺失檢查代碼是否有死循環(huán)給高頻查詢字段建索引設(shè)置預(yù)算告警還有一個(gè)特別重要的提醒不要在生產(chǎn)環(huán)境輕易刪除環(huán)境。CloudBase 刪除環(huán)境會(huì)把里面的數(shù)據(jù)庫、函數(shù)、存儲(chǔ)全部清空而且這個(gè)過程沒有二次確認(rèn)的余地我身邊就有朋友手一抖把測試環(huán)境數(shù)據(jù)全刪了。建議把生產(chǎn)環(huán)境和測試環(huán)境分開重要數(shù)據(jù)定期用控制臺(tái)的“數(shù)據(jù)導(dǎo)出”功能做備份。結(jié)尾的內(nèi)容我更想說說選型時(shí)的取舍。就我個(gè)人而言如果你做的是小程序、H5 活動(dòng)頁、內(nèi)部工具這類偏前端驅(qū)動(dòng)的項(xiàng)目團(tuán)隊(duì)里沒有專職后端CloudBase 就是目前國內(nèi)性價(jià)比很高的選擇它能讓你把精力集中在業(yè)務(wù)邏輯上而不是服務(wù)器運(yùn)維上。但如果你做的是數(shù)據(jù)關(guān)系極其復(fù)雜、需要深度定制基礎(chǔ)設(shè)施的核心系統(tǒng)那就別硬上云開發(fā)該用 CVM 自建還是自建。我在實(shí)際項(xiàng)目中的體會(huì)是CloudBase 不是一個(gè)適合所有場景的銀彈但它確實(shí)把“云開發(fā)”這件事的門檻降到了很低的程度。理性的做法不是問“它好不好”而是問“它適不適合我現(xiàn)在這個(gè)項(xiàng)目的階段”。起步階段用它快速驗(yàn)證等產(chǎn)品跑通后再考慮瓶頸問題這個(gè)策略對我來說一直很有效。最后分享一個(gè)小技巧新項(xiàng)目上線前記得在控制臺(tái)把數(shù)據(jù)庫所有集合的權(quán)限規(guī)則整理一遍把不必要的寫權(quán)限全部關(guān)閉這個(gè)習(xí)慣能幫你省掉后面大量的數(shù)據(jù)安全問題。