Piekiełko mikroserwisów
Mikroserwisy to kolejny buzzword, który dotknął IT. Kilka dużych firm, jak Netflix, opisało, jak mikroserwisy stały się rozwiązaniem ich problemów. A my rzuciliśmy się, by wdrażać je do naszych systemów.
Zapomnieliśmy tylko, że mikroserwisy są narzędziem. Narzędziem, które powinno rozwiązywać konkretne problemy. A większość naszych systemów nie ma takich problemów z wydajnością jak Netflix.
Mikroserwisy wiążą się także z wysokim progiem wiedzy, który musi mieć zespół. I nie chodzi mi o wiedzę stricte techniczną, bo mikroserwisy w warstwie technologicznej są dość proste, aż za proste. Problemem jest wiedza domenowa. Trzeba posiadać dogłębną wiedzę o modelowanym systemie, by potrafić zidentyfikować zależności między rozdzielanymi kontekstami.
Wymagania
W artykule Microservice Prerequisites możemy przeczytać o wymaganiach, które stawia Martin Fowler. Są to:
- monitoring wszystkiego, co się da;
- automatyzacja:
- wdrożenia i jego wycofywania,
- tworzenia i likwidowania instancji mikroserwisu.
Dodałbym jeszcze znajomość DDD i domeny przez osoby odpowiedzialne za identyfikację i definiowanie mikroserwisów.
Problemy
Ja w swojej przygodzie z mikroserwisami napotkałem kilka problemów. Główną przyczyną problemów, na które natrafiliśmy jako zespół, był wymóg uzupełniania żądania o dane spoza kontekstu danego mikroserwisu. Efektem tego była duża liczba żądań między mikroserwisami. To powodowało problemem z identyfikacją żądań będących efektem jednej akcji użytkownika. Szczególnie uciążliwe stało się to, gdy zaczęliśmy mieć problemy z wydajnością spowodowane zaimplementowaniem problemu 1 + N.
Rozwiązania
Dzięki zastosowaniu agregatora logów (Kibana) mieliśmy wszystkie logi, zarówno z serwera, jak i z aplikacji, zebrane w jednym miejscu. Problemem było zidentyfikowanie, które wpisy pochodzą z diagnozowanego żądania. Dlatego na poziomie serwera zaczęliśmy dodawać do nagłówka HTTP dodatkowy identyfikator w postaci wygenerowanego losowo ciągu znaków.
Oczywiście taki znacznik to za mało. Zbudowaliśmy system przekazywania tego znacznika do logów i kolejnych podżądań. W efekcie udało się przypisać wszystkie logi do oryginalnego żądania.
Dzięki temu mogliśmy efektywnie wyszukiwać żądania generujące duże liczby podżądań, a nawet duże liczby zapytań do baz danych.
Trochę kodu
Middleware zgodny z PSR-15:
class RequestIdMiddleware implements \Psr\Http\Server\MiddlewareInterface
{
/**
* @var \Psr\Container\ContainerInterface
*/
private $container;
public function __construct(Psr\Container\ContainerInterface $container)
{
$this->container = $container;
}
public function process(
\Psr\Http\Message\ServerRequestInterface $request,
\Psr\Http\Server\RequestHandlerInterface $handler
): \Psr\Http\Message\ResponseInterface {
$requestIds = $request->getHeader('request_id');
if (empty($requestIds)) {
$requestId = uniqid();
} else {
$requestId = current($requestIds);
}
$this->container->setParameter('request_id', $requestId);
return $handler->handle($request);
}
}
Klasa dla monologa
class RequestIdProcessor
{
/**
* @var string
*/
private $requestId;
public function __construct(string $requestId)
{
$this->requestId = $requestId;
}
public function __invoke(array $record)
{
$record['extra']['request_id'] = $this->requestId;
return $record;
}
}
Categories: php