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

2021-01-07 51CTO

前言

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

需求

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

初步方案

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

在伺服器部署初始化時(init.ts初始啟動文件中)啟動node-schedule的定時任務,讀取資料庫中的企業微信的企業配置,然後並行啟動若干企業的組織架構更新進程。

企業微信提供了獲取部門成員的詳情,因此只需並行更新每個部門的信息,並且寫入mysql資料庫中。

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

開發過程中的踩雷

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

1. 訪問頻率受限

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

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

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

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

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

4. 資料庫讀寫衝突

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

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

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

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

深度優化設計

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

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;   };        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調用封禁;

完善錯誤恢復機制和報警,實時查看運行狀況。

【編輯推薦】

【責任編輯:

張燕妮

 TEL:(010)68476606】

點讚 0

相關焦點

  • Node開發實踐總結——定時腳本的設計與實現
    來源:騰訊IMWeb前端團隊前言作為Node語言的初學者去實踐後端開發時,不僅僅有見獵心喜,也有一些忐忑,好在大家都很open,給予了很多建議和分享,到目前為止,也成功建立了三個基於Node.js + TypeScript + IMServer 1 的工程,也是時候將自己最近的學習過程進行總結,下面就以一個小小的開發任務為載體分享下我的成長過程
  • Node.js 開發實踐總結-定時腳本的設計與實現
    作者@騰訊IMWeb前端團隊 | 地址@https://mp.weixin.qq.com/s/a_kIRvJUuICtw0CG7EFAtg前言作為Node語言的初學者去實踐後端開發時,不僅僅有見獵心喜,也有一些忐忑,好在大家都很open,給予了很多建議和分享,到目前為止,也成功建立了三個基於Node.js + TypeScript + IMServer 1 的工程,也是時候將自己最近的學習過程進行總結,下面就以一個小小的開發任務為載體分享下我的成長過程。
  • centos7編程實踐:安裝nodejs
    由於最近項目的需要,我需要在centos7上安裝nodejs,故總結這份教程,希望能幫助需要的同學。一、nodeJS簡介1、Nodejs是什麼?它讓javascript可以開發後端程序,實現幾乎其他後端語言實現的所有功能,可以與PHP、Java、Python、.NET、Ruby等後端語言平起平坐。
  • 學習筆記:node後臺開發總結
    知識總結:曹迎成。
  • Python開發:Win10創建定時任務執行Python腳本
    2020-12-26 07:48:50 來源: 小小追 舉報   日常開發過程中
  • 前端頁面開發之Node JS初學者指南
    【IT168技術】目前,Node.js是在前端頁面開發中十分受歡迎的,它是一套用來編寫高性能網絡伺服器的JavaScript工具包,在本文中,將帶領各位初學者介紹Node JS的基本知識,要求本文的閱讀對象為有一定Javascript和其他開發語言基礎的讀者。
  • Node.js 中實踐基於 Redis 的分布式鎖實現
    進程鎖:一個服務部署於一臺伺服器,同時開啟多個進程,Node.js 編程中為了利用作業系統資源,根據 CPU 的核心數可以開啟多進程模式,這個時候如果對一個共享資源操作還是會遇到資源競爭問題,另外每一個進程都是相互獨立的,擁有自己獨立的內存空間。
  • 【 Node.js】你應該知道的 NPM 知識都在這!
    (簡單總結:通過 npm 啟動的腳本,會默認把 node_modules/.bin 加到 PATH 環境變量中。)例子當前項目的依賴裡面有 Mocha,只要直接寫 mocha test 就可以了。但是 npm 本身對兩個腳本提供了默認值,這兩個腳本不用在 script 屬性中定義,可以直接使用"start": "node server.js""install": "node-gyp rebuild"npm run start 的默認值是 node server.js ,前提是根目錄下有 server.js
  • 運用Node-RED開發LoRa應用
    在之前的課程LoRa G-IoT模塊基礎應用中,我們已經知道如何將從LoRa得到的數值上傳伺服器,本文我們將學習撰寫Node-RED,將數據傳送到自己設計的網頁監測接口。先來介紹一下啊Node-REDNode-RED是IBM在2013年末開發的一個開源項目,用於構建物聯網IOT應用程式的一個強大工具。它提供基於網頁的可視化的編程環境,過拖拽已定義node到工作區並用線連接node創建數據流來實現編程
  • 你不知道的 Npm(Node.js 進階必備好文)
    (簡單總結:通過 npm 啟動的腳本,會默認把 node_modules/.bin 加到 PATH 環境變量中。)例子當前項目的依賴裡面有 Mocha,只要直接寫 mocha test 就可以了。但是 npm 本身對兩個腳本提供了默認值,這兩個腳本不用在 script 屬性中定義,可以直接使用"start": "node server.js""install": "node-gyp rebuild"npm run start 的默認值是 node server.js ,前提是根目錄下有 server.js
  • 【 Node.js 進階】你應該知道的 NPM 知識都在這!
    (簡單總結:通過 npm 啟動的腳本,會默認把 node_modules/.bin 加到 PATH 環境變量中。)例子當前項目的依賴裡面有 Mocha,只要直接寫 mocha test 就可以了。但是 npm 本身對兩個腳本提供了默認值,這兩個腳本不用在 script 屬性中定義,可以直接使用"start": "node server.js""install": "node-gyp rebuild"npm run start 的默認值是 node server.js ,前提是根目錄下有 server.js
  • VxWorks共享看門狗定時機制的設計與實現
    文章所提出的共享看門狗定時機制就是針對這種情況實現的一種通用型定時器組件。  利用wdCreate函數,在任何任務中都可以創建一個看門狗定時器,經過設置的時間段後,實現指定的C函數。  watchDog定時器作為系統時鐘中斷服務程序的一部分來維護。因此看門狗所定時執行的程序工作在系統中斷級別具有很高的優先級,該程序必須遵守一般ISR程序的規定,不能使用任何可能被阻塞的程序。文章所介紹的高效定時器就是在看門狗定時器的基礎上設計的。
  • 無需後端,小程序全自動定時推送模板消息系統
    我們只需要使用古人云小程序開發平臺的推送API+任務腳本功能,就可以實現一個全自動的每天定時爬取更新系統啦!>再然後,我們獲取到了這個推送API的地址和密鑰,我們就開始編寫一個定時任務腳本了。古人云小程序開發平臺的定時任務腳本支持nodejs和python環境,我就用nodejs編寫吧!代碼如下:
  • 如何通過數據模型設計生成數倉開發腳本(DML)
    眾所周知在數據建模工具中設計的ER圖可以直接產生DDL腳本並執行到資料庫生成資料庫schema,稱為正向工程。
  • Vue Element+Node.js開發企業通用管理後臺系統
    8-1 node和express簡介8-2 項目初始化8-3 express基礎概念講解8-4 項目框架優化第9章 項目需求分析在正式開發前對項目的需求、技術細節進行一次復盤,並介紹項目相關的必備知識:epub、nginx、mysql。
  • 我開始討厭node.js了
    冰山一角直到我接觸到java,我才想明白我為什麼感覺node零散。java的語法和c#的語法簡直一模一樣,但是並不像.net體系那樣過度封裝,寫起來雖然沒有那种放蕩不羈愛自由的感覺,但是整體好像規矩了很多。這領我對node一統天下的想法感覺到一絲遲疑。node好像只是冰山一角,世界這麼大,我想去看看。
  • 找回 Node.js 裡面那些遺失的 ES6 特性
    and methods)PromisesNew String methodsSymbolsTemplate stringsArrow Functionsnew.target [2]Object.assignSpread operator [2]對於這些官方引擎的特性,由於在底層實現
  • node.js、MongoDB下一代的LAMP
    node.js、MongoDB下一代的LAMP 我們大部分人在做網站時,都用的是LAMP,殊不知LAMP已成過去式,新一代的小生:nix、node.js、MongoDB誕生了,讓我們走進他們,知道他們的故事!
  • 復盤node項目中遇到的13+常見問題和解決方案
    後面我們就可以正常的開發IM應用啦~5.6. nodejs如何創建定時任務定時任務在後端開發中是很常見的功能之一, 其本質是根據時間規則,系統在後臺自動執行相應的任務.在java, PHP等後臺語言中有很豐富的定時任務的支持, 對於nodejs這個興起之秀來說, 雖然沒有那麼成熟的生態, 但是仍然有定時任務的模塊, 比如node-schedule.
  • 【芥末翻】基於設計思維的教學設計與腳本探究式學習有何異同?
    該課程的實踐任務是完全真實的,它要求學生遵循系統設計者慣常採用的設計流程,包括提案、調查,以及開發滿足實際需求的具體解決方案。研究者選擇基於設計的方法的原因在於其效果已經在基於設計學習(Kolodner et al., 2003)、基於項目的學習(Prince, 2004; Thomas, 2000)和基於問題的學習(Barrows, 1985)等研究文獻中給予了證明。