React SPA की परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के बारे में असल दुनिया की केस स्टडी.
वेबसाइट की परफ़ॉर्मेंस सिर्फ़ लोड होने में लगने वाले समय पर निर्भर नहीं करती. उपयोगकर्ताओं को तेज़ और रिस्पॉन्सिव अनुभव देना ज़रूरी है. खास तौर पर, प्रॉडक्टिविटी के लिए इस्तेमाल होने वाले उन डेस्कटॉप ऐप्लिकेशन के लिए जो लोग हर दिन इस्तेमाल करते हैं. Recruit Technologies की इंजीनियरिंग टीम ने अपने एक वेब ऐप्लिकेशन, AirSHIFT को बेहतर बनाने के लिए, रीफ़ैक्टर करने का प्रोजेक्ट शुरू किया. इससे, उपयोगकर्ता इनपुट की परफ़ॉर्मेंस बेहतर हुई. उन्होंने ऐसा कैसे किया, यह जानने के लिए यहां देखें.
धीमा रिस्पॉन्स, कम प्रोडक्टिविटी
AirSHIFT एक डेस्कटॉप वेब ऐप्लिकेशन है. इसकी मदद से, रेस्टोरेंट और कैफ़े जैसे स्टोर के मालिक, अपने कर्मचारियों की शिफ़्ट मैनेज कर सकते हैं. React के साथ बनाया गया यह एक पेज वाला ऐप्लिकेशन, रिच क्लाइंट की सुविधाएं देता है. इनमें, दिन, हफ़्ते, महीने वगैरह के हिसाब से व्यवस्थित किए गए शिफ़्ट शेड्यूल की अलग-अलग ग्रिड टेबल शामिल हैं.
Recruit Technologies की इंजीनियरिंग टीम ने AirSHIFT ऐप्लिकेशन में नई सुविधाएं जोड़ीं. इसके बाद, उन्हें ऐप्लिकेशन की परफ़ॉर्मेंस के बारे में ज़्यादा शिकायतें मिलने लगीं. AirSHIFT के इंजीनियरिंग मैनेजर, योसुके फ़ुरूकावा ने कहा:
उपयोगकर्ता के बारे में की गई रिसर्च में, हमें यह जानकर हैरानी हुई कि स्टोर के एक मालिक ने बताया कि वह बटन पर क्लिक करने के बाद, कॉफ़ी बनाने के लिए अपनी सीट छोड़ देती है. ऐसा सिर्फ़ इसलिए करती है, ताकि शिफ़्ट टेबल लोड होने तक वह समय बर्बाद न करे.
रिसर्च करने के बाद, इंजीनियरिंग टीम को पता चला कि उनके कई उपयोगकर्ता, कम स्पेसिफ़िकेशन वाले कंप्यूटर पर बड़ी शिफ़्ट टेबल लोड करने की कोशिश कर रहे थे. जैसे, 10 साल पहले का 1 गीगाहर्ट्ज़ Celeron M लैपटॉप.
AirSHIFT ऐप्लिकेशन, महंगी स्क्रिप्ट की वजह से मुख्य थ्रेड को ब्लॉक कर रहा था. हालांकि, इंजीनियरिंग टीम को पता नहीं था कि स्क्रिप्ट कितनी महंगी हैं, क्योंकि वे तेज़ वाई-फ़ाई कनेक्शन वाले बेहतर कंप्यूटर पर ऐप्लिकेशन को डेवलप और टेस्ट कर रहे थे.

सीपीयू और नेटवर्क थ्रॉटलिंग की सुविधा चालू करके, Chrome DevTools में उनकी परफ़ॉर्मेंस की प्रोफ़ाइल बनाने के बाद, यह साफ़ तौर पर पता चला कि परफ़ॉर्मेंस को ऑप्टिमाइज़ करने की ज़रूरत है. इस समस्या को हल करने के लिए, AirSHIFT ने एक टास्क फ़ोर्स बनाई है. उपयोगकर्ता के इनपुट के हिसाब से अपने ऐप्लिकेशन को ज़्यादा बेहतर बनाने के लिए, उन्होंने इन पांच बातों पर फ़ोकस किया.
1. बड़ी टेबल को वर्चुअलाइज़ करना
शिफ़्ट टेबल दिखाने के लिए, कई महंगे चरण पूरे करने पड़ते हैं: वर्चुअल डीओएम बनाना और स्टाफ़ सदस्यों की संख्या और टाइम स्लॉट के हिसाब से, इसे स्क्रीन पर रेंडर करना. उदाहरण के लिए, अगर किसी रेस्टोरेंट में 50 कर्मचारी काम करते हैं और उन्हें महीने के हिसाब से अपनी शिफ़्ट का शेड्यूल देखना है, तो यह 50 (कर्मचारियों) को 30 (दिनों) से गुणा करने वाली टेबल होगी. इस टेबल में 1,500 सेल कॉम्पोनेंट रेंडर होंगे. यह प्रोसेस बहुत महंगी होती है. खास तौर पर, कम स्पेसिफ़िकेशन वाले डिवाइसों के लिए. असल में, स्थिति और भी खराब थी. रिसर्च से उन्हें पता चला कि 200 कर्मचारियों को मैनेज करने वाली दुकानों के लिए, हर महीने की एक टेबल में करीब 6,000 सेल कॉम्पोनेंट की ज़रूरत होती है.
इस प्रोसेस की लागत कम करने के लिए, AirSHIFT ने शिफ़्ट टेबल को वर्चुअल कर दिया. अब ऐप्लिकेशन सिर्फ़ व्यूपोर्ट में कॉम्पोनेंट माउंट करता है और ऑफ़-स्क्रीन कॉम्पोनेंट को अनमाउंट करता है.


