AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Hallo Habr-lezers! In het vorige artikel hadden we het over een eenvoudige manier voor noodherstel in AERODISK ENGINE-opslagsystemen: replicatie. In dit artikel zullen we ingaan op een complexer en interessanter onderwerp: de metrocluster, dat wil zeggen een middel voor geautomatiseerde rampenbescherming voor twee datacenters, waardoor datacenters in actief-actief-modus kunnen werken. Wij vertellen het u, laten het u zien, breken het en repareren het.

Zoals gewoonlijk eerst de theorie

Een metrocluster is een cluster verspreid over meerdere locaties binnen een stad of regio. Het woord ‘cluster’ geeft ons duidelijk aan dat het complex geautomatiseerd is, dat wil zeggen dat het wisselen van clusterknooppunten in geval van storingen automatisch plaatsvindt.

Dit is waar het belangrijkste verschil tussen een metrocluster en reguliere replicatie ligt. Automatisering van operaties. Dat wil zeggen dat bij bepaalde incidenten (datacenterstoring, kapotte kanalen, etc.) het opslagsysteem zelfstandig de nodige acties zal ondernemen om de beschikbaarheid van data op peil te houden. Bij gebruik van reguliere replica’s worden deze handelingen geheel of gedeeltelijk handmatig uitgevoerd door de beheerder.

Wat is het voor?

Het belangrijkste doel dat klanten nastreven bij het gebruik van bepaalde metroclusterimplementaties is het minimaliseren van RTO (Recovery Time Objective). Dat wil zeggen: het minimaliseren van de hersteltijd van IT-diensten na een storing. Als u reguliere replicatie gebruikt, zal de hersteltijd altijd langer zijn dan de hersteltijd bij een metrocluster. Waarom? Erg makkelijk. De beheerder moet achter zijn bureau zitten en de replicatie handmatig overschakelen, en het metrocluster doet dit automatisch.

Als u geen toegewijde beheerder van dienst heeft die niet slaapt, niet eet, niet rookt of ziek wordt en 24 uur per dag de status van het opslagsysteem in de gaten houdt, dan is er geen manier om te garanderen dat de beheerder dat ook zal doen beschikbaar zijn voor handmatig schakelen tijdens een storing.

Dienovereenkomstig zal de RTO bij afwezigheid van een metrocluster of een onsterfelijke beheerder van het 99e niveau van de beheerdersdienst gelijk zijn aan de som van de schakeltijd van alle systemen en de maximale tijdsperiode waarna de beheerder gegarandeerd gaat werken met opslagsystemen en aanverwante systemen.

We komen dus tot de voor de hand liggende conclusie dat het metrocluster moet worden gebruikt als de RTO-vereiste minuten bedraagt, en niet uren of dagen. Dat wil zeggen dat in het geval van de ergste datacenterstoring de IT-afdeling de business tijd moet geven om de toegang tot IT-diensten binnen enkele minuten of zelfs seconden te herstellen.

Hoe werkt het?

Op het lagere niveau gebruikt de metrocluster een mechanisme voor synchrone gegevensreplicatie, dat we in het vorige artikel hebben beschreven (zie. link). Omdat replicatie synchroon is, zijn de vereisten daarvoor overeenkomstig, of beter gezegd:

  • optische vezel als natuurkunde, 10 gigabit Ethernet (of hoger);
  • de afstand tussen datacenters bedraagt ​​maximaal 40 kilometer;
  • De optische kanaalvertraging tussen datacenters (tussen opslagsystemen) bedraagt ​​maximaal 5 milliseconden (optimaal 2).

Al deze vereisten zijn van adviserende aard, dat wil zeggen dat het metrocluster zal werken, zelfs als niet aan deze vereisten wordt voldaan, maar we moeten begrijpen dat de gevolgen van het niet naleven van deze vereisten gelijk zijn aan een vertraging in de werking van beide opslagsystemen in het metrocluster.

Een synchrone replica wordt dus gebruikt om gegevens tussen opslagsystemen over te dragen, en hoe schakelen replica's automatisch en, belangrijker nog, hoe kunnen we split-brain vermijden? Om dit te doen, wordt op een hoger niveau een extra entiteit gebruikt: een arbiter.

Hoe werkt een arbiter en wat is zijn taak?

De arbiter is een kleine virtuele machine of een hardwarecluster die op een derde locatie (bijvoorbeeld in een kantoor) moet worden gelanceerd en via ICMP en SSH toegang moet bieden tot het opslagsysteem. Na de lancering moet de arbiter het IP-adres instellen en vervolgens vanaf de opslagzijde het adres opgeven, plus de adressen van afstandsbedieningen die deelnemen aan de metrocluster. Hierna is de scheidsrechter klaar om aan het werk te gaan.

De arbiter houdt voortdurend toezicht op alle opslagsystemen in de metrocluster en als een bepaald opslagsysteem niet beschikbaar is, besluit hij, nadat hij de onbeschikbaarheid van een ander lid van het cluster (een van de “live” opslagsystemen) heeft bevestigd, de procedure voor het wisselen van replicatieregels te starten. en in kaart brengen.

Een heel belangrijk punt. De arbiter moet zich altijd op een andere locatie bevinden dan die waarop de opslagsystemen zich bevinden, dat wil zeggen niet in datacentrum 1, waar opslagsysteem 1 is geïnstalleerd, noch in datacentrum 2, waar opslagsysteem 2 is geïnstalleerd.

Waarom? Omdat dit de enige manier is waarop een arbiter, met behulp van een van de overgebleven opslagsystemen, ondubbelzinnig en nauwkeurig de val kan vaststellen van een van de twee locaties waar de opslagsystemen zijn geïnstalleerd. Elke andere methode om een ​​arbiter te plaatsen kan resulteren in een gespleten brein.

Laten we nu eens kijken naar de details van het werk van de arbiter.

De arbiter voert verschillende services uit die voortdurend alle opslagcontrollers ondervragen. Als het resultaat van de peiling afwijkt van het vorige (beschikbaar/niet beschikbaar), wordt het vastgelegd in een kleine database, die ook op de arbiter werkt.

Laten we de logica van het werk van de arbiter in meer detail bekijken.

Stap 1: Bepaal de onbeschikbaarheid. Een storing in het opslagsysteem is de afwezigheid van ping van beide controllers van hetzelfde opslagsysteem binnen 5 seconden.

Stap 2. Start de schakelprocedure. Nadat de arbiter zich heeft gerealiseerd dat een van de opslagsystemen niet beschikbaar is, stuurt hij een verzoek naar het “live” opslagsysteem om er zeker van te zijn dat het “dode” opslagsysteem ook echt dood is.

Na ontvangst van een dergelijk commando van de arbiter, controleert het tweede (live) opslagsysteem bovendien de beschikbaarheid van het gevallen eerste opslagsysteem en stuurt, als dit er niet is, een bevestiging naar de arbiter van zijn gok. Het opslagsysteem is inderdaad niet beschikbaar.

Na ontvangst van een dergelijke bevestiging start de arbiter een procedure op afstand voor het overschakelen van replicatie en het verhogen van mapping op de replica's die actief waren (primair) op het gevallen opslagsysteem, en stuurt een opdracht naar het tweede opslagsysteem om deze replica's te wijzigen van secundair naar primair en het in kaart brengen verhogen. Welnu, het tweede opslagsysteem voert deze procedures dienovereenkomstig uit en biedt vervolgens vanuit zichzelf toegang tot de verloren LUN's.

Waarom is aanvullende verificatie nodig? Voor quorum. Dat wil zeggen dat een meerderheid van het totale oneven (3) aantal clusterleden de val van een van de clusterknooppunten moet bevestigen. Alleen dan zal deze beslissing definitief juist zijn. Dit is nodig om foutief schakelen en dus split-brain te voorkomen.

Tijdstap 2 duurt ongeveer 5 - 10 seconden. Rekening houdend met de tijd die nodig is om de onbeschikbaarheid vast te stellen (5 seconden), zullen de LUN's van het omgevallen opslagsysteem binnen 10 - 15 seconden na het ongeval automatisch beschikbaar zijn om met het live-systeem te werken. opslagsysteem.

