Статьи

Введение в QBit — мощная микросервисная библиотека для Java


QBit — это библиотека очередей для 
микросервисов . Он похож на многие другие проекты, такие как 
Akka
Spring Reactor  и т. Д. QBit — это просто библиотека, а не платформа. QBit имеет библиотеки для размещения службы в 
очереди . Вы можете использовать очереди QBit напрямую или создать службу. Сервисы QBit могут быть доступны через 
WebSocket
HTTP
HTTP pipe и другие типы удаленного взаимодействия. Сервис в QBit — это класс Java, методы которого выполняются за очередями сервисов. QBit реализует 
многопоточность модели квартиры  и похожа на 
модель Actor,  или лучшим описанием будут 
Active Objects, QBit не использует разрушитель. Он использует обычные Java-очереди. QBit может выполнять до 100 миллионов вызовов в пинг-понг в секунду, что является удивительной скоростью (до 200 м). QBit также поддерживает сервисы вызова через 
REST и WebSocket. QBit — это микросервисы в чистом веб-смысле: 
JSON , HTTP, WebSocket и т. Д.

Философия QBit — почему QBit такой быстрый?

Когда вы слышите слово быстро, первое, что приходит на ум, это гоночный автомобиль / водитель. Как водитель получает максимум от своей машины и выигрывает гонку? это просто понимание того, как работает его машина. Ему не нужно знать, как восстановить двигатель или трансмиссию и т. Д., Ему просто нужно знать, как он работает, и работать в гармонии со своей машиной.

Я считаю, что это очень похоже на информатику, разработчики могут писать очень быстрый код, если они хорошо понимают, как работает аппаратное обеспечение, используемое в вычислениях (ЦП, кэш-память L1, L2, L3, основная память и т. Д.). Посмотрите на эту фотографию рулевого колеса Формулы 1:

Это выглядит страшно по сравнению с обычным стальным колесом, да, не пугайтесь всех, кого вы видите; например, один из них используется для ускорения движения автомобиля, но в то же время он изнашивает двигатель и потребляет больше топлива, другой — для регулировки баланса переднего и заднего тормозов. таким образом, все эти штучки — всего лишь инструменты для водителя, чтобы получить максимальную скорость от своей машины, это объясняет «механическую симпатию», и это объясняется таким образом Мартином Томпсоном.

QBit использует эту философию для обеспечения очень быстрого выполнения кода / службы, хороший пример, чтобы показать вам некоторые из методологий QBit, это пример шины событий. Шина событий слабо моделируется после шины событий Vertx, за исключением того, что с помощью QBit вы можете отправлять строго типизированные объекты, JSON, Карты и т. Д. Шина событий была написана с использованием библиотеки QBit, так что это не только быстрая шина событий, но и пример использования QBit для написания быстрого сервиса. 

Пример шины событий:


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

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

В этом примере используются два канала:  
  public static final String NEW_HIRE_CHANNEL = "com.mycompnay.employee.new";

    public static final String PAYROLL_ADJUSTMENT_CHANNEL = "com.mycompnay.employee.payroll";

Первый канал 
NEW_HIRE_CHANNEL  — это место, где мы отправляем новые объекты сотрудников, когда они нанимаются. Весь канал мог слушать этот канал.

Объект сотрудника выглядит так:
  public Employee(String firstName, int employeeId) {
            this.firstName = firstName;
            this.employeeId = employeeId;
        }