इस मामले में, AirSHIFT ने react-virtualized का इस्तेमाल किया, क्योंकि जटिल दो डाइमेंशन वाली ग्रिड टेबल चालू करने की ज़रूरत थी. वे आने वाले समय में, कम साइज़ वाले react-window का इस्तेमाल करने के लिए, लागू करने के तरीकों को बदलने के बारे में भी खोज कर रहे हैं.
नतीजे
सिर्फ़ टेबल को वर्चुअलाइज़ करने से, स्क्रिप्टिंग में लगने वाला समय छह सेकंड कम हो गया. ऐसा, सीपीयू के चार गुना धीमे होने और फ़ास्ट 3G की स्पीड कम होने के बावजूद हुआ. रीफ़ैक्टर करने के प्रोजेक्ट में, परफ़ॉर्मेंस में यह सबसे ज़्यादा असरदार सुधार था.


2. User Timing API की मदद से ऑडिट करना
इसके बाद, AirSHIFT की टीम ने उपयोगकर्ता के इनपुट पर चलने वाली स्क्रिप्ट को फिर से तैयार किया. Chrome DevTools के फ़्लेम चार्ट की मदद से, यह पता लगाया जा सकता है कि मुख्य थ्रेड में क्या हो रहा है. हालांकि, AirSHIFT की टीम को React के लाइफ़साइकल के आधार पर, ऐप्लिकेशन गतिविधि का विश्लेषण करना आसान लगा.
React 16, User Timing API के ज़रिए अपनी परफ़ॉर्मेंस का ट्रेस उपलब्ध कराता है. इसे Chrome DevTools के समय सेक्शन से देखा जा सकता है. AirSHIFT ने React लाइफ़साइकल इवेंट में चल रहे ग़ैर-ज़रूरी लॉजिक का पता लगाने के लिए, टाइमिंग सेक्शन का इस्तेमाल किया.