Het is duidelijk dat, om te voorkomen dat u de verbindingen met hosts verliest, u er ook voor moet zorgen dat u de time-outs op de hosts correct configureert. De aanbevolen time-out bedraagt ​​minimaal 30 seconden. Dit voorkomt dat de host de verbinding met het opslagsysteem verbreekt tijdens het wisselen van belasting in geval van een calamiteit en zorgt ervoor dat er geen I/O-onderbrekingen optreden.

Wacht even, het blijkt dat als alles zo goed is met het metrocluster, waarom hebben we dan überhaupt regelmatige replicatie nodig?

In werkelijkheid is alles niet zo eenvoudig.

Laten we eens kijken naar de voor- en nadelen van het metrocluster

We realiseerden ons dus dat de voor de hand liggende voordelen van de metrocluster vergeleken met conventionele replicatie de volgende zijn:

  • Volledige automatisering, waardoor een minimale hersteltijd wordt gegarandeerd in geval van een calamiteit;
  • Dat is alles :-).

En nu, aandacht, de nadelen:

  • Oplossing kosten. Hoewel het metrocluster in Aerodisk-systemen geen aanvullende licenties vereist (dezelfde licentie wordt gebruikt als voor de replica), zullen de kosten van de oplossing nog steeds hoger zijn dan bij gebruik van synchrone replicatie. U moet alle vereisten voor een synchrone replica implementeren, plus de vereisten voor de metrocluster die verband houdt met extra schakelingen en extra locaties (zie metroclusterplanning);
  • Complexiteit van de oplossing. Het metrocluster is veel complexer dan een reguliere replica en vergt veel meer aandacht en inspanning voor planning, configuratie en documentatie.

Eventueel. Metrocluster is zeker een technologisch zeer geavanceerde en goede oplossing als je echt binnen enkele seconden of minuten RTO moet leveren. Maar als zo'n taak niet bestaat, en RTO in uren oké is voor zaken, dan heeft het geen zin om mussen uit een kanon te schieten. De gebruikelijke replicatie tussen arbeiders en boeren is voldoende, aangezien een metrocluster extra kosten en complicaties van de IT-infrastructuur zal veroorzaken.

Metroclusterplanning

Dit gedeelte pretendeert niet een allesomvattende gids te zijn voor het ontwerpen van metroclusters, maar toont alleen de hoofdrichtingen die moeten worden uitgewerkt als u besluit een dergelijk systeem te bouwen. Zorg er daarom voor dat u bij de daadwerkelijke implementatie van een metrocluster de fabrikant van het opslagsysteem (dat wil zeggen wij) en andere gerelateerde systemen betrekt voor overleg.

locaties

Zoals hierboven aangegeven heeft een metrocluster minimaal drie locaties nodig. Twee datacenters waar opslagsystemen en aanverwante systemen zullen opereren, evenals een derde locatie waar de arbiter zal werken.

De aanbevolen afstand tussen datacenters bedraagt ​​maximaal 40 kilometer. Een grotere afstand zal zeer waarschijnlijk voor extra vertraging zorgen, wat in het geval van een metrocluster uiterst onwenselijk is. Laten we u eraan herinneren dat vertragingen maximaal 5 milliseconden mogen bedragen, hoewel het raadzaam is deze binnen 2 milliseconden te houden.

Het wordt aanbevolen om vertragingen ook tijdens het planningsproces te controleren. Elke min of meer volwassen aanbieder die glasvezel tussen datacenters aanbiedt, kan vrij snel een kwaliteitscontrole organiseren.

Wat betreft vertragingen voor de arbiter (dat wil zeggen tussen de derde site en de eerste twee), is de aanbevolen vertragingsdrempel maximaal 200 milliseconden, dat wil zeggen dat een reguliere zakelijke VPN-verbinding via internet geschikt is.

Switchen en netwerken

