背景
好久沒寫文章了,沉寂了大半年
持續性萎靡不振,間歇性癲癇發作
天天來大姨爹,在迷茫、焦慮中度過每一天
不得不承認,其實自己就是個廢物
作為一名低階前端工程師
最近處理了一個十幾年的祖傳老介面
它繼承了一切至尊級複雜度邏輯
傳說中呼叫一次就能讓cpu負載飆升90%的日天服務
專治各種不服與老年痴呆
我們欣賞一下這個介面的耗時
平均呼叫時間在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,
age: Int
}
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
作者:第一名的小蝌蚪,公眾號:前端屌絲
FFCreator是我們團隊做的一個輕量、靈活的短視訊加工庫。您只需要新增幾張圖片或文字,就可以快速生成一個類似抖音的酷炫短視訊。github地址:https://github.com/tnfe/FFCreator 歡迎小夥伴star。