En aquest tema, explorarem dues tècniques essencials per millorar el rendiment de les aplicacions GraphQL: l'agrupació (batching) i l'emmagatzematge en memòria cau (caching). Aquestes tècniques ajuden a reduir la latència i a optimitzar l'ús dels recursos del servidor.

Agrupació (Batching)

Què és l'agrupació?

L'agrupació és una tècnica que permet combinar múltiples sol·licituds en una sola operació per reduir el nombre de crides a la base de dades o a altres serveis externs. Això és especialment útil en GraphQL, on una sola consulta pot desencadenar múltiples resolucions de dades.

Exemple pràctic d'agrupació

Suposem que tenim una consulta que necessita obtenir informació de diversos usuaris:

query {
  users {
    id
    name
    posts {
      id
      title
    }
  }
}

Sense agrupació, cada resolució de posts per a cada usuari podria resultar en una crida separada a la base de dades. Amb l'agrupació, podem combinar aquestes crides en una sola operació.

Implementació amb DataLoader

Una eina popular per implementar l'agrupació en GraphQL és DataLoader. A continuació, es mostra com utilitzar DataLoader per agrupar crides a la base de dades:

const DataLoader = require('dataloader');

// Funció per carregar múltiples usuaris per ID
const batchUsers = async (userIds) => {
  const users = await User.find({ _id: { $in: userIds } });
  return userIds.map(id => users.find(user => user.id === id));
};

// Crear una instància de DataLoader
const userLoader = new DataLoader(batchUsers);

// Resolver per a la consulta d'usuaris
const resolvers = {
  Query: {
    users: () => userLoader.loadMany([1, 2, 3]), // Exemple d'IDs d'usuaris
  },
  User: {
    posts: (user) => Post.find({ userId: user.id }),
  },
};

Beneficis de l'agrupació

  • Reducció de crides a la base de dades: Menys crides significa menys latència i menys càrrega al servidor.
  • Millora del rendiment: Les operacions agrupades són més eficients i poden processar-se més ràpidament.

Emmagatzematge en memòria cau (Caching)

Què és l'emmagatzematge en memòria cau?

L'emmagatzematge en memòria cau és una tècnica per guardar dades recentment sol·licitades en una ubicació temporal (memòria cau) per accelerar futures sol·licituds de les mateixes dades. Això redueix la necessitat de recalcular o tornar a obtenir dades des de la font original.

Tipus de memòria cau

  • Memòria cau del client: Emmagatzematge de dades al costat del client per evitar sol·licituds repetides al servidor.
  • Memòria cau del servidor: Emmagatzematge de dades al costat del servidor per evitar recalculs o crides repetides a la base de dades.

Implementació de la memòria cau

Memòria cau del client amb Apollo Client

Apollo Client ofereix una solució integrada per a la memòria cau del client:

import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:4000/graphql',
  cache: new InMemoryCache(),
});

Memòria cau del servidor amb Redis

Redis és una eina popular per a la memòria cau del servidor. A continuació, es mostra com utilitzar Redis per emmagatzemar dades en memòria cau:

const redis = require('redis');
const client = redis.createClient();

// Funció per obtenir dades amb memòria cau
const getUser = async (id) => {
  const cacheKey = `user:${id}`;
  const cachedUser = await client.get(cacheKey);

  if (cachedUser) {
    return JSON.parse(cachedUser);
  }

  const user = await User.findById(id);
  await client.set(cacheKey, JSON.stringify(user), 'EX', 3600); // Emmagatzema durant 1 hora
  return user;
};

// Resolver per a la consulta d'usuari
const resolvers = {
  Query: {
    user: (_, { id }) => getUser(id),
  },
};

Beneficis de la memòria cau

  • Reducció de la latència: Les dades emmagatzemades en memòria cau es poden recuperar més ràpidament que les dades obtingudes des de la font original.
  • Reducció de la càrrega del servidor: Menys crides a la base de dades o a altres serveis externs.

Exercici pràctic

Exercici

Implementa una solució d'agrupació i memòria cau per a una consulta que obtingui informació de productes i les seves categories.

Pas 1: Crear un DataLoader per agrupar les crides a la base de dades de categories.

const batchCategories = async (categoryIds) => {
  const categories = await Category.find({ _id: { $in: categoryIds } });
  return categoryIds.map(id => categories.find(category => category.id === id));
};

const categoryLoader = new DataLoader(batchCategories);

Pas 2: Implementar la memòria cau del servidor amb Redis per a les dades de productes.

const getProduct = async (id) => {
  const cacheKey = `product:${id}`;
  const cachedProduct = await client.get(cacheKey);

  if (cachedProduct) {
    return JSON.parse(cachedProduct);
  }

  const product = await Product.findById(id);
  await client.set(cacheKey, JSON.stringify(product), 'EX', 3600); // Emmagatzema durant 1 hora
  return product;
};

Pas 3: Integrar les solucions d'agrupació i memòria cau en els resolvers.

const resolvers = {
  Query: {
    product: (_, { id }) => getProduct(id),
    products: () => Product.find(),
  },
  Product: {
    category: (product) => categoryLoader.load(product.categoryId),
  },
};

Solució

const DataLoader = require('dataloader');
const redis = require('redis');
const client = redis.createClient();

// Funció per agrupar categories
const batchCategories = async (categoryIds) => {
  const categories = await Category.find({ _id: { $in: categoryIds } });
  return categoryIds.map(id => categories.find(category => category.id === id));
};

const categoryLoader = new DataLoader(batchCategories);

// Funció per obtenir productes amb memòria cau
const getProduct = async (id) => {
  const cacheKey = `product:${id}`;
  const cachedProduct = await client.get(cacheKey);

  if (cachedProduct) {
    return JSON.parse(cachedProduct);
  }

  const product = await Product.findById(id);
  await client.set(cacheKey, JSON.stringify(product), 'EX', 3600); // Emmagatzema durant 1 hora
  return product;
};

// Resolvers
const resolvers = {
  Query: {
    product: (_, { id }) => getProduct(id),
    products: () => Product.find(),
  },
  Product: {
    category: (product) => categoryLoader.load(product.categoryId),
  },
};

Conclusió

L'agrupació i l'emmagatzematge en memòria cau són tècniques poderoses per millorar el rendiment de les aplicacions GraphQL. L'agrupació redueix el nombre de crides a la base de dades, mentre que l'emmagatzematge en memòria cau accelera la recuperació de dades. Implementar aquestes tècniques pot significar una gran diferència en l'eficiència i la velocitat de la teva aplicació.

© Copyright 2024. Tots els drets reservats