Вот геттеры для этого примера:
 public String getFirstName() {
            return firstName;
        }

        public int getEmployeeId() {
            return employeeId;
        }

        @Override
        public String toString() {
            return "Employee{" +
                    "firstName='" + firstName + '\'' +
                    ", employeeId=" + employeeId +
                    '}';

В этом примере есть три службы: 
EmployeeHiringService
BenefitsService и 
PayrollService .

Эти услуги являются недействительными.
QBit также поддерживает удаленные сервисы WebSocket, HTTP и REST, но сейчас давайте сосредоточимся на сервисах inproc. Если вы понимаете inproc, то вы поймете удаленное.

Служба  EmployeeHiringService  фактически запускает события для двух других служб:

public class EmployeeHiringService {



        public void hireEmployee(final Employee employee) {

            int salary = 100;
            System.out.printf("Hired employee %s\n", employee);

            //Does stuff to hire employee

            //Sends events
            final EventManager eventManager = 
                              serviceContext().eventManager();

            eventManager.send(NEW_HIRE_CHANNEL, employee);

            eventManager.sendArray(PAYROLL_ADJUSTMENT_CHANNEL, 
                                                employee, salary);


        }

    }

В этом примере мы используем сервисы в QBit, что дает нам много преимуществ; события поступают в ту же очередь, которая обрабатывает вызовы метода, поэтому вызовы метода событий являются потокобезопасными. Все входит в один поток, события и методы. Чтобы подключить сервисы к qbit, очень просто сделать следующее:

EmployeeHiringService employeeHiring = new EmployeeHiringService();
Service employeeHiringService = serviceBuilder()
                .setServiceObject(employeeHiring)
                .setInvokeDynamic(false).build();

При работе внутри службы QBit вы можете получить доступ к менеджеру событий с помощью serviceContext (). EventManager (). Если вы получите к нему доступ таким образом, вы позаботитесь о вас. Сброс сообщений в другие службы пакетами помогает повысить производительность. Вы должны сбросить после использования клиентского прокси. Метод eventManager () возвращает клиентский прокси. При работе внутри QBit вам не нужно сбрасывать, это делается для вас в тот момент, когда / где вы получите максимальную производительность системы. Это то, что позволяет менеджеру событий отправлять так много сообщений за такой короткий промежуток времени. Не только отправлять сообщения, но и ставить их в очередь на другие сервисные очереди.

Обратите внимание на   службу EmployeeHiringService, которую мы вызываем sendArray, чтобы мы могли отправить сотруднику и его зарплату. Слушатель для  PAYROLL_ADJUSTMENT_CHANNEL  должен обрабатывать как сотрудника, так и int, представляющий новую зарплату сотрудника.

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

public class BenefitsService {

        @OnEvent(NEW_HIRE_CHANNEL)
        public void enroll(final Employee employee) {

            System.out.printf("Employee enrolled into benefits system employee %s %d\n",
                    employee.getFirstName(), employee.getEmployeeId());

        }

    }

Сотрудник — это объект Employee из 
EmployeeHiringService . так что вы можете получить свои преимущества.

Как я показал вам раньше; здесь мы создаем объекты и подключаем все сервисы к устройству массового обслуживания QBit.

  EmployeeHiringService employeeHiring = new EmployeeHiringService();
        PayrollService payroll = new PayrollService();
        BenefitsService benefits = new BenefitsService();


        Service employeeHiringService = serviceBuilder()
                .setServiceObject(employeeHiring)
                .setInvokeDynamic(false).build();

        Sys.sleep(100);


        Service payrollService = serviceBuilder()
                .setServiceObject(payroll)
                .setInvokeDynamic(false).build();

        Sys.sleep(100);

        Service employeeBenefitsService = serviceBuilder()
                .setServiceObject(benefits)
                .setInvokeDynamic(false).build();








Объекты 
employeeHiringService
payrollService
employeeBenefitsService  являются службами QBit.

Для начала вам нужно получить клиентский прокси для 
EmployeeHiringService  с помощью 
employeeHiringService .

Также для вызова метода в службе QBit вы хотите получить клиентский прокси.
Клиентский прокси будет отправлять сообщения в службу. Служба получит эти сообщения как вызовы методов.

Каждый звонок отправляется по высокоскоростной внутренней очереди inproc.
Вы также можете использовать клиентский прокси для общения с QBit через WebSockets.

Для создания прокси вы используете   метод  ServicePro createProxy :

 EmployeeHiringServiceClient employeeHiringServiceClientProxy = 

                   employeeHiringService.createProxy(EmployeeHiringServiceClient.class);

Теперь, когда мы создали наш прокси, мы можем отправлять ему сообщения. Здесь клиентский прокси сделан и используется для найма Фади с идентификационным номером 1.

employeeHiringServiceClientProxy.hireEmployee(new Employee("Fadi", 1));

Время от времени нам приходится сбрасывать звонки на клиентский прокси.

Клиентский прокси сбрасывает вызовы каждый раз, когда достигается размер пакета очереди.
Таким образом, если размер пакета очереди был установлен на 5, то он будет сбрасываться каждые пять вызовов. Но независимо от того, когда вы закончите делать вызовы, вы должны сбросить вызовы следующим образом:
  flushServiceProxy(employeeHiringServiceClientProxy);

Если вы выполняли звонки на услугу в узком цикле, вы можете сбросить каждые десять звонков или каждые 100 звонков.
Или вы можете сбросить связанные вызовы.

Если вы установите размер пакета в 1, то каждый вызов метода сбрасывается, но это снижает производительность.

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

Теперь мы все сделали.
Но вы знаете, как приложения. Позже кто-то решает создать программу по работе с населением. Что теперь?

Достаточно просто, мы просто добавляем еще один сервис для прослушивания нового канала событий найма.

Сначала мы определим наш POJO:
 public class VolunteerService {

        @OnEvent(NEW_HIRE_CHANNEL)
        public void invite(final Employee employee) {

            System.out.printf("Employee will be invited to the community outreach program %s %d\n",
                    employee.getFirstName(), employee.getEmployeeId());

        }

    }

Так что теперь у нас есть наш новый сервис.

Давайте подключим это:
VolunteerService volunteering = new VolunteerService(); 
Service volunteeringService = serviceBuilder()
                .setServiceObject(volunteering)
                .setInvokeDynamic(false).build();

Это вывод этого приложения:

Hired employee Employee{firstName='Fadi', employeeId=1}
Employee added to payroll  Fadi 1 100
Employee enrolled into benefits system employee Fadi 1
Employee will be invited to the community outreach program Fadi 1

Теперь наш новый сотрудник принят на работу, добавлен в систему начисления заработной платы, зачислен на выплаты и приглашен в нашу программу по работе с населением. Вот полный список кодов :

package io.advantageous.qbit.example.events;

import io.advantageous.qbit.annotation.OnEvent;
import io.advantageous.qbit.events.EventManager;
import io.advantageous.qbit.service.Service;
import io.advantageous.qbit.service.ServiceProxyUtils;
import org.boon.Lists;
import org.boon.core.Sys;

import static io.advantageous.qbit.service.ServiceBuilder.serviceBuilder;
import static io.advantageous.qbit.service.ServiceContext.serviceContext;
import static io.advantageous.qbit.service.ServiceProxyUtils.flushServiceProxy;


public class EmployeeEventExample {

    public static final String NEW_HIRE_CHANNEL = "com.mycompnay.employee.new";

    public static final String PAYROLL_ADJUSTMENT_CHANNEL = "com.mycompnay.employee.payroll";

    public class Employee {
        final String firstName;
        final int employeeId;

        public Employee(String firstName, int employeeId) {
            this.firstName = firstName;
            this.employeeId = employeeId;
        }

        public String getFirstName() {
            return firstName;
        }

        public int getEmployeeId() {
            return employeeId;
        }

        @Override
        public String toString() {
            return "Employee{" +
                    "firstName='" + firstName + '\'' +
                    ", employeeId=" + employeeId +
                    '}';
        }
    }

    interface EmployeeHiringServiceClient {
        void hireEmployee(final Employee employee);

    }

    public class EmployeeHiringService {



        public void hireEmployee(final Employee employee) {

            int salary = 100;
            System.out.printf("Hired employee %s\n", employee);

            //Does stuff to hire employee

            //Sends events
            final EventManager eventManager = 
                              serviceContext().eventManager();

            eventManager.send(NEW_HIRE_CHANNEL, employee);

            eventManager.sendArray(PAYROLL_ADJUSTMENT_CHANNEL, 
                                                employee, salary);


        }

    }



    public class BenefitsService {

        @OnEvent(NEW_HIRE_CHANNEL)
        public void enroll(final Employee employee) {

            System.out.printf("Employee enrolled into benefits system employee %s %d\n",
                    employee.getFirstName(), employee.getEmployeeId());

        }

    }

    public class VolunteerService {

        @OnEvent(NEW_HIRE_CHANNEL)
        public void invite(final Employee employee) {

            System.out.printf("Employee will be invited to the community outreach program %s %d\n",
                    employee.getFirstName(), employee.getEmployeeId());

        }

    }



    public class PayrollService {

        @OnEvent(PAYROLL_ADJUSTMENT_CHANNEL)
        public void addEmployeeToPayroll(final Employee employee, int salary) {

            System.out.printf("Employee added to payroll  %s %d %d\n",
                    employee.getFirstName(), employee.getEmployeeId(), salary);

        }

    }

    public static void main(String... args) {


        EmployeeHiringService employeeHiring = new EmployeeHiringService();
        PayrollService payroll = new PayrollService();
        BenefitsService benefits = new BenefitsService();
        VolunteerService volunteering = new VolunteerService();


        Service employeeHiringService = serviceBuilder()
                .setServiceObject(employeeHiring)
                .setInvokeDynamic(false).build();

        Sys.sleep(100);


        Service payrollService = serviceBuilder()
                .setServiceObject(payroll)
                .setInvokeDynamic(false).build();

        Sys.sleep(100);

        Service employeeBenefitsService = serviceBuilder()
                .setServiceObject(benefits)
                .setInvokeDynamic(false).build();


        Service volunteeringService = serviceBuilder()
                .setServiceObject(volunteering)
                .setInvokeDynamic(false).build();

        EmployeeHiringServiceClient employeeHiringServiceClientProxy = 

                   employeeHiringService.createProxy(EmployeeHiringServiceClient.class);

        employeeHiringServiceClientProxy.hireEmployee(new Employee("Fadi", 1));

        flushServiceProxy(employeeHiringServiceClientProxy);

        Sys.sleep(5_000);

    }
}

Резюме:

Сравнивая рулевое колесо Формулы-1 с примером шины событий, вы можете увидеть, что водитель использовал нобов, чтобы получить максимальную скорость из своего автомобиля, и разработчик устанавливает пакет очереди, так что прокси-клиент клиента будет сбрасываться соответствующим образом, что позволит разработчик, чтобы получить максимальную скорость из своего вычислительного оборудования. Надеюсь, вам понравилась эта статья, мы ценим ваши комментарии и отзывы, следите за обновлениями для других статей. благодаря!

QBit Lingo

QBit — это библиотека микросервисов Java, поддерживающая REST, JSON и WebSocket. Он написан на Java, но я мог бы однажды написать версию на Rust или Go или C # (но это потребовало бы большой зарплаты).

  • Служба  POJO (обычный старый Java-объект) позади очереди, которая может принимать вызовы методов через вызовы прокси или события (может иметь один поток, управляющий событиями, вызовами методов и ответами, или два — один для вызовов методов и событий, а другой — для ответов, так что обработчики ответов не блокируйте сервис. Один быстрее, если ответы не блокируют). Сервисы могут использовать аннотации REST в стиле Spring MVC, чтобы представить себя внешнему миру через REST и WebSocket.
  • ServiceBundle  Множество POJO за одной очередью ответов и много очередей приема. Может быть одна тема для всех ответов или нет. Они также могут быть одной очередью приема.
  • Очередь  Поток, управляющий очередью. Он поддерживает дозирование. У этого есть события для пустого, достигли Лимита, запустили, пропускают. Вы можете прослушивать эти события из служб, которые находятся за очередью. Вам не нужно использовать Услуги. Вы можете использовать очередь напрямую.
  • ServiceServer  ServiceBundle, который открыт для связи REST и WebSocket
  • EventBus  EventBus — это способ отправки большого количества сообщений в службы, которые могут быть слабо связаны
  • ClientProxy  Способ вызова службы через асинхронный интерфейс, служба может быть inproc (тот же процесс) или удаленно через WebSocket.
  • Неблокирующая  библиотека QBit — это неблокирующая библиотека. Вы используете CallBacks через Java 8 Lambdas. Вы также можете отправлять сообщения о событиях и получать ответы. Обмен сообщениями встроен в систему, поэтому вы можете легко координировать сложные задачи.
  • Скорость  Есть много возможностей для улучшения со скоростью. Но уже QBit ОЧЕНЬ быстр. Настольный пинг-понг 200M + TPS, шина событий 10M-20M + TPS, RPC-вызовы 500K TPS через WebSocket / JSON и т. Д. Для повышения скорости необходимо проделать дополнительную работу, но теперь это достаточно быстро, когда я больше работаю с удобством использования.

Статьи по Теме:

  • [Подробное руководство] Пример микросервиса QBit
  • [Doc] обратные вызовы очереди для служб на основе очереди QBit
  • [Быстрый старт] Создание простого веб-сервера микросервиса Rest с помощью QBit
  • [Быстрый старт] Создание клиента веб-микросервиса TODO с QBit
  • [Быстрый старт] Создание сервера веб-микросервисов TODO с QBit
  • [Быстрый старт] Создание блага для микросервисного движка QBit
  • [Быстрый старт] Сборка QBit библиотеки microservice для Java
  • [Черновая обработка] Поставка одностраничных приложений из QBit Java JSON Microservice lib
  • [Rough Cut] Работа с шиной событий для QBit микросервисного движка
  • [Черновая обработка] Работа с inproc MicroServices
  • [Rough Cut] Работа с частной шиной событий для микросервисов inproc
  • [Rough Cut] Работа со строго типизированными прокси шины событий для QBit Java Microservice lib
  • [Черновая обработка] Работа с системным менеджером для QBit Mircoservice lib
  • [Z Notebook] Больше внутренних тестов
  • [Z Notebook] Тестирование производительности для REST
  • [Z Notebook] Дорожная карта
  • Дом
  • Введение в QBit
  • Локальные сервисные прокси
  • QBit Boon Новая волна JSON HTTP и Websocket
  • QBit Docs