আপস্ট্যাশ ফর রেডিস এবং পারফরম্যান্স API নিয়ে এই আর্টিকেলে, আমরা দেখব কীভাবে আপনি একটি Deno অ্যাপে আপস্ট্যাশ ফর রেডিস সেরাভাবে ব্যবহার করতে পারেন। আপস্ট্যাশ ফর রেডিস একটি সার্ভারলেস ডেটাবেস যা সার্ভার-সাইড ক্যাশিং-এর জন্য আদর্শ। একটি ওয়েব অ্যাপে আমি কাজ করছিলাম যা Initial Server Response Time-এ খারাপ স্কোর করছিল। Lighthouse ৫০০ ms রিপোর্ট করছিল। একটি আপস্ট্যাশ ক্যাশ যোগ করে আমি এটি ১৫০ ms-এর নিচে নামিয়ে এনেছি এবং অডিট পাস করলাম। কঠিন অংশ ছিল ক্যাশ যোগ করা নয়; বরং কোথায় ক্যাশ ব্যবহার করা উচিত তা বের করা ছিল קרিটিক্যাল। শুধু পারফরম্যান্স মাপা দিয়ে আমি বটলनेक শনাক্ত করতে পারলাম ন্যূনতম প্রচেষ্টায় পারফরম্যান্স বাড়াতে। এই আর্টিকেলে আমরা পারফরম্যান্স মেজারমেন্ট নিয়ে নজদিক থেকে দেখব।
আমার প্রজেক্টটি একটি Deno Fresh ওয়েব অ্যাপ। Deno-তে ইনস্ট্যান্ট বিল্ড এবং ডিপ্লয় আছে। এটি অপ্টিমাইজেশনের জন্য একটি স্বপ্নের এনভায়রনমেন্ট। ফিডব্যাক লুপ ছোট। আপনি লোকালি অপ্টিমাইজেশন কোড করুন, সার্ভারে পুশ করুন, এবং রিমোট সাইটটি তাৎক্ষণিক টেস্ট করতে পারেন।
স্ট্যাক
এখানে, আমি একটি স্কেলেটন অ্যাপ ব্যবহার করে পারফরম্যান্স উন্নত করার কথা বলব। এটি নিচের টুলিং ব্যবহার করে:
upstash_redis: Upstash for Redis-এর সাথে কাজ করার জন্য একটি Deno মডিউল- Deno Fresh: Deno-তে সার্ভার-সাইড রেন্ডার্ড (SSR) অ্যাপ বানাতে একটি নতুন, প্রোডাকশন-রেডি ফ্রেমওয়ার্ক
- সার্ভারলেস লগিং: এখানে কনসোল ব্যবহার করছি, কিন্তু আপনার ডিপ্লয় করা অ্যাপের জন্য, লাইভ মেজারমেন্ট অ্যাক্সেস করতে Logtail-এর মতো একটি সার্ভিস লাগবে
সেটআপ
Node এবং Deno-র মধ্যে একটি মূল পার্থক্য হলো কীভাবে আপনি আপনার কোডে থার্ড-পার্টি মডিউল অ্যাক্সেস করেন। Deno URLs এবং ইম্পোর্ট ম্যাপস দিয়ে কাজ করে package.json ফাইলের পরিবর্তে। upstash_redis-র পূর্ণ URL হলো https://deno.land/x/upstash_redis@v1.20.0। শুরু করতে একটি নতুন Deno Fresh অ্যাপ তৈরি করুন।
deno run -A -r https://fresh.deno.dev upstash-redis-deno-perf
আপনি যদি প্রথমবার চেষ্টা করেন, কিছু টার্মিনাল কমান্ড দিয়ে Deno নিজেই আপনার সিস্টেমে সেটআপ করতে পারেন।
এখন আপনি প্রজেক্ট রুট ডিরেক্টরিতে import_map.json-এ আপস্ট্যাশ যোগ করতে পারেন:
{
"imports": {
"@/": "./",
"$fresh/": "https://deno.land/x/fresh@1.1.2/",
// ...TRUNCATED
"$std/": "https://deno.land/std@0.177.0/",
"upstash/": "https://deno.land/x/upstash_redis@v1.20.0/"
}
}
@/সুবিধার জন্য একটি ইম্পোর্ট আলিয়াস সংজ্ঞায়িত করে। এটি আপনাকেcomponents(প্রজেক্ট রুট ডিরেক্টরিতে) ইম্পোর্ট করতে দেয়@/componentsব্যবহার করে কোনো ফোল্ডার থেকে আপনার সোর্স ফাইল থাকে।$std/আমাদের Deno Standard Library-এর জন্য একটি আলিয়াস যাতে.envএনভায়রনমেন্ট ভেরিয়েবল ফাইল পড়ার একটি ইউটিলিটি ফাংশন আছে।upstash/আমাদের প্রজেক্টের যেকোনো TypeScript বা JavaScript সোর্স ফাইল থেকে Upstash for Redis লাইব্রেরি অ্যাক্সেস করতে দেয়।
আপস্ট্যাশ ফর রেডিস এবং পারফরম্যান্স API: স্কেলেটন অ্যাপ
স্কেলেটন অ্যাপটি নিচের ডেটা খেনչে আনবে:
- Tinybird (সার্ভারলেস Clickhouse) থেকে ওয়েব অ্যানালিটিক্স ব্যবহার করে গত ২৮ দিনের পেজ ভিউ
- Webmentions ব্যবহার করে পেজ লাইক
এই ডেটাগুলো fetch রিকোয়েস্ট ব্যবহার করে সোর্স করা হয়, যা আমাদের সার্ভার টাস্কগুলিকে একটি রিয়েল-ওয়ার্ল্ড বিজনেস অ্যাপের প্রতিনিধিত্ব করে। likes এবং views ভেরিয়েবলগুলো এই দুটি API থেকে রেসপন্স ধারণ করে যা আমরা ফ্রন্টএন্ডে প্রদর্শন করি।