नतीजे
AirSHIFT की टीम को पता चला कि हर रूट नेविगेशन से ठीक पहले, React ट्री रीकंसिलिएशन की ग़ैर-ज़रूरी प्रोसेस चल रही थी. इसका मतलब है कि नेविगेशन से पहले, React, शिफ़्ट टेबल को ग़ैर-ज़रूरी तौर पर अपडेट कर रहा था. इस समस्या की वजह, Redux स्टेट का ग़ैर-ज़रूरी अपडेट था. इसे ठीक करने से, स्क्रिप्टिंग में करीब 750 मिलीसेकंड की बचत हुई. AirSHIFT ने कुछ और माइक्रो ऑप्टिमाइज़ेशन भी किए, जिसकी वजह से स्क्रिप्टिंग में लगने वाला कुल समय एक सेकंड कम हो गया.
3. कॉम्पोनेंट को लेज़ी लोड करना और ज़्यादा खर्च वाले लॉजिक को वेब वर्कर्स पर ले जाना
AirSHIFT में चैट करने की सुविधा पहले से मौजूद है. कई स्टोर मालिक, शिफ़्ट टेबल देखते समय चैट की मदद से अपने स्टाफ़ से बातचीत करते हैं. इसका मतलब है कि टेबल लोड होने के दौरान, कोई उपयोगकर्ता मैसेज टाइप कर सकता है. अगर मुख्य थ्रेड, टेबल को रेंडर करने वाली स्क्रिप्ट में व्यस्त है, तो उपयोगकर्ता का इनपुट अनियमित हो सकता है.
इस अनुभव को बेहतर बनाने के लिए, AirSHIFT अब React.lazy और Suspense का इस्तेमाल करता है. इससे टेबल के कॉन्टेंट के लिए प्लेसहोल्डर दिखाए जाते हैं, जबकि असल कॉम्पोनेंट को धीरे-धीरे लोड किया जाता है.
AirSHIFT की टीम ने, धीरे-धीरे लोड होने वाले कॉम्पोनेंट में मौजूद कुछ महंगे बिज़नेस लॉजिक को वेब वर्कर्स में भी माइग्रेट किया. इससे मुख्य थ्रेड को खाली करके, उपयोगकर्ता इनपुट की समस्या को हल किया गया, ताकि वह उपयोगकर्ता इनपुट का जवाब देने पर फ़ोकस कर सके.
आम तौर पर, डेवलपर को वर्कर्स का इस्तेमाल करने में मुश्किल होती है. हालांकि, इस बार Comlink ने उनके लिए ज़्यादातर काम किया. यहां एक स्यूडो कोड दिया गया है, जिसमें बताया गया है कि AirSHIFT ने अपने सबसे महंगे ऑपरेशन में से एक को कैसे ऑटोमेट किया: कुल मजदूरी की लागत का हिसाब लगाना.
App.js में, लोड होने के दौरान फ़ॉलबैक कॉन्टेंट दिखाने के लिए, React.lazy और Suspense का इस्तेमाल करें
/** App.js */
import React, { lazy, Suspense } from 'react'
// Lazily loading the Cost component with React.lazy
const Hello = lazy(() => import('./Cost'))
const Loading = () => (
<div>Some fallback content to show while loading</div>
)
// Showing the fallback content while loading the Cost component by Suspense
export default function App({ userInfo }) {
return (
<div>
<Suspense fallback={<Loading />}>
<Cost />
</Suspense>
</div>
)
}
लागत कॉम्पोनेंट में, कैलकुलेशन लॉजिक को लागू करने के लिए comlink का इस्तेमाल करना
/** Cost.js */
import React from 'react';
import { proxy } from 'comlink';
// import the workerlized calc function with comlink
const WorkerlizedCostCalc = proxy(new Worker('./WorkerlizedCostCalc.js'));
export default async function Cost({ userInfo }) {
// execute the calculation in the worker
const instance = await new WorkerlizedCostCalc();
const cost = await instance.calc(userInfo);
return <p>{cost}</p>;
}
वर्कर्स में चलने वाले कैलकुलेशन लॉजिक को लागू करना और उसे comlink की मदद से एक्सपोज़ करना
// WorkerlizedCostCalc.js
import { expose } from 'comlink'
import { someExpensiveCalculation } from './CostCalc.js'
// Expose the new workerlized calc function with comlink
expose({
calc(userInfo) {
// run existing (expensive) function in the worker
return someExpensiveCalculation(userInfo);
}
}, self);
नतीजे
उन्होंने प्रयोग के तौर पर, सीमित लॉजिक को वर्कर्स में बदला. इसके बावजूद, AirSHIFT ने अपने JavaScript के करीब 100 मिलीसेकंड को मुख्य थ्रेड से वर्कर्स थ्रेड में शिफ़्ट किया. यह 4x सीपीयू थ्रॉटलिंग के साथ सिम्युलेट किया गया था.
फ़िलहाल, AirSHIFT यह पता लगा रहा है कि क्या वे अन्य कॉम्पोनेंट को लैज़ी लोड कर सकते हैं और वेब वर्कर पर ज़्यादा लॉजिक ऑफ़लोड करके, जंक को और कम किया जा सकता है.
4. परफ़ॉर्मेंस बजट सेट करना
इन सभी ऑप्टिमाइज़ेशन को लागू करने के बाद, यह पक्का करना ज़रूरी था कि ऐप्लिकेशन समय के साथ बेहतर परफ़ॉर्म करता रहे. AirSHIFT अब bundlesize का इस्तेमाल करता है, ताकि मौजूदा JavaScript और सीएसएस फ़ाइल का साइज़ न बढ़े. इन बुनियादी बजट को सेट करने के अलावा, उन्होंने एक डैशबोर्ड बनाया है. इससे, शिफ़्ट टेबल लोड होने में लगने वाले समय के अलग-अलग प्रतिशत को दिखाया जा सकता है. इससे यह पता चलता है कि ऐप्लिकेशन, सही परिस्थितियों में भी अच्छा परफ़ॉर्म कर रहा है या नहीं.
- अब हर Redux इवेंट के लिए स्क्रिप्ट पूरी होने का समय मेज़र किया जाता है
- परफ़ॉर्मेंस डेटा को Elasticsearch में इकट्ठा किया जाता है
- हर इवेंट की 10वीं, 25वीं, 50वीं, और 75वीं पर्सेंटाइल परफ़ॉर्मेंस को Kibana की मदद से विज़ुअलाइज़ किया जाता है
AirSHIFT अब शिफ़्ट टेबल लोड होने के इवेंट को मॉनिटर कर रहा है, ताकि यह पक्का किया जा सके कि यह 75वें प्रतिशत के उपयोगकर्ताओं के लिए तीन सेकंड में पूरा हो जाए. फ़िलहाल, यह बजट लागू नहीं है. हालांकि, बजट से ज़्यादा खर्च होने पर, Elasticsearch की मदद से अपने-आप सूचनाएं भेजने की सुविधा पर विचार किया जा रहा है.