In tegenstelling tot het replicatieschema, waarbij het voldoende is om opslagsystemen van verschillende locaties met elkaar te verbinden, vereist het metroclusterschema het verbinden van hosts met beide opslagsystemen op verschillende locaties. Om duidelijker te maken wat het verschil is, worden beide schema’s hieronder weergegeven.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Zoals uit het diagram blijkt, kijken onze hosts van site 1 naar zowel opslagsysteem 1 als opslagsysteem 2. Integendeel, de hosts van site 2 kijken naar zowel opslagsysteem 2 als opslagsysteem 1. Dat wil zeggen dat elke host beide opslagsystemen ziet. Dit is een voorwaarde voor het functioneren van het metrocluster.

Het is uiteraard niet nodig om elke host met een optische kabel op een ander datacenter aan te sluiten; geen enkele poort of kabel is voldoende. Al deze verbindingen moeten tot stand worden gebracht via Ethernet 10G+ of FibreChannel 8G+ switches (FC is alleen voor het verbinden van hosts en opslagsystemen voor IO, het replicatiekanaal is momenteel alleen beschikbaar via IP (Ethernet 10G+).

Nu een paar woorden over de netwerktopologie. Een belangrijk punt is de juiste configuratie van subnetten. Het is noodzakelijk om onmiddellijk verschillende subnetten te definiëren voor de volgende soorten verkeer:

  • Het replicatiesubnet waarover gegevens tussen opslagsystemen worden gesynchroniseerd. Er kunnen er meerdere zijn, in dit geval maakt het niet uit, het hangt allemaal af van de huidige (reeds geïmplementeerde) netwerktopologie. Als er twee zijn, moet er uiteraard routering tussen worden geconfigureerd;
  • Opslagsubnetten waarmee hosts toegang krijgen tot opslagbronnen (als het iSCSI is). Er zou in elk datacenter één zo’n subnet moeten zijn;
  • Beheer subnetten, dat wil zeggen drie routeerbare subnetten op drie locaties van waaruit opslagsystemen worden beheerd, en de scheidsrechter bevindt zich daar ook.

We houden hier geen rekening met subnetten voor toegang tot hostbronnen, omdat deze sterk afhankelijk zijn van de taken.

Het scheiden van verschillend verkeer in verschillende subnetten is uiterst belangrijk (het is vooral belangrijk om de replica te scheiden van de I/O), omdat als je al het verkeer in één “dik” subnet mengt, dit verkeer onmogelijk te beheren zal zijn, en in Door de omstandigheden van twee datacenters kan dit nog steeds verschillende netwerkbotsingsopties veroorzaken. We zullen in het kader van dit artikel niet diep op deze kwestie ingaan, aangezien u kunt lezen over het plannen van een netwerk dat zich uitstrekt tussen datacenters op de bronnen van fabrikanten van netwerkapparatuur, waar dit tot in detail wordt beschreven.

Configuratie van de scheidsrechter

De arbiter moet toegang verlenen tot alle beheerinterfaces van het opslagsysteem via de ICMP- en SSH-protocollen. Denk ook aan de failsafe van de arbiter. Er is hier een nuance.

Arbiter-failover is zeer wenselijk, maar niet vereist. Wat gebeurt er als de scheidsrechter op het verkeerde moment crasht?

  • De werking van het metrocluster in de normale modus zal niet veranderen, omdat arbtir heeft absoluut geen effect op de werking van het metrocluster in de normale modus (het is zijn taak om de belasting tussen datacenters tijdig te schakelen)
  • Bovendien, als de arbiter om de een of andere reden valt en doorslaapt tijdens een ongeval in het datacenter, zal er geen wisseling plaatsvinden, omdat er niemand zal zijn die de noodzakelijke schakelopdrachten kan geven en een quorum kan organiseren. In dit geval verandert het metrocluster in een regulier schema met replicatie, dat tijdens een calamiteit handmatig moet worden omgeschakeld, wat gevolgen heeft voor de RTO.

Wat volgt hieruit? Als u echt een minimale RTO wilt garanderen, moet u ervoor zorgen dat de arbiter fouttolerant is. Hiervoor zijn twee opties:

  • Lanceer een virtuele machine met een arbiter op een fouttolerante hypervisor, gelukkig ondersteunen alle hypervisors voor volwassenen fouttolerantie;
  • Als je op de derde locatie (in een conventioneel kantoor) te lui bent om een ​​normaal cluster te installeren en er is geen bestaand hypervozorcluster, dan hebben we een hardwareversie van de arbiter geleverd, die is gemaakt in een 2U-doos waarin twee gewone x-86-servers werken en die een lokale storing kunnen overleven.

We raden ten zeerste aan om de fouttolerantie van de arbiter te garanderen, ondanks het feit dat het metrocluster deze in de normale modus niet nodig heeft. Maar zoals zowel de theorie als de praktijk laten zien: als je een werkelijk betrouwbare, rampbestendige infrastructuur bouwt, kun je beter op safe spelen. Het is beter om uzelf en uw bedrijf te beschermen tegen de 'wet van gemeenheid', dat wil zeggen tegen het falen van zowel de arbiter als een van de locaties waar het opslagsysteem zich bevindt.

Oplossingsarchitectuur

Rekening houdend met de bovenstaande vereisten, krijgen we de volgende algemene oplossingsarchitectuur.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

LUN's moeten gelijkmatig over twee locaties worden verdeeld om ernstige overbelasting te voorkomen. Tegelijkertijd moet u bij het dimensioneren van beide datacenters niet alleen rekening houden met het dubbele volume (wat nodig is om gegevens tegelijkertijd op twee opslagsystemen op te slaan), maar ook met dubbele prestaties in IOPS en MB/s om degradatie van applicaties in de datacenters te voorkomen. bij een storing van één van de datacenters.

Los daarvan merken we op dat met de juiste benadering van de grootte (dat wil zeggen, op voorwaarde dat we de juiste bovengrenzen van IOPS en MB/s hebben opgegeven, evenals de noodzakelijke CPU- en RAM-bronnen), als een van de opslagsystemen in de metrocluster faalt, zal er geen sprake zijn van een ernstige prestatiedaling onder omstandigheden van tijdelijke werkzaamheden op één opslagsysteem.

Dit wordt verklaard door het feit dat wanneer twee sites tegelijkertijd actief zijn, synchrone replicatie de helft van de schrijfprestaties “opslokt”, aangezien elke transactie naar twee opslagsystemen moet worden geschreven (vergelijkbaar met RAID-1/10). Dus als een van de opslagsystemen uitvalt, verdwijnt de invloed van replicatie tijdelijk (totdat het defecte opslagsysteem herstelt) en krijgen we een tweevoudige toename van de schrijfprestaties. Nadat de LUN's van het defecte opslagsysteem opnieuw zijn opgestart op het werkende opslagsysteem, verdwijnt deze tweevoudige toename als gevolg van het feit dat er belasting verschijnt van de LUN's van het andere opslagsysteem, en keren we terug naar hetzelfde prestatieniveau als vóór de lancering. “vallen”, maar alleen binnen het kader van één site.

Met behulp van een competente dimensionering kunt u omstandigheden garanderen waarin gebruikers helemaal niet het falen van een heel opslagsysteem zullen voelen. Maar we herhalen nogmaals: dit vereist een zeer zorgvuldige maatvoering, waarvoor u overigens gratis contact met ons kunt opnemen :-).

