Введение

Микросервис — это отдельная автономная единица, которая вместе со многими другими составляет большое приложение. Благодаря разделению вашего приложения на небольшие блоки каждая его часть может быть развернута и масштабируема независимо друг от друга, может быть написана разными командами и на разных языках программирования, а также может быть протестирована индивидуально.

Микросервисная архитектура означает, что ваше приложение состоит из множества небольших независимых приложений, способных работать в своем собственном пространстве памяти и масштабироваться независимо друг от друга на потенциально многих отдельных машинах.

Обзор Kubernetes

Kubernetes (K8s) — это система с открытым исходным кодом для автоматизации и управления оркестровкой контейнеров, которая выросла из Google Borg и теперь поддерживается Cloud Native Computing Foundation.

Благодаря удобному пользовательскому интерфейсу, ориентированному на разработчиков и инженеров DevOps, и впечатляющему набору функций оркестровки, включая автоматические развертывания и откаты, обнаружение сервисов, балансировку нагрузки, а также управление секретами и конфигурациями, Kubernetes за короткое время обеспечил большую поддержку. Интеграция со всеми основными облачными провайдерами обеспечивает переносимость Kubernetes в различные инфраструктуры.

Архитектура Кубернета

Архитектура Kubernetes на основе мастер-узлов обеспечивает быстрое горизонтальное масштабирование. Сетевые функции помогают ускорить обмен данными между различными элементами Kubernetes, между ними и между ними.

Вот основные компоненты архитектуры Kubernetes:

  • Под. Наименьшая развертываемая единица, созданная и управляемая Kubernetes. Под — это группа из одного или нескольких контейнеров. Контейнеры в поде имеют общий IP-адрес и могут получать доступ друг к другу через локальный хост, а также пользоваться общим доступом к томам.
  • Узел: рабочий компьютер в Kubernetes. Это может быть виртуальная машина или физическая машина, и она поставляется со службами, необходимыми для запуска Pods.
  • Сервис. Абстракция, определяющая логический набор модулей и политику доступа к ним. Назначает фиксированный IP-адрес репликам пода, позволяя другим подам или службам взаимодействовать с ними.
  • ReplicaSet: гарантирует, что указанное количество реплик Pod работает в любой момент времени. K8s рекомендует использовать Deployments вместо прямого управления объектами ReplicaSet, если только вам не требуется индивидуальная оркестровка обновлений или вообще не требуются обновления.
  • Развертывание: контроллер, предоставляющий декларативные обновления для модулей Pod и наборов реплик.
  • Пространство имен: виртуальный кластер, поддерживаемый тем же физическим кластером. Способ разделения ресурсов кластера между несколькими пользователями и механизм привязки авторизации и политики к подразделу данного кластера.

Архитектура приложения

Приложение представляет собой мини-сервер электронной коммерции с возможностью покупать и создавать продукты. Одновременно можно купить несколько продуктов, и будет создан соответствующий заказ.

Приложение будет состоять из трех независимых служб: службы аутентификации для аутентификации пользователей, службы продуктов для создания и покупки продуктов и службы заказов, через которую пользователь может получить доступ к заказам.

Начать

products/index.js будет состоять из двух маршрутов: один для получения всех продуктов из базы данных, а другой — для покупки продуктов. Последний вызовет микрослужбу заказа для создания нового объекта заказа и сохранения его в базе данных, а затем отправит его клиенту через ответ.

const express = require('express');
require('express-async-errors');
const sequelize = require('./database');
const isAuthenticated = require('./isAuthenticated');
const Product = require('./product.model');
const amqp = require('amqplib');
const Sequelize = require('sequelize');

let channel;

async function connect() {
  const amqpServer = process.env.RABBITMQ_URL;
  const connection = await amqp.connect(amqpServer);
  channel = await connection.createChannel();
  await channel.assertQueue('PRODUCT');
}

connect().catch(error => {
  console.error('Unable to connect to the Rabbit MQ:', error);
  process.exit(1);
});

const app = express();

app.use(express.json());

const port = +process.env.PORT ?? 3002;

app.listen(port, () => {
  console.log(`Products Service at ${port}`);
});

app.get('/products', async (req, res) => {
  const results = await Product.findAll();

  res.status(200).json(results);
});

app.post('/products', isAuthenticated, async (req, res) => {
  const { name, price, description, imageURL } = req.body;

  const product = await Product.create({
    name,
    price,
    description,
    imageURL,
    creator: req.user.email,
  });

  res.status(200).json(product);
});

app.post('/products/buy', isAuthenticated, async (req, res) => {
  const { ids } = req.body;
  const products = await Product.findAll({
    where: {
      id: {
        [Sequelize.Op.in]: ids,
      },
    },
  });
  let order;

  channel.sendToQueue(
    'ORDER',
    Buffer.from(
      JSON.stringify({
        products,
        userEmail: req.user.email,
      })
    )
  );
  await channel.consume('PRODUCT', data => {
    order = JSON.parse(data.content);
  });
  res.json(order);
});

sequelize.sync();

Orders/index.js будет прослушивать сообщение «ЗАКАЗ», и как только он получит это сообщение, он возьмет предоставленный идентификатор электронной почты покупателя и все идентификаторы продуктов и сгенерирует объект заказа с этими данными. Затем служба заказов отправит эти данные обратно в службу продуктов через RabbitMQ.

const express = require('express');
require('express-async-errors');
const sequelize = require('./database');
const isAuthenticated = require('./isAuthenticated');
const Order = require('./order.model.js');
const amqp = require('amqplib');

let channel;

async function createOrder(products, userEmail) {
  let total = 0;
  for (let t = 0; t < products.length; ++t) {
    total += +products[t].price;
  }

  products = products.map(product => {
    return product.id;
  });

  const newOrder = await Order.create({
    products,
    creator: userEmail,
    totalPrice: total,
  });

  return newOrder;
}

async function connect() {
  const amqpServer = process.env.RABBITMQ_URL;
  const connection = await amqp.connect(amqpServer);
  channel = await connection.createChannel();
  await channel.assertQueue('ORDER');
}

connect()
  .then(() => {
    channel.consume('ORDER', data => {
      console.log('Consuming ORDER service');
      const { products, userEmail } = JSON.parse(data.content);
      createOrder(products, userEmail)
        .then(newOrder => {
          channel.ack(data);
          channel.sendToQueue(
            'PRODUCT',
            Buffer.from(JSON.stringify({ newOrder }))
          );
        })
        .catch(err => {
          console.log(err);
        });
    });
  })
  .catch(error => {
    console.error('Unable to connect to the Rabbit MQ:', error);
    process.exit(1);
  });

const app = express();

app.use(express.json());

const port = +process.env.PORT ?? 3003;

app.listen(port, () => {
  console.log(`Orders Service at ${port}`);
});

app.get('/orders', async (req, res) => {
  const results = await Order.findAll();

  res.status(200).json(results);
});

sequelize.sync();

Как видите, эти сервисы полностью независимы друг от друга. Архитектура микросервисов может быть полезным инструментом, однако в небольших проектах применение этой архитектуры может привести к определенным сложностям, таким как дублирование кода и ненужные сложности. Следовательно, эту архитектуру часто рекомендуют для более крупных проектов, над которыми работает огромная команда инженеров. Вы можете проверить полный репозиторий приведенного выше кода ниже.



Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:

  • 👏 Хлопайте за историю и подписывайтесь на автора 👉
  • 📰 Смотрите больше контента в публикации Level Up Coding
  • 🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"

🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу