Node開發實踐總結——定時腳本的設計與實現

2021-01-10 Nodejs開發

來源:騰訊IMWeb前端團隊

前言

作為Node語言的初學者去實踐後端開發時,不僅僅有見獵心喜,也有一些忐忑,好在大家都很open,給予了很多建議和分享,到目前為止,也成功建立了三個基於Node.js + TypeScript + IMServer 1 的工程,也是時候將自己最近的學習過程進行總結,下面就以一個小小的開發任務為載體分享下我的成長過程。

需求

在完成Node工程的搭建之後,我接受到第一個Node後臺開發任務:定時將企業微信的組織架構信息拉取到業務資料庫系統中,並且提供手機號查詢用戶查詢接口。一開始對這個任務還是比較樂觀的,信心滿滿的去開發了。

初步方案

經過方案設計之後形成了上述的方案:

在伺服器部署初始化時(init.ts初始啟動文件中)啟動node-schedule的定時任務,讀取資料庫中的企業微信的企業配置,然後並行啟動若干企業的組織架構更新進程。企業微信提供了獲取部門成員的詳情,因此只需並行更新每個部門的信息,並且寫入mysql資料庫中。

3.當查詢接口到達伺服器後,首先從資料庫中查詢該手機號對應的成員,若不存在則從企業微信側調用手機號獲取userid API,然後通過獲取用戶信息API獲取最新的用戶信息,避免定時更新帶來的更新時間gap;若存在則直接返回資料庫中的信息。

開發過程中的踩雷

整體業務邏輯並不複雜,調試和部署的過程中遇到許多問題,這裡給大家一一列舉下:

1.訪問頻率受限

企業微信官方規定同一時間對同一份資源的請求數不可超過一定數值(60),由於部門詳情的請求接口採用的並行模式,因此超過了閾值,測試過程中被官方封禁了IP。

2.過多進程導致SQL慢查詢

沒有考慮多地部署(3地 * 5伺服器 * 8 worker)導致同時存在了120個更新進程,進而導致資料庫mysql的讀寫混亂,也消耗了大量性能,導致資料庫讀寫壓力比較大時,出現了部分慢查詢的情況

3.無效手機號不可調用企業微信api

企業微信對手機號獲取userid的接口,具有以下限制:當查詢中出現一定數量的無效手機號時,會觸發企業微信官方IP封禁。但是業務系統中存在大量離職後的無效手機號,因此當檢查到資料庫中不存在時,頻繁調用上述接口則會觸發封禁。

4.資料庫讀寫衝突

由於存在多臺伺服器同時讀寫資料庫,導致資料庫出現了部分重複、缺少的情況。

5.網絡環境導致讀寫鎖的平衡性失效,產生衍生問題

為了優化上述部分,引入的任務讀寫鎖,保證單一進程更新。但是未考慮各地服務網絡情況,導致內網伺服器一直持有讀寫鎖,失去了均衡負載的設計有效性。也導致在配置預上線環境時,預上線環境由於網絡環境良好一直持有讀寫鎖,進而影響線上的實時數據。

6.未考慮失敗情況進行報警和恢復

深度優化設計

下面介紹下如何解決這些問題和思路和方案。

1、訪問頻率受限

這裡針對「部門成員信息API「的並行請求,改造成基於有效頻率值的串行發送機制,設計成10個/每秒的調用速度。

2、過多進程導致SQL慢查詢

這個解決方案比較明確,就是減少啟動定時任務的進程數。

由於後端服務一般分為測試環境、預上線環境、正式環境,不同的環境中是否需要啟動各個定時器腳本可以通過部署時(以SKTE為例),設置環境變量 「SCHEDULE_ENV」 來管理。

每臺伺服器會啟動8個worker進程,每個worker使用 「 process.env.IMSERVER_WORKER_ID 」 變量進行標識,因此可以設計只有「worker1」進程來進行定時任務的啟動;

3、無效手機號不可調用企業微信api

這個是在技術調研中沒能發現的情況,發現前期技術調研的工作疏忽。

首先是業務調用方是無法得知手機號是否有效,且也不應該去關心這個限制,因此原先為了解決部分新記錄更新不及時的問題,而引入的實時查詢機制是不合理的。

實時查詢機制:「對於資料庫中不存在的手機號,通過企業微信官方api進行實時查詢來返回結果」

因此移除了這個機制,並且提供了一個基於企業微信官方API的實時查詢接口,每次業務方調用時,也將結果同步更新到組織架構中。

4、資料庫讀寫衝突

引入redis任務鎖機制,保證同一時間內只有一個進程能夠進行資料庫更新操作。

其次是企業之間的更新採用並行機制,由於相互之間是互不衝突的,因此不會引起同一條記錄的讀寫衝突,也可以提升其更新速度。

5、網絡環境導致讀寫鎖的平衡性失效,產生衍生問題

在最初的設計中,我希望伺服器之間能夠根據自身的負載情況來進行公平競爭任務鎖,但是實際情況是由於多地部署,其中穩定的內網環境可以一直優先獲取到任務鎖,就是沒有所謂的公平性了。

特別是當壓測需要部署預上線環境時,如果沒有設置只讀db帳號並且沒有設置啟動定時任務環境變量,這兩個失誤會導致某一次的組織架構更新邏輯調整的代碼更新到線上時,線上一直是舊的邏輯在執行,經過一系列排查我們發現預上線環境一直獲取了讀寫鎖,使用舊的邏輯更新資料庫。

因此增加環境變量來控制定時任務啟動、對於壓測的環境的中的資料庫權限進行了區分,增加了只讀模式。

6、報警和錯誤恢復

這裡有一點前端思維定勢的影響了,這一部分是同樣重要的。

報警方面

則是接入IMLog的Node SDK,通過 Kibana 和 Grafana 的系統配置,可以有效監控組織架構的更新情況。

錯誤恢復方面

這裡的錯誤主要是發生在企業微信API的access_token過期的情況,常發生於以下兩種情況:

企業微信官方主動使access_token過期在組織架構更新過程中,access_token剛好失效情況,也就是http傳輸到企業微信剛好失效的情況

以上的情況是無法避免的。這裡使用中間件對node.fetch進行封裝,增加對response的返回值的校驗,如果企業微信api的返回值是 「 WX_CODE.INVALIDE_TOKEN 」 則進行預警和重置accessToken。

export default (app) => { const { utils: { imlogHelper } } = app; const wrapperLogFetch = (originFetch, { traceId, header, client_ip, }) => async (...args) => { const res = await originFetch(...args); if (res.errcode === WX_CODE.INVALIDE_TOKEN) { // 進行更新邏輯 wxService.clearAllRedisKey(); imlogHelper({ cmd: url, message: 'accessToken_update_warning', body: JSON.stringify(res), trace_id: traceId, retcode, headers: header, }); } return res; }; // 覆蓋context.fetch方法return async (ctx, next) => { if (!ctx.logFetch) { const originFetch = ctx.fetch; const { traceId, ip: client_ip } = ctx.request; const header = JSON.stringify(ctx.request.header); const logFetch = wrapperLogFetch(originFetch, { traceId, header, client_ip, }); ctx.logFetch = logFetch; } if (ctx.fetch !== ctx.logFetch) { ctx.fetch = ctx.logFetch; } await next(); }; }

總結

經過重新設計和驗證後形成以上的設計方案,具有以下優化點:

首先通過基於redis setnx實現的任務鎖,來實現同一時間單進程更新資料庫;通過部署時設置定時任務啟動環境變量和資料庫讀寫帳號設置,來保證不同環境的分離;通過企業並行,部門數據拉取接口串行的模式,最大化性能和避免API調用封禁;完善錯誤恢復機制和報警,實時查看運行狀況。

相關焦點

  • 玩客雲 N1 armbian 一鍵部署甜糖CDN 問題總結
    前言之前 保姆級教程 玩客雲 刷armbian 掛甜糖CDN GIF動圖教程 文章引發很多小夥伴的折騰,很多小夥伴反饋命令部署還是比較麻煩,所以一直考慮做個一鍵部署腳本,這不今天有空現學現賣寫了個一鍵部署腳本,同時解答一些小夥伴折騰遇到的常規問題。
  • 復盤node項目中遇到的13+常見問題和解決方案
    執行npm install發生node-gyp報錯的問題在項目開發過程中有時候拉取新的node項目代碼後執行npm install, 會報如下錯誤: node-gyp6. nodejs如何創建定時任務定時任務在後端開發中是很常見的功能之一, 其本質是根據時間規則,系統在後臺自動執行相應的任務.
  • 第二期:「自動避免Namenode的單點故障導致的集群不可用」獲獎公布
    現描述一下大體思路:採用drbd +  heartbeat方案實現name node的HA。drbd實現共享存儲,在drbd的2個伺服器上共享存儲元數據,2臺伺服器對hadoop提供一個同樣的虛擬IP。heartbeat實現心跳監控,所有伺服器都配有雙網卡,其中一個網卡專門用於建立心跳網絡連接。當heartbeat監控到線上的機器掛掉時,會自動的切換到另一臺機器上,對外IP不變。
  • 如何使用 Docker 高效部署 Node 應用 - 51CTO.COM
    [1]❞一個合理並且高效的部署方案,不僅能夠實現快速升級,平滑切換,負載均衡,應用隔離等部署特性,而且配有一套成熟穩定的監控。kubernetes 把 Node 應用視作一個服務端應用的黑盒子,完美匹配了以上條件,越來越多的團隊把 node 部署在 k8s 上。但在此之前,需要先把 Node 應用跑在一個 Docker 容器上,這也是本章的主題。
  • 21 個 JSBox 腳本發布或更新
    Th2ee 開發,發布於 Erots 腳本商店。 再見 開發,發布於 Erots 腳本商店。 Th2ee 開發,發布於 Erots 腳本商店。 Azite 開發,發布於 Erots 腳本商店。 Ren 開發,發布於 Erots 腳本商店。
  • XSS(跨站腳本攻擊)內容總結整理
    XSS(跨站腳本攻擊)內容總結整理跨站腳本攻擊(XSS)XSS 簡介人們經常將跨站腳本攻擊(Cross Site Scripting)縮寫為CSS,但這會與層疊樣式表(Cascading Style Sheets,CSS)的縮寫混淆。
  • Node.js模塊化你所需要知道的事
    有Node.js開發經驗的同學會發現在引用模塊時,不一定非得指定到準確的文件,也可以通過引用目錄來完成對目標模塊的引用,例如:~/learn-node $ mkdir -p node_modules/find-me~/learn-node $ echo "console.log('
  • 編寫Linux Shell腳本的最佳實踐
    具體的來說,對於shell腳本,注釋一般包括下面幾個部分:shebang腳本的參數腳本的用途腳本的注意事項腳本的寫作時間,作者,版權等各個函數前的說明注釋一些較複雜的單行命令注釋參數要規範這一點很重要,當我們的腳本需要接受參數的時候,我們一定要先判斷參數是否合乎規範
  • 基於WebGL的在線3D建模與互動腳本開發 ThingJS
    #三維可視化##3D開發#ThingJS編輯界面布局3D建模與場景搭建方法交互控制腳本開發關鍵點ThingJS平臺基於 WebGL中的3D框架進行3D開發,界面設計採用HTML5,系統腳本採用 JavaScript。
  • Shell 腳本編程最佳實踐
    前言由於工作需要,最近重新開始拾掇shell腳本。雖然絕大部分命令自己平時也經常使用,但是在寫成腳本的時候總覺得寫的很難看。而且當我在看其他人寫的腳本的時候,總覺得難以閱讀。畢竟shell腳本這個東西不算是正經的程式語言,他更像是一個工具,用來雜糅不同的程序供我們調用。
  • 高中學生所開發的一款瀏覽器,用於觀看VIP電影。油猴腳本通用
    從極簡主義者的角度來看,移動瀏覽器必須首先具有簡單的界面,而無需在頁面上堆疊各種信息甚至廣告,然後才可以實現各種功能。基於這兩點,當前有很多瀏覽器可供選擇。例如,每個人都一直推薦的Quark瀏覽器和Alook已廣受歡迎。
  • 如何在Web應用系統表示層開發實現中應用Velocity模板技術
    軟體項目實訓及課程設計指導——如何在Web應用系統表示層開發實現中應用Velocity模板技術1、分離Web表示層的數據處理和展現邏輯的常見的應用技術分離Web表示層的數據處理和展現邏輯是目前企業級的Web應用系統開發中表現層組件開發實現中的基本實現目標。
  • 快速在你的vue/react應用中實現ssr(服務端渲染)
    >使用node+vue-server-renderer實現vue項目的服務端渲染使用node+React renderToStaticMarkup實現react項目的服務端渲染傳統網站通過模板引擎來實現ssr(比如ejs, jade, pug等)
  • 命令行工具開發:如何快速實現命令行提示?
    那麼對於不同語言的開發者,有沒有一種簡單快捷的實現方式呢?本文分享一種快速實現的方法,使用YAML文件定義命令行工具的使用規範,再通過工具自動生成各種shell的命令行提示腳本,最後分享一些至關重要的命令行解析器。文末福利:雲開發體驗——Linux指令入門。
  • Shell 腳本編程最佳實踐
    前言由於工作需要,最近重新開始拾掇shell腳本。雖然絕大部分命令自己平時也經常使用,但是在寫成腳本的時候總覺得寫的很難看。而且當我在看其他人寫的腳本的時候,總覺得難以閱讀。畢竟shell腳本這個東西不算是正經的程式語言,他更像是一個工具,用來雜糅不同的程序供我們調用。
  • 華為主題創意開發工作坊活動落幕,科技讓藝術設計釋放無限想像力
    9月12日,華為主題創意開發工作坊活動在華為大學圓滿落幕。現場不僅分享了華為主題優秀實踐案例,同時解讀了華為主題高級開發框架,主題、錶盤開發工具最新功能。更有意義的是,現場還開展了利用全新開發工具進行主題創作的上手實戰,提升了大家對多場景主題開發的認知和理解,通過科技的手段讓設計師的創意成為現實。
  • 短視頻拍攝腳本設計及文案模板!
    ,你一定要學會如何設計腳本。今天我們主要主要從以下幾個方面進行闡述:1.什麼是腳本設計2.腳本設計的準備工作3.腳本製作技巧4.腳本文案模板一、什麼是腳本設計不少小夥伴對腳本設計一知半解,只知道憑感覺就地取材拍攝短視頻,通俗的說,腳本設計就是我們拍攝視頻的方向,就像導演拍攝電影的劇本,人員、服裝、場景定位、拍攝技巧、剪輯等一切步驟和人員安排都是根據劇本的設定進行的,腳本設計也是如此,什麼地點、在什麼時間點出現什麼畫面、如何運用鏡頭等都是根據腳本的設計來進行拍攝的。