সার্ভার handler কোডটি সেই পেজের জন্য এরকম দেখায়:
export const handler: Handlers<Data> = {
async GET(request, context) {
const { url } = request;
const { pathname } = new URL(url);
const likes = await getWebmentionLikes(pathname);
const views = await getTinybirdViews({ days: 28 });
return context.render({ likes, views });
},
};
আমরা ইনকামিং request অবজেক্ট থেকে pathname এক্সট্র্যাক্ট করি, তারপর pathname ডেটা হেল্পার ফাংশনগুলিতে ব্যবহার করি, এবং অবশেষে রিমোট्ली সোর্স করা মানগুলো ফেরত দেই।
দক্ষতার জন্য, হেল্পার ফাংশন কলগুলো পুনর্গঠিত করা যেতে পারে:
const [likes, views] = await Promise.all([
getWebmentionLikes(pathname),
getTinybirdViews({ days: 28 }),
]);
JavaScript পারফরম্যান্স ওয়েব API
পারফরম্যান্স মেজারমেন্ট সাধারণত অপ্টিমাইজেশনে প্রথম ধাপ হওয়া উচিত। রেট লিমিটিং ধাপটি সর্বদা সেটা নয় যা আপনি আশা করেন। মাপা ছাড়া, আপনি সহজে সময় এবং রিসোর্স ব্যয় করতে পারেন যা hậuপর্যন্ত সাব-অপ্টিমাল সমাধান বলে সাবিত হয়। পারফরম্যান্স API এখানে বড় সাহায্য করতে পারে। এই সেকশনে আমরা দেখব কীভাবে আমরা এটি ব্যবহার করতে পারি নির্ধারণ করতে যে অ্যাপে আপস্ট্যাশ ফর রেডিস কোথায় ব্যবহার করা সবচেয়ে সार्थক।
window.performance আপনাকে ক্লায়েন্ট ব্রাউজার থেকে পারফরম্যান্স ওয়েব API-এ অ্যাক্সেস দেয়। Deno সার্ভারে ওয়েব API ব্যবহার সাপোর্ট করে তাই performance গ্লোবালি আপনার Deno সার্ভার-সাইড কোডে উপলব্ধ। এখানে দুটি পারফরম্যান্স মেথড আছে যা আপনি ব্যবহার করতে চাবেন:
performance.mark('your-mark-name'): একটিPerformanceMarkঅবজেক্ট তৈরি করে, যা একটি পয়েন্ট-ইন-টাইম রিপ্রেজেন্ট করে। নাম প্যারামিটারটি ব্যবহৃত হয় যখন আপনি মার্ক দিয়ে একটি মেজার তৈরি করেন।performance.measure('your description', startMarkName, finishMarkName): একটিPerformanceMeasureঅবজেক্ট তৈরি করে। এটি স্টার্ট এবং ফিনিশ টাইম মার্কগুলো একটি লেবেলের সাথে অ্যাসোসিয়েট করে, যা লগিং এবং ক্যালকুলেট করার জন্য উপযোগী যে ইভেন্টটি কতক্ষণ ধরে রান হয়েছে।
timeEvent: পারফরম্যান্স হেল্পার ফাংশন
এখন যেহেতু আমরা বেসিক্স জানি, একটি timeEvent ফাংশন তৈরি করি। এটি একটি PerformanceMeasure অবজেক্টের অ্যারে এবং একটি ফাংশন ইনপুট হিসেবে নেবে যেটি আমরা টাইম করতে চাই। timeEvent একটি স্টার্ট মার্ক তৈরি করবে, পাস করা ফাংশনটি আহ্বান করবে, তারপর তাৎক্ষণিক একটি ফিনিশ মার্ক তৈরি করবে। অবশেষে, এটি ইনপুট হিসেবে প্রাপ্ত PerformanceMeasure অবজেক্টের অ্যারে মিউটেট করবে, নতুনটি যোগ করে। এখানে utils/performance.ts- থেকে কোড:
export async function timeEvent<EventReturnType>(
eventFunction: () => Promise<EventReturnType>,
{ description, performanceMeasures, }: { description: string; performanceMeasures: PerformanceMeasure[] },
): Promise<EventReturnType> {
// প্রস্তুতি
const startName = `${description}-started`;
const finishName = `${description}-finished`;
// টাইমিং
performance.mark(startName);
const result = await eventFunction();
performance.mark(finishName);
// রেকর্ড
performanceMeasures.push(
performance.measure(description, startName, finishName),
);
return result;
}
ফাংশনটি জেনেরিক, যদিও স্কেলেটন অ্যাপের জন্য, EventReturnType সবসময় একটি নাম্বার হবে।
মেজারমেন্ট সহ সার্ভার কোড আপডেট
আমরা নতুন timeEvent ফাংশনটি হ্যান্ডলারে ব্যবহার করতে পারি, তারপর তুলনা চালাতে পারি। এখানে আপডেট করা সার্ভার হ্যান্ডলার কোড:
import type { Handlers, PageProps } from "$fresh/server.ts";
import "$std/dotenv/load.ts";
/* visibility-এর জন্য এখানে অন্তর্ভুক্ত, সাধারণত আপনি একবার ইম্পোর্ট করতে পারেন প্রজেক্টে `dev.ts`-এ */
import { timeEvent } from "@/utils/performance.ts";
// ...TRUNCATED
export const handler: Handlers<Data> = {
async GET(request, context) {
// ...TRUNCATED
const performanceMeasures: PerformanceMeasure[] = [];
const [likes, views] = await Promise.all([
timeEvent<number>(() => getWebmentionLikes(pathname), {
description: "web-mention-likes",
performanceMeasures,
}),
timeEvent<number>(() => getTinybirdViews({ days: 28 }), {
description: "analytics-views",
performanceMeasures,
}),
]);
// প্রোডাকশনে সার্ভারলেস লগিং সার্ভিস দিয়ে রিপ্লেস করুন
console.log({ performanceMeasures });
return context.render({ likes, views });
},
};
timeEvent ফাংশনটি আমরা যা পাস করেছি সেই ফাংশনের রেজাল্ট ফেরত দেয়। এই প্রোপার্টি আমাদের দুটি ডেটা হেল্পার ফাংশনকে যেগুলো আমাদের আগে ছিল timeEvent কলগুলিতে শুধু র্যাপ করতে দেয়। আমরা লোকালি রান করছি। প্রোডাকশন অ্যাপের জন্য, আপনাকে আপনার লাইভ সাইটে মেজারমেন্ট রান করতে হবে, যেহেতু আপনার সার্ভারে ব্যাকবোন কানেকশন লোকাল থেকে আলাদা পারফর্ম করে। সার্ভারে রান করার সময় Logtail-এর মতো একটি লগিং সার্ভিস ব্যবহার করুন মেজারমেন্ট রেকর্ড করার জন্য।

