小蝌蚪傳記:前端菜鳥讓接口提速60%的優化技巧

FFCreator是咱們團隊作的一個輕量、靈活的短視頻加工庫。您只須要添加幾張圖片或文字,就能夠快速生成一個相似抖音的酷炫短視頻。github地址:github.com/tnfe/FFCrea… 歡迎小夥伴star。javascript

背景

很久沒寫文章了,沉寂了大半年前端

持續性精神萎頓,間歇性癲癇發做java

每天來大姨爹,在迷茫、焦慮中度過每一天node

不得不認可,其實本身就是個廢物git

做爲一名低級前端工程師github

最近處理了一個十幾年的祖傳老接口redis

它繼承了一切至尊級複雜度邏輯數組

傳說中調用一次就能讓cpu負載飆升90%的日天服務promise

專治各類不服與老年癡呆緩存

咱們欣賞一下這個接口的耗時

平均調用時間在3s以上

致使頁面出現嚴重的轉菊花

通過各類深度剖析與專業人士答疑

最後得出結論是:放棄醫療

魯迅在《狂人日記》裏曾說過:「能戰勝個人,只有女人和酒精,而不是bug

每當身處黑暗之時

這句話總能讓我看到光

因此此次要硬起來

我決定作一個node代理層

用下面三個方法進行優化:

  • 按需加載 -> graphQL

  • 數據緩存 -> redis

  • 輪詢更新 -> schedule

代碼地址:github

按需加載 -> graphQL

天秀老接口存在一個問題,咱們每次請求1000條數據,返回的數組中,每一條數據都有上百個字段,其實咱們前端只用到其中的10個字段而已。

如何從一百多個字段中,抽取任意n個字段,這就用到graphQL。

graphQL按需加載數據只須要三步:

  • 定義數據池 root
  • 描述數據池中數據結構 schema
  • 自定義查詢數據 query

定義數據池

咱們針對屌絲追求女神的場景,定義一個數據池,以下:

// 數據池
var root = {
    girls: [{
        id: 1,
        name: '女神一',
        iphone: 12345678910,
        weixin: 'xixixixi',
        height: 175,
        school: '劍橋大學',
        wheel: [{ name: '備胎1號', money: '24萬元' }, { name: '備胎2號', money: '26萬元' }]
    },
    {
        id: 2,
        name: '女神二',
        iphone: 12345678910,
        weixin: 'hahahahah',
        height: 168,
        school: '哈佛大學',
        wheel: [{ name: '備胎3號', money: '80萬元' }, { name: '備胎4號', money: '200萬元' }]
    }]
}

複製代碼

裏面有兩個女神的全部信息,包括女神的名字、手機、微信、身高、學校、備胎集合等信息。

接下來咱們就要對這些數據結構進行描述。

描述數據池中數據結構

const { buildSchema } = require('graphql');

// 描述數據結構 schema
var schema = buildSchema(` type Wheel { name: String, money: String } type Info { id: Int name: String iphone: Int weixin: String height: Int school: String wheel: [Wheel] } type Query { girls: [Info] } `);
複製代碼

上面這段代碼就是女神信息的schema。

首先咱們用type Query定義了一個對女神信息的查詢,裏面包含了不少女孩girls的信息Info,這些信息是一堆數組,因此是[Info]

咱們在type Info中描述了一個女孩的全部信息的維度,包括了名字(name)、手機(iphone)、微信(weixin)、身高(height)、學校(school)、備胎集合(wheel)

定義查詢規則

獲得女神的信息描述(schema)後,就能夠自定義獲取女神的各類信息組合了。

好比我想和女神認識,只須要拿到她的名字(name)和微信號(weixin)。查詢規則代碼以下:

const { graphql } = require('graphql');

// 定義查詢內容
const query = ` { girls { name weixin } } `;

// 查詢數據
const result = await graphql(schema, query, root)
複製代碼

篩選結果以下:

又好比我想進一步和女神發展,我須要拿到她備胎信息,查詢一下她備胎們(wheel)的家產(money)分別是多少,分析一下本身能不能獲取優先擇偶權。查詢規則代碼以下:

const { graphql } = require('graphql');

// 定義查詢內容
const query = ` { girls { name wheel { money } } } `;

// 查詢數據
const result = await graphql(schema, query, root)
複製代碼

篩選結果以下:

咱們經過女神的例子,展示瞭如何經過graphQL按需加載數據。

映射到咱們業務具體場景中,天秀接口返回的每條數據都包含100個字段,咱們配置schema,獲取其中的10個字段,這樣就避免了剩下90個沒必要要字段的傳輸。