Opzetten van een metrocluster

Het opzetten van een metrocluster lijkt sterk op het opzetten van reguliere replicatie, zoals we hebben beschreven in vorige artikel. Laten we ons daarom alleen concentreren op de verschillen. In het laboratorium hebben we een bank ingericht op basis van bovenstaande architectuur, alleen in een minimale versie: twee opslagsystemen verbonden via 10G Ethernet, twee 10G-switches en één host die door de switches naar beide opslagsystemen met 10G-poorten kijkt. De arbiter draait op een virtuele machine.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Wanneer u virtuele IP's (VIP's) voor een replica configureert, moet u het VIP-type selecteren: voor metrocluster.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

We hebben twee replicatielinks gemaakt voor twee LUN's en deze over twee opslagsystemen verdeeld: LUN TEST Primary op opslagsysteem 1 (METRO-link), LUN TEST2 Primary voor opslagsysteem 2 (METRO2-link).

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Voor hen hebben we twee identieke doelen geconfigureerd (in ons geval is iSCSI, maar FC wordt ook ondersteund, de installatielogica is hetzelfde).

Opbergsysteem1:

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Opbergsysteem2:

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Voor replicatieverbindingen zijn op elk opslagsysteem mappings gemaakt.

Opbergsysteem1:

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Opbergsysteem2:

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