কনসোল লগের ক্যাপচারে, আপনি দেখতে পাচ্ছেন PerformanceMeasure অবজেক্ট নিচের মেজার ভ্যালুগুলো প্রদান করে (যেগুলো আমরা আগে কথা বলেছিলাম):
- name
- start time
- duration (মিলিসেকেন্ডে)
আদর্শভাবে, আমাদের উভয় ডেটা ভ্যালু (likes এবং views) অ্যাপ রেন্ডার করতে হয়। এখানে তারা প্রায় একই সময় নিল (২ সেকেন্ড)। যদি একটি ফাংশন অন্যটির চেয়ে খুব ধীরে চালাত, আমরা সবচেয়ে ধীর মানটির জন্য আপস্ট্যাশ ফর রেডিস ক্যাশিং যোগ করতাম। বরং, এখানে আমরা উভয়ই যোগ করব। দ্রষ্টব্য, প্রোডাকশনে, আমরা কমপক্ষে কয়েকশো ডেটা পয়েন্ট চাইব। তারপর আমরা মিন বা P90-এর মতো একটি এগরিগেট মেজার ব্যবহার করতে পারি তুলনার জন্য।
অ্যানালিটিক্স হেল্পার কোডে আপস্ট্যাশ ফর রেডিস যোগ করা
চলুন অ্যানালিটিক্স হেল্পার ফাংশনে আপস্ট্যাশ ফর রেডিস যোগ করার কোডটি দেখি। Webmentions হেল্পার ফাংশনটি সিমিলার এবং আপনি এটি পুরো GitHub রিপোতে দেখতে পারেন (লিংক নিচে)।
import { Redis } from "upstash/mod.ts";
const UPSTASH_REDIS_REST_TOKEN = Deno.env.get("UPSTASH_REDIS_REST_TOKEN");
if (typeof UPSTASH_REDIS_REST_TOKEN === "undefined") {
console.error("env `UPSTASH_REDIS_REST_TOKEN` must be set");
}
const UPSTASH_REDIS_REST_URL = Deno.env.get("UPSTASH_REDIS_REST_URL");
if (typeof UPSTASH_REDIS_REST_URL === "undefined") {
console.error("env `UPSTASH_REDIS_REST_URL` must be set");
}
const redis = new Redis({
token: UPSTASH_REDIS_REST_TOKEN,
url: UPSTASH_REDIS_REST_URL,
});
প্রথমে, আমাদের একটি আপস্ট্যাশ ফর রেডিস অবজেক্ট ইনিশিয়ালাইজ করতে হবে। আপনার আপস্ট্যাশ কনসোল থেকে UPSTASH_REDIS_REST_TOKEN এবং UPSTASH_REDIS_REST_URL মানগুলো লাগবে। আপস্ট্যাশ অ্যাকাউন্ট সেটআপ করা কুইক যদি আপনার কাছে ইতিমধ্যে না থাকে। উভয় মান (UPSTASH_REDIS_REST_TOKEN এবং UPSTASH_REDIS_REST_URL) প্রজেক্ট রুট ডিরেক্টরিতে .env ফাইলে যোগ করুন।
উপরের প্রথম লাইনে দ্রষ্টব্য করুন, আমরা আগে সেটআপ করা ইম্পোর্ট ম্যাপ থেকে upstash কী ব্যবহার করছি। এটি প্রতিটি TypeScript ফাইলে পূর্ণ ইম্পোর্ট URL যোগ করার চেয়ে বেশি সুবিধাজনক। upstash_redis-র পরবর্তী রিলিজ উপলব্ধ হলে আপনাকে শুধু এক জায়গায় ভার্সন নম্বর আপডেট করতে হবে।
এখানে getTinybirdViews ফাংশন:
export async function getTinybirdViews({ days, }: { days: number; }): Promise<number> {
try {
// ...TRUNCATED
const cachedCount = (await redis.get("view-count")) as number | null;
if (cachedCount != null) {
return cachedCount;
}
// ...TRUNCATED
const response = await fetch(
`https://api.tinybird.co/v0/pipes/${TINYBIRD_PIPE_NAME}.json?${params.toString()}`,
{
headers: {
Authorization: `Bearer ${TINYBIRD_TOKEN}`,
},
},
);
const { data: [{ count_sessions: count = -1 }], } = await response.json();
if (typeof count === "number" && count > 0) {
const CACHE_TTL_SECONDS = 14_400;
await redis.set("view-count", count);
await redis.expire("view-count", CACHE_TTL_SECONDS);
}
return count;
} catch (error: unknown) {
// ...TRUNCATED
}
}
এখানে আমরা:
- চেক করি
view-countজন্য ইতিমধ্যে কোনো আপস্ট্যাশ ফর রেডিস ক্যাশড ভ্যালু আছে কিনাredis.get('view-count')কল দিয়ে। - যদি থাকে, ক্যাশড ভ্যালু ফেরত দেয়, অন্যথায় Tinybird থেকে একটি নতুন ভ্যালু পায়।
- নতুন ভ্যালুটিকে আপস্ট্যাশ ফর রেডিস ক্যাশে স্টোর করে এবং এক্সপায়ারি সেট করে
redis.set('view-count', value)কল দিয়ে তারপরredis.expire(TTL)। এটি একটি টাইম টু লিভ (TTL) ভ্যালু সহ ভ্যালু সেট করে যার পর ডেটা পুরনো ধরে নেওয়া হয়। আমরা এখানে TTL চার ঘণ্টা সেট করেছি। সেই পেরিয়ডের পরgetTinybirdViewsকল গুলোর জন্য, আমরা Tinybird-এ হিট করব একটি নতুন ভ্যালুর জন্য।