graphQL還有另外一個好處就是能夠靈活配置,這個接口須要10個字段,另外一個接口要5個字段,第n個接口須要另外x個字段

按照傳統的作法咱們要作出n個接口才能知足,如今只須要一個接口配置不一樣schema就能知足全部狀況了。

感悟

在生活中,我們舔狗真的很缺乏graphQL按需加載的思惟

渣男渣女,各取所需

你的真情在名媛面前不值一提

咱們要學會投其所好

上來就亮車鑰匙,沒有車就秀才藝

今晚我有一條祖傳的染色體想與您分享一下

行就行,不行就換下一個

直奔主題,簡單粗暴

緩存 -> redis

第二個優化手段,使用redis緩存

天秀老接口內部調用了另外三個老接口,並且是串行調用,極其耗時耗資源,秀到你頭皮發麻

咱們用redis來緩存天秀接口的聚合數據,下次再調用天秀接口,直接從緩存中獲取數據便可,避免高耗時的複雜調用,簡化後代碼以下:

const redis = require("redis");
const { promisify } = require("util");

// 連接redis服務
const client = redis.createClient(6379, '127.0.0.1');

// promise化redis方法,以便用async/await
const getAsync = promisify(client.get).bind(client);
const setAsync = promisify(client.set).bind(client);

async function list() {
	// 先獲取緩存中數據,沒有緩存就去拉取天秀接口
	let result = await getAsync("緩存");
    if (!result) {
    	  // 拉接口
    	  const data = await 天秀接口();
          result = data;
          // 設置緩存數據
          await setAsync("緩存", data)
    }
   	return result;
}

list(); 

複製代碼

先經過getAsync來讀取redis緩存中的數據,若是有數據,直接返回,繞過接口調用,若是沒有數據,就會調用天秀接口,而後setAsync更新到緩存中,以便下次調用。由於redis存儲的是字符串,因此在設置緩存的時候,須要加上JSON.stringify(data),爲了便於你們理解,我就不加了,會把具體細節代碼放在github中。

將數據放在redis緩存裏有幾個好處

能夠實現多接口複用、多機共享緩存

這就是傳說中的雲備胎

追求一個女神的成功率是1%

同時追求100個女神,那你獲取到一個女神的機率就是100%

魯迅《狂人日記》裏曾說過:「舔一個是舔狗,舔一百個你就是戰狼

你是想當舔狗仍是當戰狼?

來吧,緩存用起來,redis用起來

輪詢更新 -> schedule

最後一個優化手段:輪詢更新 -> schedule

女神的備胎用久了,會定時換一批備胎,讓新鮮血液進來,發現新的快樂

緩存也同樣,須要定時更新,保持與數據源的一致性,代碼以下:

const schedule = require('node-schedule');

// 每一個小時更新一次緩存
schedule.scheduleJob('* * 0 * * *', async () => {
    const data = await 天秀接口();
    // 設置redis緩存數據
    await setAsync("緩存", data)
});
複製代碼

天秀接口不是一個強實時性接口,數據源一週可能纔會變一次

因此咱們根據實際狀況用輪詢來設置更新緩存頻率

咱們用node-schedule這個庫來輪詢更新緩存,* * 0 * * *這個的意思就是設置每一個小時的第0分鐘就開始執行緩存更新邏輯,將獲取到的數據更新到緩存中,這樣其餘接口和機器在調用緩存的時候,就能獲取到最新數據,這就是共享緩存和輪詢更新的好處。

早年我在當舔狗的時候,就將輪詢機制發揮到淋漓盡致

天天向白名單裏的女神,定時輪詢發消息

無限循環雲跪舔三件套:

  • 「啊寶貝,最近有沒有想我」
  • 「啊寶貝早安安」
  • 「寶貝晚安,麼麼噠」

雖然女神依然看不上我

但仍然時刻準備着爲女神服務

結尾

通過以上三個方法優化後

接口請求耗時從3s降到了860ms

這些代碼都是從業務中簡化後的邏輯

真實的業務場景遠比這要複雜:分段式數據存儲、主從同步 讀寫分離、高併發同步策略等等

每個模塊都晦澀難懂

就好像每個女神都遙不可及

屌絲打敗了全部bug,惟獨打敗不了她的心

受傷了只能在深夜裏獨自買醉

但每當夢到女神打開我作的頁面

被極致流暢的體驗驚豔到

在精神高潮中享受靈魂昇華

那一刻

我以爲我又行了

(完)

代碼地址:github

做者:第一名的小蝌蚪,公衆號:前端屌絲

相關文章
相關標籤/搜索