Usullar7 min read

Keshlash

Keshlash ilovangiz unumdorligini oshirish uchun kuchli va sodda texnika. U vaqtinchalik saqlash qatlamini taqdim etib, tez-tez ishlatiladigan ma'lumotlarga tezroq kirishni ta'minla

Keshlash ilovangiz unumdorligini oshirish uchun kuchli va sodda texnika. U vaqtinchalik saqlash qatlamini taqdim etib, tez-tez ishlatiladigan ma'lumotlarga tezroq kirishni ta'minlaydi va bir xil ma'lumotni qayta-qayta olish yoki hisoblash zaruratini kamaytiradi. Natijada javob vaqti tezlashadi va umumiy samaradorlik oshadi.

O'rnatish

Nestda keshlashni boshlash uchun @nestjs/cache-manager paketi bilan birga cache-manager paketini o'rnatishingiz kerak.

Terminal
1$ npm install @nestjs/cache-manager cache-manager

Standart holatda hamma narsa xotirada saqlanadi; cache-manager ichkarida Keyv dan foydalangani uchun, mos paketni o'rnatib, Redis kabi yanada rivojlangan saqlash yechimiga oson o'tishingiz mumkin. Buni keyinroq batafsil ko'rib chiqamiz.

Xotira ichidagi kesh

Ilovangizda keshlashni yoqish uchun CacheModule ni import qiling va register() metodi orqali sozlang:

TypeScript
1import { Module } from '@nestjs/common';
2import { CacheModule } from '@nestjs/cache-manager';
3import { AppController } from './app.controller';
4
5@Module({
6  imports: [CacheModule.register()],
7  controllers: [AppController],
8})
9export class AppModule {}

Bu sozlama xotira ichidagi keshlashni default sozlamalar bilan ishga tushiradi va darhol ma'lumotlarni keshlashni boshlash imkonini beradi.

Cache store bilan ishlash

Cache manager instansiyasi bilan ishlash uchun CACHE_MANAGER tokeni yordamida uni sinfingizga in'eksiya qiling:

TypeScript
1constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
Hint

Cache sinfi va CACHE_MANAGER tokeni ikkalasi ham @nestjs/cache-manager paketidan import qilinadi.

Cache instansiyasidagi get metodi (cache-manager paketidan) keshdan elementlarni olish uchun ishlatiladi. Agar element keshda mavjud bo'lmasa, null qaytariladi.

TypeScript
1const value = await this.cacheManager.get('key');

Keshga element qo'shish uchun set metodidan foydalaning:

TypeScript
1await this.cacheManager.set('key', 'value');
Note

Xotira ichidagi kesh faqat structured clone algorithm qo'llab-quvvatlaydigan tiplardagi qiymatlarni saqlay oladi.

Muayyan kalit uchun TTL (millisekundlardagi amal qilish muddati) ni qo'lda ko'rsatishingiz mumkin, quyidagicha:

TypeScript
1await this.cacheManager.set('key', 'value', 1000);

Bu yerda 1000 TTL millisekundlarda - bu holatda kesh elementi bir soniyadan keyin yaroqsiz bo'ladi.

Keshning eskirishini o'chirish uchun ttl konfiguratsiya xossasini 0 ga o'rnating:

TypeScript
1await this.cacheManager.set('key', 'value', 0);

Keshdan elementni o'chirish uchun del metodidan foydalaning:

TypeScript
1await this.cacheManager.del('key');

Butun keshni tozalash uchun clear metodidan foydalaning:

TypeScript
1await this.cacheManager.clear();

Javoblarni avtomatik keshlash

Warning

GraphQL ilovalarida interceptorlar har bir field resolver uchun alohida bajariladi. Shuning uchun CacheModule (javoblarni keshlash uchun interceptorlardan foydalanadi) to'g'ri ishlamaydi.

Javoblarni avtomatik keshlashni yoqish uchun, ma'lumot keshlanadigan joyda CacheInterceptor ni bog'lang.

TypeScript
1@Controller()
2@UseInterceptors(CacheInterceptor)
3export class AppController {
4  @Get()
5  findAll(): string[] {
6    return [];
7  }
8}
Warning

Faqat GET endpointlar keshlanadi. Shuningdek, native response obyektini in'eksiya qiladigan HTTP server route'lari (@Res()) Cache Interceptor'dan foydalana olmaydi. Batafsil ma'lumot uchun response mapping ga qarang.

Kerakli boilerplate miqdorini kamaytirish uchun CacheInterceptor ni barcha endpointlarga global tarzda bog'lashingiz mumkin:

TypeScript
1import { Module } from '@nestjs/common';
2import { CacheModule, CacheInterceptor } from '@nestjs/cache-manager';
3import { AppController } from './app.controller';
4import { APP_INTERCEPTOR } from '@nestjs/core';
5
6@Module({
7  imports: [CacheModule.register()],
8  controllers: [AppController],
9  providers: [
10    {
11      provide: APP_INTERCEPTOR,
12      useClass: CacheInterceptor,
13    },
14  ],
15})
16export class AppModule {}