পেজটি রিফ্রেশ করুন (কয়েকবার) আপস্ট্যাশ ফর রেডিস উভয় ডেটা কোয়েরিতে ইন্টিগ্রেটেড থাকা অবস্থায়, আমরা জিনিসগুলো স্পিড আপ দেখতে পাই। এখানে আমরা ঠিক ২ সেকেন্ডের বেশি থেকে প্রায় ০.২৯ সেকেন্ডে নামিয়ে এনেছি। এখানে সংখ্যাগুলোতে অনেক বেশি আস্থা করবেন না কারণ আমরা লোকালি রান করছি এবং আমাদের অনেক ডেটা পয়েন্ট নেই। আপনার নিজের অ্যাপে সার্ভিসটি ট্রাই করুন কী ধরনের গেইন আপনি অর্জন করতে পারেন তা দেখতে।
আপস্ট্যাশ ফর রেডিস এবং পারফরম্যান্স API: উপসংহার
এখানে, আমরা দেখেছি কীভাবে জাভাস্ক্রিপ্ট পারফরম্যান্স API আপনার অপ্টিমাইজেশন প্রচেষ্টার ফোকাস কোথায় রাখবেন তা গাইড করতে সাহায্য করতে পারে। এর বাইরে, আমরা দেখেছি কীভাবে Deno Fresh-এ আপস্ট্যাশ ফর রেডিস বাস্তবায়ন করা যায়। অবশেষে আমরা আবিষ্কার করেছি যে Deno সার্ভার সাইডে ওয়েব API সাপোর্ট করে, যা লার্নিং কার্ভ সমতল করে। Deno-র অপ্টিমাইজেশনের জন্য অন্য বড় সুবিধা হলো ইনস্ট্যান্ট ডিপ্লয়, যা আপনাকে একটি ছোট ফিডব্যাক লুপ দেয় এবং পারফরম্যান্স ফাইন-টিউন করার সময় আপনাকে দ্রুত কাজ করতে দেয়।
আশা করি আপস্ট্যাশ ফর রেডিস এবং পারফরম্যান্স API নিয়ে পড়া আপনাকে মূল্যবান লেগেছে। আপনি যদি Deno বা Deno Fresh-এ নতুন হন, Deno-র সাথে শুরু করার জন্য আমার তৈরি কিছু কন্টেন্ট দেখুন। আপনি GitHub-এ অ্যাপের পূর্ণ কোড খুলতে পারেন।