.Net mikrozerbitzuen ingurune batean saioa egitea praktikan

.Net mikrozerbitzuen ingurune batean saioa egitea praktikan

Erregistroa funtsezko tresna da garatzaileentzat, baina sistema banatuak eraikitzerakoan, aplikazioaren oinarrian bertan jarri behar den oinarrizko elementu bihurtzen da, bestela mikrozerbitzuen garapenaren konplexutasuna azkar agerian geratuko da.

.Net Core 3-k ezaugarri bikaina gehitu du HTTP goiburuetan korrelazio-testuingurua pasatzeko gaitasuna, beraz, zure aplikazioek zerbitzuen arteko komunikaziorako HTTP dei zuzenak erabiltzen badituzte, funtzionalitate hau erabil dezakezu. Hala ere, zure backend arkitekturak mezu-bitartekari baten bidezko komunikazioa behar badu (RabbitMQ, Kafka, etab.), korrelazio-testuinguruaren transferentzia zuk zeuk kudeatu beharko duzu mezu horien bidez.

Artikulu honetan, web API aplikazio sinple bat hartuko dugu eta erregistroak antolatuko ditugu.

  • Mantendu zerbitzu independenteen erregistroen arteko muturretik muturrerako korrelazioa, bezero baten eskaera espezifiko batek eragindako jarduera guztiak erraz ikusi ahal izateko.

  • Sarrera-puntu bakarra izan analisi erosoarekin, "Aplikazioan errore bat jaso dut halako eskaera ID batekin" bezalako galderak jasotzen dituen Laguntza Zerbitzuak ere erregistro-tresna erabil dezan.

Lehenik eta behin, gure aplikaziorako erregistro-hornitzaile bat erabaki behar dugu. Erregistro modernoen funtsezko baldintza egitura da, hau da, objektuekin lan egin behar dugu testu-mezu lauen ordez. Erregistro horiei esker, erraz eraiki ditzakegu gure mezuen irudikapenak dimentsio ezberdinetan eta analisiak egin.

Gure aplikaziorako, Serilog paketea erabiliko dugu, erregistro egituratuetarako euskarri bikaina eta plugin sistema aberatsa dituena. Oinarrizko konfigurazio urratsak saltatuko ditut (gai honi buruzko artikulu ugari aurki ditzakezu) eta suposatuko dut...

  • Seriallog dagoeneko konfiguratuta dago eta zure mendekotasun injekzio hornitzailearen erregistro lehenetsia da.

  • bere konfigurazioak testuinguru-propietateekin mezua aberastea barne hartzen du (Enrich.FromLogContext)

Hurrengo urratsa Serilog-etik mezuak zein erregistro bilketa sistema zentralizatura bidaliko diren aukeratzea da. Gaur egun, kode irekiko aukerarik ohikoena ELK pila da (Elasticsearch, Logstash eta Kibana), beraz, hori erabiliko dugu. Horretarako, honako hauen irtenbide bat erabiliko dugu: Logz.IO — Doako plan batean izena eman ondoren, Lucene bilatzailearen potentzial osoa eskura duzu.

Gure proiektura pakete bat gehitzea besterik ez zaigu geratzen. Serilog.Sinks.Logzio

Install-Package Serilog.Sinks.Logzio

Eta gehitu dagokion enreacherra gure logger konfigurazioari, sarbide-tokena emanez.

LoggerConfiguration loggerConfig = new LoggerConfiguration();
loggerConfig.WriteTo.Logzio(secrets.LogzioToken, 10, TimeSpan.FromSeconds(10), null, LogEventLevel.Debug);

Aplikazioa abiaraziz, gure mezuak ez ditugu kontsolan bakarrik ikusi ahal izango, baita Kibanan ere.

.Net mikrozerbitzuen ingurune batean saioa egitea praktikan

Interfazeak

.Net mikrozerbitzuen ingurune batean saioa egitea praktikan

Zerbitzu motako aplikazio batek bi interfaze nagusi ditu kanpoko munduarekin, bertikala eta horizontala deituko ditugunak. Interfaze bertikala bezero aplikaziotik deiak iristen diren web APIa da. Interfaze horizontala mezu-bitartekaria da, beste barne zerbitzuekin datuak trukatzeko erabiltzen dena.

Ikus ditzagun interfaze hauetan bakoitzean korrelazioa ezartzeko etapak.

HTTP eskaeretan korrelazioa

Ahalik eta informazio gehien lortzeko, korrelazio IDa jardueraren hasieratik ahalik eta gertuen sortu behar dugu, hau da, pasabidean edo zuzenean bezeroan (mugikorra edo weba). Gaur egun backend aplikazio batekin ari garenez, "X-Correlation-ID" goiburu derrigorrezkoa besterik ez dugu beharko web API eskaera guztietan.

Pakete bat gehitzea Korrelazio IDa, zeinaren funtzioa behar dugun goiburutik balioa hartzea den

Install-Package CorrelationID

Gehitu dezagun eskaera prozesatzeko bidera