Time-to-live (TTL)

ttl ning default qiymati 0, ya'ni kesh hech qachon eskirmaydi. Maxsus TTL ni ko'rsatish uchun register() metodida ttl opsiyasini bering, quyidagicha:

TypeScript
1CacheModule.register({
2  ttl: 5000, // milliseconds
3});

Modulni global ishlatish

CacheModule ni boshqa modullarda ishlatmoqchi bo'lsangiz, uni import qilishingiz kerak (istalgan Nest modulida bo'lgani kabi). Muqobil ravishda, opsiyalar obyektidagi isGlobal xossasini true qilib, uni global modul sifatida e'lon qilishingiz mumkin, quyida ko'rsatilgandek. Bunda CacheModule bir marta root modulda (masalan, AppModule) yuklangach, boshqa modullarda uni import qilishingiz shart bo'lmaydi.

TypeScript
1CacheModule.register({
2  isGlobal: true,
3});

Global kesh override'lari

Global kesh yoqilganda, kesh yozuvlari route path asosida avtomatik generatsiya qilingan CacheKey ostida saqlanadi. Siz @CacheKey() va @CacheTTL() yordamida kesh sozlamalarini har bir metod bo'yicha override qilishingiz mumkin, bu har bir controller metodi uchun alohida keshlash strategiyalarini taqdim etadi. Bu ko'proq turli kesh store'larini ishlatayotganda dolzarb bo'ladi.

Butun controller uchun TTL belgilash uchun @CacheTTL() dekoratorini controller darajasida qo'llashingiz mumkin. Agar controller darajasida ham, metod darajasida ham cache TTL sozlamalari berilgan bo'lsa, metod darajasidagi sozlama ustuvor bo'ladi.

TypeScript
1@Controller()
2@CacheTTL(50)
3export class AppController {
4  @CacheKey('custom_key')
5  @CacheTTL(20)
6  findAll(): string[] {
7    return [];
8  }
9}
Hint

@CacheKey() va @CacheTTL() dekoratorlari @nestjs/cache-manager paketidan import qilinadi.

@CacheKey() dekoratori mos @CacheTTL() dekoratorisiz ham, aksincha ham ishlatilishi mumkin. Kimdir faqat @CacheKey() yoki faqat @CacheTTL() ni override qilishni tanlashi mumkin. Dekorator bilan override qilinmagan sozlamalar global ro'yxatdan o'tkazilgandagi default qiymatlardan foydalanadi (qarang Customize caching).

WebSockets va Microservices

