Примус до асинхронності в Java сервісах для Baratine

Baratine сервер для мікро-сервісів — одна з найбільш незвичайних платформ над якою мені довелося працювати. В основі дизайну цього сервера лежать кілька доповнюючих один одного принципів.
  • Асинхронні сервіс інтерфейси
  • Виконання викликів сервісу в єдиному потоці
  • Неразделенное володіння даними
  • Асинхронний Web
  • Асинхронна платформа виконання сервісів

    Асинхронні сервіс інтерфейси
Мікро-сервіси Baratine описуються інтерфейсами. Інтерфейс визначає операції, що надаються сервісом. Особливістю асинхронного інтерфейсу є те, що методи інтерфейсу повертають результат асинхронно, подібно об'єкту Future.
Наприклад звичний інтерфейс для операції оплати кредитною карткою може виглядати наступним чином:
public interface CreditService {
PaymentStatus pay(int amount, CreditCard card); 
}

Такий метод повертає результат за фактом проведення оплати, а код використовує його, виглядає наступним чином:
CreditService _creditService;

PaymentStatus executePayment(int amount, Client client) {
return _creditService.pay(amount, client.getCreditCard()); 
}

Асинхронний інтерфейс не повертає результат, а заповнює Future–об'єкт асинхронно:
public interface CreditService {
void pay(int amount, CreditCard card, Result<PaymentStatus> result);
}

Користувальницький код для такого інтерфейсу може виглядати наступним чином:
CreditService _creditService;

void executePayment(int amount, Client client, Result<PaymentStatus> result) {
return _creditService.pay(amount, client.getCreditCard(), result.then()); 
}

Особливістю цього клієнтського коду є те, що код передає свій Future-об'єкт в кінцевий сервіс Payment з допомогою result.then().
У тих випадках, коли клієнту потрібно додатково обробити результат можна використовувати лямбду, яка буде викликана щодо заповнення результату:
void executePayment(int amount, Client client, Result<PaymentStatus> result)
{
_creditService.pay(amount,
client.getCreditCard(),
result.then(
status -> {
log(status);
return status;
}
));
}

На перший погляд асинхронні інтерфейси можуть здатися не зовсім зручними, але така організація коду дозволяє швидко вивільняти потоки для виконання наступних завдань, а клієнти отримують результати по їх готовності.
Виконання викликів сервісу в єдиному потоці
Мікро-сервіси Baratine виконуються в одному, виділеному цього сервісу, потоці. Потік виділяється сервісу відразу по появі викликів. У загальному випадку виклики до сервісу йдуть від безлічі клієнтів. Виклики поміщаються в чергу і виконуються послідовно одним виділеним потоком.
У цьому контексті слід зазначити, що сервіси повинні бути написані таким чином, щоб не займати потік очікуванням виконання операцій. Для цього використовуються Future–об'єкти типу io.baratine.service.Result (див. вище). Саме вони дозволяють перенести обробку результату виклику дорогих блокувальних операцій в майбутнє.
Наприклад, оплата з використанням чекового рахунку може зайняти кілька годин, а користувальницький код ініціації оплати буде виконаний в реальному часі за мілісекунди.
CheckingService _checkingService = ...;

void executePayment(int amount, Client client, Result<PaymentStatus> result) 
{
_checkingPayment.pay(amount,
client.getCheckingAccInfo(),
result.then(
status-> {
log(status);
if (status.isAppoved()) {
shipGoods();
} else {
handleFailedPayment(status);
}
}
));
);
}

У наведеному вище коді виконання лямбды виклику then() буде відкладено до повернення _checkingService'ом результату оплати, a метод executePayment() моментально стає доступним для наступного виклику.
Виконання в єдиному потоці позитивно позначається на продуктивності через скорочення числа зміни контекстів і гарне узгодження з процесорним кешем.
Неразделенное володіння даними
Володіння правами запису на майстер-копію — одна з відмінних особливостей архітектури мікро-сервісів на Baratine. Так як мікро-сервіс обробляє виклики послідовно, а не паралельно, дані можуть зберігатися в пам'яті одиничного примірника (singleton) сервісу і завжди є останньою, найбільш актуальною копією даних.
(В даному випадку використання слова "копія" не зовсім доречно і використовується идиоматично).
Мікро-сервіс з даними має розширений життєвий цикл, в якому, перш ніж сервіс надійде у використання, Baratine виконає метод сервісу з анотацією @OnLoad або завантажить поля примірника з асинхронної об'єктної бази даних (Kraken) є частиною Baratine.
Мікро-сервіс підкріплений даними може представляти користувача системи наступним чином:
@Asset
public class User
{
@Id
private IdAsset _id;

private UserData _data;
}

У наведеному вище коді примірник UserData з даними про користувача буде завантажений з Kraken.
Асинхронний Web
Для досягнення швидкодії і кращого сполучення з асинхронними сервісами принцип асинхронності підпорядкував собі і виконання Web запитів. Це досягається за допомогою Future–об'єкта для відповіді.
io.baratine.web.RequestWeb, подібно io.baratine.service.Result надає можливість відкласти заповнення відповіді до тих пір, поки не будуть готові дані для відповіді.
наприклад, код запит по протоколу REST може виглядати наступним чином:
@Service
public class QuoteRestService
{
QuoteService _quotes;

@Get
public void quote(@Query("symbol") String symbol, RequestWeb requestWeb)
{
_quotes.quote(symbol, requestWeb.then(quote -> quote));
}
}

У наведеному вище коді метод quote() позначений анотацією Get і це робить метод доступним для Web запитів. У Baratine платформі єдиний примірник сервісу відповідає на всі отримані запити в одному, відведеному для цього сервісу, потоці. У такій архітектурі продуктивність досягається швидким поверненням з методу quote() з допомогою делегування операції за запитом конкретної quote сервісу відповідає за Quotes — QuoteService.
Асинхронна платформа виконання сервісів
У процесі роботи над платформою сама собою стала викристалізовуватися тенденція поширення асинхронності на компоненти платформи. Таким чином всі вбудовані сервіси надаються платформою є асинхронними.
Так в результаті розробки системи з'явилися сервіси бази даних (Kraken), Scheduling, Events, Pipe, Web; і всі вони полагодили правилом тяжіння до асинхронності.
Як одного з розробників цієї системи мені було б дуже цікаво дізнатися думку хабра-спільноти про Baratine.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.