नतीजे
ऊपर दिए गए ग्राफ़ से पता चलता है कि AirSHIFT अब 75वें पर्सेंटाइल के उपयोगकर्ताओं के लिए, ज़्यादातर तीन सेकंड के बजट को पूरा कर रहा है. साथ ही, 25वें पर्सेंटाइल के उपयोगकर्ताओं के लिए, एक सेकंड में शिफ़्ट टेबल लोड कर रहा है. अलग-अलग स्थितियों और डिवाइसों से RUM की परफ़ॉर्मेंस का डेटा कैप्चर करके, AirSHIFT अब यह जांच कर सकता है कि किसी नई सुविधा के रिलीज़ होने से, ऐप्लिकेशन की परफ़ॉर्मेंस पर असल में असर पड़ रहा है या नहीं.
5. परफ़ॉर्मेंस हैकेथॉन
परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए किए गए ये सभी काम ज़रूरी और असरदार थे. हालांकि, इंजीनियरिंग और कारोबार की टीमों को काम न करने वाले डेवलपमेंट को प्राथमिकता देना हमेशा आसान नहीं होता. समस्या का एक हिस्सा यह है कि परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के कुछ तरीकों को पहले से तय नहीं किया जा सकता. इसके लिए, प्रयोग करना और 'आज़मा-ओर-गलती करो' वाला मेंटैलिटी होना ज़रूरी है.
AirSHIFT अब एक दिन के इंटरनल परफ़ॉर्मेंस हैकथॉन आयोजित कर रहा है, ताकि इंजीनियर सिर्फ़ परफ़ॉर्मेंस से जुड़े काम पर फ़ोकस कर सकें. इन हैकथॉन में, वे सभी पाबंदियां हटा देते हैं और इंजीनियरों की क्रिएटिविटी का सम्मान करते हैं. इसका मतलब है कि प्रोसेस को तेज़ करने में मदद करने वाले किसी भी सुझाव पर विचार किया जा सकता है. हैकथॉन को तेज़ी से आगे बढ़ाने के लिए, AirSHIFT ग्रुप को छोटी टीमों में बांट देता है. इसके बाद, हर टीम यह मुकाबला करती है कि Lighthouse की परफ़ॉर्मेंस में सबसे ज़्यादा सुधार कौन कर सकता है. टीमें बहुत प्रतिस्पर्धी हो जाती हैं! 🔥
नतीजे
हैकेथॉन का तरीका उनके लिए कारगर साबित हो रहा है.
- हैकथॉन के दौरान कई तरीकों को आज़माकर और Lighthouse की मदद से हर तरीके को मेज़र करके, परफ़ॉर्मेंस से जुड़ी समस्याओं का आसानी से पता लगाया जा सकता है.
- हैकथॉन के बाद, टीम को यह समझाना आसान हो जाता है कि प्रोडक्शन रिलीज़ के लिए, उन्हें किस ऑप्टिमाइज़ेशन को प्राथमिकता देनी चाहिए.
- यह तेज़ी से लोड होने की अहमियत को बताने का भी एक असरदार तरीका है. इस सुविधा की मदद से, हर व्यक्ति यह समझ सकता है कि कोडिंग करने का तरीका और परफ़ॉर्मेंस में क्या फ़र्क़ पड़ता है.
इसकी एक अच्छी बात यह थी कि Recruit की कई अन्य इंजीनियरिंग टीमों ने इस तरीके में दिलचस्पी दिखाई. अब AirSHIFT की टीम, कंपनी में कई स्पीड हैकथॉन की सुविधा दे रही है.
खास जानकारी
इन ऑप्टिमाइज़ेशन पर काम करना, AirSHIFT के लिए आसान नहीं था. हालांकि, इसका फ़ायदा मिला. अब AirSHIFT, शिफ़्ट टेबल को औसतन 1.5 सेकंड में लोड कर रहा है. यह प्रोजेक्ट शुरू करने से पहले की परफ़ॉर्मेंस के मुकाबले छह गुना बेहतर है.
परफ़ॉर्मेंस ऑप्टिमाइज़ेशन लॉन्च होने के बाद, एक उपयोगकर्ता ने कहा:
शिफ़्ट टेबल को तेज़ी से लोड करने के लिए धन्यवाद. अब शिफ़्ट के हिसाब से काम को व्यवस्थित करना ज़्यादा आसान हो गया है.