CacheInterceptor ni WebSocket subscriberlariga ham, Microservice patternlariga ham (qaysi transport metodi ishlatilishidan qat'i nazar) qo'llashingiz mumkin.

TypeScript
1@CacheKey('events')
2@UseInterceptors(CacheInterceptor)
3@SubscribeMessage('events')
4handleEvent(client: Client, data: string[]): Observable<string[]> {
5  return [];
6}

Biroq, keyinchalik keshlangan ma'lumotlarni saqlash va olish uchun ishlatiladigan kalitni ko'rsatish maqsadida qo'shimcha @CacheKey() dekoratori talab qilinadi. Shuningdek, hamma narsani keshlamasligingiz kerakligini unutmang. Ma'lumotni shunchaki so'rashdan ko'ra biznes operatsiyalarni bajaradigan amallar hech qachon keshlanmasligi kerak.

Bundan tashqari, @CacheTTL() dekoratori yordamida keshning amal qilish muddati (TTL)ni ko'rsatishingiz mumkin, u global default TTL qiymatini override qiladi.

TypeScript
1@CacheTTL(10)
2@UseInterceptors(CacheInterceptor)
3@SubscribeMessage('events')
4handleEvent(client: Client, data: string[]): Observable<string[]> {
5  return [];
6}
Hint

@CacheTTL() dekoratori mos @CacheKey() dekoratorisiz ham ishlatilishi mumkin.

Trackingni moslash

Standart holatda Nest endpointlaringiz bilan kesh yozuvlarini bog'lash uchun request URL (HTTP ilovada) yoki kesh kalitidan (websocket va microservice ilovalarida, @CacheKey() dekoratori orqali beriladi) foydalanadi. Shunga qaramay, ba'zan trackingni boshqa omillar asosida sozlashni xohlashingiz mumkin, masalan, HTTP headerlar (masalan, Authorization orqali profile endpointlarini to'g'ri identifikatsiya qilish).

Buni amalga oshirish uchun CacheInterceptor dan meros olib, trackBy() metodini override qiling.

TypeScript
1@Injectable()
2class HttpCacheInterceptor extends CacheInterceptor {
3  trackBy(context: ExecutionContext): string | undefined {
4    return 'key';
5  }
6}

Muqobil Cache store'lardan foydalanish

Boshqa kesh store'ga o'tish juda sodda. Avval mos paketni o'rnating. Masalan, Redisdan foydalanish uchun @keyv/redis paketini o'rnating:

Terminal
1$ npm install @keyv/redis

Shundan so'ng, quyidagicha bir nechta store bilan CacheModule ni ro'yxatdan o'tkazishingiz mumkin:

TypeScript
1import { Module } from '@nestjs/common';
2import { CacheModule } from '@nestjs/cache-manager';
3import { AppController } from './app.controller';
4import KeyvRedis from '@keyv/redis';
5import { Keyv } from 'keyv';
6import { CacheableMemory } from 'cacheable';
7
8@Module({
9  imports: [
10    CacheModule.registerAsync({
11      useFactory: async () => {
12        return {
13          stores: [
14            new Keyv({
15              store: new CacheableMemory({ ttl: 60000, lruSize: 5000 }),
16            }),
17            new KeyvRedis('redis://localhost:6379'),
18          ],
19        };
20      },
21    }),
22  ],
23  controllers: [AppController],
24})
25export class AppModule {}

Bu misolda biz ikki store'ni ro'yxatdan o'tkazdik: CacheableMemory va KeyvRedis. CacheableMemory store'i oddiy xotira ichidagi store, KeyvRedis esa Redis store. stores massivi ishlatiladigan store'larni ko'rsatish uchun ishlatiladi. Massivdagi birinchi store default store bo'ladi, qolganlari esa fallback store'lar.

Mavjud store'lar haqida ko'proq ma'lumot uchun Keyv hujjatlarini ko'ring.

Asinxron konfiguratsiya

Ba'zan modul opsiyalarini kompilyatsiya vaqtida statik uzatish o'rniga asinxron tarzda uzatish kerak bo'ladi. Bunday holatda bir nechta usullarni taqdim etadigan registerAsync() metodidan foydalaning.

Yondashuvlardan biri - factory funksiyasidan foydalanish:

TypeScript
1CacheModule.registerAsync({
2  useFactory: () => ({
3    ttl: 5,
4  }),
5});

Bizning factory boshqa asinxron modul factory'lari kabi ishlaydi (u async bo'lishi mumkin va inject orqali bog'liqliklarni in'eksiya qila oladi).

TypeScript
1CacheModule.registerAsync({
2  imports: [ConfigModule],
3  useFactory: async (configService: ConfigService) => ({
4    ttl: configService.get('CACHE_TTL'),
5  }),
6  inject: [ConfigService],
7});

Muqobil ravishda, useClass metodidan foydalanishingiz mumkin:

TypeScript
1CacheModule.registerAsync({
2  useClass: CacheConfigService,
3});

Yuqoridagi konstruktsiya CacheConfigService ni CacheModule ichida instansiyalaydi va undan opsiyalar obyektini olish uchun foydalanadi. CacheConfigService konfiguratsiya opsiyalarini taqdim etishi uchun CacheOptionsFactory interfeysini amalga oshirishi shart:

TypeScript
1@Injectable()
2class CacheConfigService implements CacheOptionsFactory {
3  createCacheOptions(): CacheModuleOptions {
4    return {
5      ttl: 5,
6    };
7  }
8}

Agar boshqa moduldan import qilingan mavjud konfiguratsiya provayderidan foydalanmoqchi bo'lsangiz, useExisting sintaksisini ishlating:

TypeScript
1CacheModule.registerAsync({
2  imports: [ConfigModule],
3  useExisting: ConfigService,
4});

Bu useClass bilan bir xil ishlaydi, faqat bitta muhim farq bilan - CacheModule o'z ConfigService instansiyasini yaratish o'rniga, import qilingan modullarda mavjud bo'lgan allaqachon yaratilgan ConfigService ni qayta ishlatadi.

Hint

CacheModule#register, CacheModule#registerAsync va CacheOptionsFactory ixtiyoriy generic (tip argumenti)ga ega bo'lib, store'ga xos konfiguratsiya opsiyalarini toraytirishga yordam beradi va type safety ta'minlaydi.

registerAsync() metodiga extraProviders deb ataladigan provayderlarni ham uzatishingiz mumkin. Bu provayderlar modul provayderlariga qo'shib yuboriladi.

TypeScript
1CacheModule.registerAsync({
2  imports: [ConfigModule],
3  useClass: ConfigService,
4  extraProviders: [MyAdditionalProvider],
5});

Bu factory funksiyasiga yoki sinf konstruktori uchun qo'shimcha bog'liqliklar taqdim etmoqchi bo'lganingizda foydali.

Misol

Ishlaydigan misol bu yerda mavjud.