We hebben Multipath opgezet en aan de host gepresenteerd.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Het instellen van een arbiter

U hoeft niets speciaals te doen met de arbiter zelf; u hoeft hem alleen maar in te schakelen op de derde site, hem een ​​IP te geven en de toegang daartoe te configureren via ICMP en SSH. De installatie zelf wordt uitgevoerd vanuit de opslagsystemen zelf. In dit geval is het voldoende om de arbiter één keer te configureren op een van de opslagcontrollers in het metrocluster; deze instellingen worden automatisch naar alle controllers gedistribueerd.

In de sectie Replicatie op afstand >> Metrocluster (op elke controller) >> de knop “Configureren”.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

We voeren het IP-adres van de arbiter in, evenals de besturingsinterfaces van twee externe opslagcontrollers.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Hierna moet u alle services inschakelen (de knop "Alles opnieuw opstarten"). Als de services in de toekomst opnieuw worden geconfigureerd, moeten ze opnieuw worden gestart om de instellingen van kracht te laten worden.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

We controleren of alle services actief zijn.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Hiermee is de configuratie van het metrocluster voltooid.

Crashtest

De crashtest zal in ons geval vrij eenvoudig en snel zijn, aangezien de replicatiefunctionaliteit (switching, consistentie, enz.) werd besproken in laatste artikel. Om de betrouwbaarheid van het metrocluster te testen, volstaat het daarom om de automatisering van foutdetectie, schakelen en de afwezigheid van opnameverliezen (I/O-stops) te controleren.

Om dit te doen emuleren we een volledige storing van een van de opslagsystemen door beide controllers fysiek uit te schakelen, nadat we eerst zijn begonnen met het kopiëren van een groot bestand naar de LUN, die op het andere opslagsysteem moet worden geactiveerd.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Schakel één opslagsysteem uit. Op het tweede opslagsysteem zien we in de logs waarschuwingen en berichten dat de verbinding met het naburige systeem is verbroken. Als meldingen via SMTP- of SNMP-monitoring zijn geconfigureerd, ontvangt de beheerder overeenkomstige meldingen.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

Precies 10 seconden later (zichtbaar in beide schermafbeeldingen) werd de METRO-replicatieverbinding (degene die primair was op het defecte opslagsysteem) automatisch primair op het werkende opslagsysteem. Met behulp van de bestaande mapping bleef LUN TEST beschikbaar voor de host, de opname daalde iets (binnen de beloofde 10 procent), maar werd niet onderbroken.

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

AERODISK-motor: Rampbestendig. Deel 2. Metrocluster

De test is succesvol afgerond.

Samenvattend

De huidige implementatie van de metrocluster in AERODISK Engine N-serie opslagsystemen maakt het volledig mogelijk om problemen op te lossen waarbij het nodig is om de downtime voor IT-diensten te elimineren of te minimaliseren en de werking ervan 24/7/365 te garanderen met minimale arbeidskosten.

We kunnen natuurlijk zeggen dat dit allemaal theorie is, ideale laboratoriumomstandigheden, enzovoort... MAAR we hebben een aantal geïmplementeerde projecten waarin we functionaliteit voor rampenbestendigheid hebben geïmplementeerd, en de systemen werken perfect. Een van onze redelijk bekende klanten, die slechts twee opslagsystemen in een rampbestendige configuratie gebruikt, heeft al ingestemd met het publiceren van informatie over het project, dus in het volgende deel zullen we het hebben over de gevechtsimplementatie.

Bedankt, we kijken uit naar een productieve discussie.

Bron: www.habr.com

Voeg een reactie