public class Startup
{
    public void Configure(IApplicationBuilder application)
    {
        application
	    .UseCorrelationId(new CorrelationIdOptions
        {
            Header = "X-Correlation-ID",
            IncludeInResponse = false,
            UpdateTraceIdentifier = false,
            UseGuidForCorrelationId = false
        });
    }
}

Orain, ekintza-iragazki sinple bat sortzeko erabiliko dugu:

public sealed class ApiRequestFilter : ActionFilterAttribute
{
    public ApiRequestFilter(IApiRequestTracker apiRequestTracker, ICorrelationContextAccessor correlationContextAccessor)
    {
        _correlationContextAccessor = correlationContextAccessor ?? throw new ArgumentNullException(nameof(correlationContextAccessor));
    }
    
    private readonly ICorrelationContextAccessor _correlationContextAccessor;
    
    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        if (!Guid.TryParse(_correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
        {
            context.Result = new BadRequestResult();
            return;
        }
    
        await next.Invoke();
    }
    
    public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        await next.Invoke();
    }
}

Eta gehitu dezagun kontrolatzaileari

[Route("[controller]")]
[ApiController]
[ServiceFilter(typeof(ApiRequestFilter))]
public class CarsController : ControllerBase
{

}

Ondorioz, kontrolatzaileak 400 Eskaera okerra emango du dagokion identifikatzailea duen goibururik gabeko eskaera guztientzat.

Bezeroarengandik identifikatzaile bat jasotzen hasi ondoren, erregistro-testuinguruari gehitu behar diogu. Horretarako marko-geruza bat sortuko dugu:

public class CorrelationIdContextLogger
{
    public CorrelationIdContextLogger(RequestDelegate next)
    {
        _next = next ?? throw new ArgumentNullException(nameof(next));
    }
    
    readonly RequestDelegate _next;
    
    public async Task InvokeAsync(HttpContext httpContext, ILogger<CorrelationIdContextLogger> logger, ICorrelationContextAccessor correlationContextAccessor)
    {
        if (Guid.TryParse(correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
        {
            using (logger.BeginScopeWith(("CorrelationId", correlationId)))
            {
                await _next(context);
            }
        }
        else
        {
            await _next(context);
        }
    }
}

Gure aplikazioan, Microsoft.Extensions.Logging.Abstractions paketeko ILogger estandarra erabiltzen dugu, beraz, balioa luzapen sinple bat erabiliz gehituko diogu.

public static IDisposable BeginScopeWith(this ILogger logger, params (string key, object value)[] keys)
{
    return logger.BeginScope(keys.ToDictionary(x => x.key, x => x.value));
}

Eskaerak prozesatzeko hodiari geruza bat gehitzen diogu eta nahi den emaitza lortzen dugu.

public class Startup
{
    public void Configure(IApplicationBuilder application)
    {
        application.UseMiddleware<CorrelationIdContextLogger>();
    }
}

Orain, gure web APIra egindako eskaerek sortutako jarduera guztiek korrelazio identifikatzaile bat dute, eta horren bidez erraz lotu daitezke.

.Net mikrozerbitzuen ingurune batean saioa egitea praktikan

Korrelazioa bitartekarien mezuetan

Hurrengo urratsa korrelazio-identifikatzailearen transmisioa eta harrera konfiguratzea da mezu-bitartekariaren bidez. Gure adibidean, RabbitMQ eta MassTransit framework-a erabiliko ditugu bezero gisa. Berriz ere, MassTransit-en hasierako konfigurazioa saltatuko dugu eta zuzenean erregistroetara pasako gara.

Hasteko, MassTransit-en beraren erregistroak gaitu ditzakegu, horretarako pakete bat gehituko diogu gure aplikazioari MassTransit.SerilogIntegrazioa

Install-Package MassTransit.SerilogIntegration

Orain, erregistratzailea MassTransit ezarpenetara gehitu ondoren, markoaren erregistroak ikusi ahal izango ditugu.

services
    .AddSingleton(provider =>
        {
            return Bus.Factory.CreateUsingRabbitMq(cfg =>
            {
                cfg.UseSerilog();
            });
        });

Demagun gure aplikazioak "done" balioa duen SomethingDoneMessage gertaera bat bidaltzen duela POST eskaera bati erantzunez. Mezu horren kontratua honela deskriba daiteke:

namespace MbMessages
{
    public interface ISomethingDoneMessageV1
    {
        string Value { get; }
    }
}

MassTransit mezuak funtsean bitartekarien mezuak dituzten gutun-azalak dira. Gutun-azalak honelako zerbait dirudi:

{
  "messageId": "59020000-5dba-0015-10b8-08d77ec28593",
  "requestId": "59020000-5dba-0015-5674-08d77ec28592",
  "conversationId": "59020000-5dba-0015-bca8-08d77ec28594",
  "destinationAddress": "rabbitmq://bear.rmq.cloudamqp.com/aelzlsta/ya.servicetemplate.receiveendpoint",
  "headers": {},
  "messageType": [
    "urn:message:MbMessages:ISomethingDoneMessageV1"
  ],
  "message": {
    "value": "done"
  }
}

Mezuak esparruak berak behar dituen zerbitzu-eremuak erakusten ditu, baina gure propietate gehigarriak ere gehi ditzakegu gutun-azal honi. Gainera, MassTransit-ek tresna integratuak ditu aukerako eremu batzuk kudeatzeko, eta horien artean interesgarriena CorrelationId da.

Gehitu dezagun CorrelatedBy interfazea mezu-kontratuari:

namespace MbMessages
{
    public interface ISomethingDoneMessageV1 : CorrelatedBy<Guid>
    {
        string Value { get; }
    }
}

Ea inplementatzen dugun eta balio bat esleitzen diogu CorrelationId propietateari mezu bat sortzerakoan:

internal class SomethingDoneMessageV1 : ISomethingDoneMessageV1
{
    internal SomethingDoneMessageV1(Guid correlationId, string value)
    {
        CorrelationId = correlationId;
        Value = value;
    }
    
    public Guid CorrelationId { get; private set; }
    public string Value { get; private set; }
}

Mezu eguneratua aztertzen badugu, ikusiko dugu korrelazio-identifikatzailea ez dela orain gure mezuaren parte bakarrik, gutun-azalaren parte ere badela; identifikatzaile hau MassTransit-eko erregistro guztietan ere erabiliko da orain, eta horrek esan nahi du askoz errazagoa izango zaigula mezu-bitartekari mailan dauden arazoak konpontzea.

{
  "messageId": "59020000-5dba-0015-10b8-08d77ec28593",
  "requestId": "59020000-5dba-0015-5674-08d77ec28592",
  "conversationId": "59020000-5dba-0015-bca8-08d77ec28594",
  "correlationId": "c7ff562a-b639-415b-9add-c9e524a727cc",
  "destinationAddress": "rabbitmq://bear.rmq.cloudamqp.com/aelzlsta/ya.servicetemplate.receiveendpoint",
  "headers": {},
  "messageType": [
    "urn:message:MbMessages:ISomethingDoneMessageV1"
  ],
  "message": {
    "correlationId": "c7ff562a-b639-415b-9add-c9e524a727cc",
    "value": "Hello"
  }
}

Mezuaren zerbitzu-propietate hauen erregistroa konfiguratu behar dugu oraindik. Horretarako, pakete bat gehituko diogu proiektuari. Serilog.Enrichers.MassTransitMessagePaketeak iragazki bat gehitzen dio MassTransit mezuen prozesatzeko hodiari, mezuaren testuingurua hari-seguruko pila batean kokatzen duena. SerialLog-ek testuingurua pilatik irakurtzen du eta propietate gehigarri horiek gehitzen dizkie gure erregistro-objektuei.

Install-Package Serilog.Enrichers.MassTransitMessage

Txertatu iragazki bat MassTransit-en

services
    .AddSingleton(provider =>
        {
            return Bus.Factory.CreateUsingRabbitMq(cfg =>
            {
                cfg.UseSerilog();
                cfg.UseSerilogMessagePropertiesEnricher();
            });
        });

Eta Serilog konfigurazioan Enricher gehitzen dugu

Log.Logger = new LoggerConfiguration()
    .Enrich.FromMassTransitMessage()
    .CreateLogger();

RabbitMQ ilara batetik mezu bat jasotzen duen aplikazioak MassTransit gutun-azalaren propietate guztietarako sarbidea duenez, ondoriozko korrelazio identifikatzailea erabil dezakegu kontsumitzen duen aplikazioaren barruan eta dei-katean behera ere pasa dezakegu.

Ondorioz, gure erregistroek CorrelationId edukitzen hasi ziren, ez bakarrik zerbitzu bakar batean, baita beste aplikazio batzuekin elkarreraginean ere.

.Net mikrozerbitzuen ingurune batean saioa egitea praktikan

Beraz, .Net aplikazioetarako sortutako erregistro-sistemak mikrozerbitzu guztiz desberdinetako erregistroak erraz korrelazionatzeko aukera ematen digu, baita mezu-bitartekari baten bidez exekutatzen direnenak ere. Eta Elasticsearch-ekin, erregistroak azkar eta erraz azter ditzakegu Kibana-n beharrezko aginte-panelak eraikiz (adibide bat erakusten da argitalpenari erantsitako irudian).

Noski, formulario honetan saioa hasteak ez ditu zure zerbitzuen eta kanpoko hainbat sistemaren arteko elkarrekintza konplexuak estaliko, baina proiektu baten garapenaren hasieran ordena mota hau ezartzea askotan eskertuko diozun gauzetako bat da.

Proiektuan sistemaren iturburu-kodea azter dezakezu: github.com/a-postx/YA.ServiceTemplate

Iturria: www.habr.com

Erosi hosting fidagarria DDoS babesa duten guneetarako, VPS VDS zerbitzariak 🔥 Erosi webguneentzako ostatu fidagarria DDoS babesarekin, VPS VDS zerbitzariak | ProHoster