Selles artiklis rÀÀgime, kuidas ja miks me selle vĂ€lja töötasime â mehhanism, mis edastab teavet kliendirakenduste ja 1C:EttevĂ”tte serverite vahel â ĂŒlesande mÀÀratlemisest arhitektuuri ja rakendamise ĂŒksikasjade mĂ”tlemiseni.
Koostöö sĂŒsteem (edaspidi â KS) on hajutatud tĂ”rke- ja koormustaluv sĂŒsteem sĂ”numite vahetamiseks, millele on tagatud kohaletoimetamine. KS on kujundatud kui suure koormusega teenus, millel on kĂ”rge skaleeritavus, ja see on saadaval nii veebiteenusena (mida pakub ettevĂ”te 1C) kui ka seeriatootena, mida saab rakendada oma serverivĂ”imsusel.
KS kasutab hajutatud salvestusruumi ja otsingusĂŒsteemi . Samuti rÀÀgime Java'st ja sellest, kuidas me PostgreSQL-i horisontaalselt skaleerime.
Ălesande seadmine
Et aru saada, miks me Koostöö sĂŒsteemi lĂ”ime, rÀÀgin natuke sellest, kuidas 1C-s Ă€rrakenduste arendamine toimub.
Alustuseks â natuke meie kohta neile, kes veel ei tea, millega me tegeleme :) Me arendame tehnoloogilist platvormi â1C:EttevĂ”teâ. Platvorm sisaldab Ă€rrakenduste arendamise vahendit ning runtime'i, mis vĂ”imaldab Ă€rrakendustel töötada mitmesugustes keskkondades.
Kliendiserveri arendusparadigma
Ărrakendused, mis on loodud â1C:EttevĂ”ttesâ, töötavad kolmetasandilises arhitektuuris âDBMS â rakenduste server â klientâ. Rakenduslik kood, mis on kirjutatud , vĂ”ib töötada rakenduste serveris vĂ”i kliendil. KĂ”ik töö, mis on seotud rakendusobjektide (nĂ€iteks registrid, dokumendid jne), samuti andmebaasi lugemise ja kirjutamisega, toimub ainult serveris. Vormide ja kĂ€suliidese funktsionaalsus on samuti rakendatud serveris. Klient tegeleb vormide saamise, avamise ja kuvamisega, âsuhtlemisegaâ kasutajaga (hoiatused, kĂŒsimused...), vĂ€ikeste arvutustega vormides, mis vajavad kiiret reageerimist (nĂ€iteks hinnaliste koguste korrutamine), kohalike failide töötlemise ja seadme töötlusega.
Rakendusliku koodi protseduuride ja funktsioonide pĂ€istes tuleb selgelt nĂ€idata, kus kood töötab â kasutada direktiive &ĐаĐĐ»ĐžĐ”ĐœŃĐ” / &ĐаХДŃĐČĐ”ŃĐ” (&AtClient / &AtServer ingliskeelses versioonis). 1C arendajad parandavad mind, öeldes, et direktiivid on tegelikult , kuid see pole meile praegu oluline.
Kliendikoodist saab kutsuda serverikoodi, kuid serverikoodist kliendikoodi kutsuda ei saa. See on meie poolt kehtestatud pĂ”hi piirang mitmetel pĂ”hjustel. EelkĂ”ige seetĂ”ttu, et serverikood peab olema kirjutatud nii, et see toimib ĂŒhtviisi, sĂ”ltumata sellest, kust seda kutsutakse - kliendist vĂ”i serverist. Ja juhul, kui serverikoodi kutsutakse teise serverikoodi kaudu, siis klient enam ei eksisteeri. Samuti seetĂ”ttu, et serverikoodi tĂ€itmise ajal vĂ”ib klient, kes selle kutsus, sulgeda, rakendusest vĂ€lja minna ja serveril ei ole enam kedagi, kellele kutsuda.
Kood, mis töötleb nupu vajutamist: serveripĂ€ring kliendist töötab, kuid kliendipĂ€ring serverist â ei.
See tĂ€hendab, et kui me serverist soovime edastada mĂ”ne sĂ”numi kliendirakendusele, nĂ€iteks et "pikaks ajaks" kestnud aruande koostamine on lĂ”ppenud ja aruanne on saadaval â meil pole sellist vĂ”imalust. Peame leidma muid lahendusi, nĂ€iteks kĂŒsima serverilt regulaarselt. Kuid selline lĂ€henemine koormab sĂŒsteemi liigsete pĂ€ringutega ja kokkuvĂ”ttes ei nĂ€e see vĂ€ga elegantne vĂ€lja.
Ja on veel vajadus, nĂ€iteks, kui saabub telefonikĂ”ne, teavitada sellest kliendirakendust, et see leidlikult otsiks helistaja numbrit partnerite andmebaasist ja kuvaks kasutajale teavet helistava partneri kohta. VĂ”i nĂ€iteks teavitada kliendirakendust tellijast, kui laost saabub tellimus. ĂhesĂ”naga, selliseid juhtumeid, kus selline mehhanism oleks abiks, on palju.
Asjaolu sÔnastamine.
Luua sÔnumite vahetamise mehhanism. Kiire, usaldusvÀÀrne, tagatud kohaletoimetamisega, vÔimalusega paindlikult sÔnumeid otsida. Mehhanismi baasil ellu viia sÔnumitooja (sÔnumid, videokÔned), mis töötab 1C rakenduste sees.
Kavandada horisontaalselt skaleeritav sĂŒsteem. Kasvav koormus peab olema kaetud sĂ”lmede arvu suurendamisega.
Rakendamine
Otsustasime, et SV serveri osa ei integreerita otse 1C:Enterprise platvormi, vaid rakendatakse eraldi tootena, mille API-d saab kutsuda 1C rakenduste kodeerimisest. See otsus tehti mitmel pÔhjusel, millest peamine oli soov vÔimaldada sÔnumite vahetamist erinevate 1C rakenduste vahel (nÀiteks Kaupade Halduse ja Raamatupidamise vahel). Erinevad 1C rakendused vÔivad töötada erinevate 1C:Enterprise platvormi versioonidega, asuda erinevatel serveritel jne. Sellistes tingimustes on SV rakendamine eraldiseisva tootena, mis asub 1C installatsioonidest
Nii otsustasime, et teeme SV eraldi tootena. VĂ€ikestele ettevĂ”tetele soovitame kasutada SV serverit, mille oleme paigaldanud oma pilve (wss://1cdialog.com), et vĂ€ltida kohapealse paigalduse ja seadistamisega seotud kulusid. Suuremad kliendid vĂ”ivad aga kaaluda enda SV serveri paigaldamist oma ressurssidele. Sarnast lĂ€henemist oleme kasutanud oma pilve pĂ”hises SaaS tootes. â see vĂ€ljastatakse kui seeriatoode klientide paigalduseks ja samuti on see rakendatud meie pilve .
Rakendus
Koormuse ja tĂ”rketaluvuse jaotamiseks ei paigalda me mitte ĂŒhte, vaid mitut Java-rakendust ning nende ette paigaldame koormuse tasakaalustaja. Kui on vajalik sĂ”numi edastamine node'ilt node'ile â kasutame publish/subscribe funktsiooni Hazelcastis.
Klientide ja serveri vaheline suhtlemine toimub websocketi kaudu. See sobib hĂ€sti reaalajas sĂŒsteemidele.
Jaotatud vahemÀlu
Valisime Redis, Hazelcasti ja Ehcache'i vahel. Aasta on 2015. Redis just kÀivitas uue klastriversiooni (liialt uus, liiga hirmus), Sentinelil on palju piiranguid. Ehcache ei suuda klastrisse kokku minna (see funktsionaalsus ilmus hiljem). Otsustasime proovida Hazelcasti 3.4.
Hazelcast koguneb klastriks "kastist vĂ€lja". Ăhe node'i reĆŸiimis ei ole see kuigi kasulik ja vĂ”ib sobida ainult vahemĂ€luks - see ei oska andmeid kettale salvestada, kui kaotame ainus node'i - kaotame andmed. Me kĂ€sitleme mitut Hazelcast'i, mille vahel varundame kriitilisi andmeid. VahemĂ€lu ei varunda â seda ei ole kahju kaotada.
Meie jaoks on Hazelcast:
- Kasutajasektsioonide salvestamine. Igal korral andmebaasist seanssile minek on aeglane, seetÔttu paneme kÔik seansid Hazelcasti.
- VahemĂ€lu. Otsid kasutaja profiili â kontrolli vahemĂ€lus. Kirjutasid uue sĂ”numi â salvesta vahemĂ€llu.
- Rakenduste instantside suhtlemise teemad. SĂ”lm genereerib sĂŒndmuse ja lisab selle Hazelcasti teema. Teised rakenduse sĂ”lmed, mis on sellel teemal tellitud, saavad ja töötlevad sĂŒndmust.
- Klastri lukustused. NĂ€iteks loome arutelu unikaalse vĂ”tme jĂ€rgi (arutelu-sĂŒntetar, mis on 1C andmebaasis):
conversationKeyChecker.check("BENSIINIAJA");
doInClusterLock("BENSIINIAJA", () -> {
conversationKeyChecker.check("BENSIINIAJA");
createChannel("BENSIINIAJA");
});Kontrollisime, et kanali ei ole. VĂ”tsime lukustuse, kontrollisime uuesti, lĂ”ime kanali. Kui lukustuse vĂ”tmisel ei kontrolli, on vĂ”imalus, et teine thread kontrollis samuti ja proovib luua sama arutelu â aga see juba eksisteerib. Lukustamine synchronized vĂ”i tavalise java Lockiga ei ole vĂ”imalik. Andmebaasi kaudu â aeglane, ja andmebaasi on kahju, Hazelcasti kaudu â see on just see, mida vajame.
Valime andmebaasi
Meil on suur ja edukas kogemus PostgreSQL-i ja selle andmebaasi arendajatega koostöös.
PostgreSQL-i klastri haldamine on keeruline â there are , , , kuid see ei ole pĂ”himĂ”tteliselt noSQL, mis skaleeruvad kohe vĂ€lja. NoSQL-i peamise salvestusena ei kaalutud, sest piisavalt on, et vĂ”tame Hazelcasti, millega pole varem töötatud.
Kui on vaja mÔÔta relatiivset andmebaasi â see tĂ€hendab, . Nagu teate, jagame andmebaasi eraldi osadeks, et igaĂŒks neist saaks viia eraldi serverisse.
Meie shardingâi esimene variant vĂ”imaldas iga meie rakenduse tabeli eraldamise erinevatesse serveritesse erinevates proportsioonides. Palju sĂ”numeid serveris A â tulge, viime osa sellest tabelist serverisse B. Selline lahendus karjus varajase optimeerimise jĂ€rele, seega otsustasime piirduda multi-tenant lĂ€henemisega.
Multi-tenantâi kohta saab lugeda nĂ€iteks veebisaidilt .
SV-s on rakenduse ja tellija mĂ”isted. Rakendus on konkreetne Ă€rirakenduse installatsioon, nĂ€iteks ERP vĂ”i raamatupidamine, koos oma kasutajate ja Ă€riandmetega. Tellija on organisatsioon vĂ”i fĂŒĂŒsiline isik, kelle nimel rakenduse registreerimine SV-serveris toimub. Tellijal vĂ”ib olla registreeritud mitmeid rakendusi, ja need rakendused saavad omavahel teateid vahetada. Tellija on meie sĂŒsteemis nĂŒĂŒd elanik (tenant). Mitme tellija teated vĂ”ivad asuda ĂŒhes fĂŒĂŒsilises andmebaasis; kui me nĂ€eme, et mĂ”ni tellija genereerib palju liiklust, viime ta eraldi fĂŒĂŒsilisse andmebaasi (vĂ”i isegi eraldi DB-serverisse).
Meil on peamine andmebaas, kus hoitakse marsruutimistabelit, mis sisaldab teavet kÔigi tellijate andmebaaside asukoha kohta.
Kuna peamine andmebaas ei tohiks olla kitsas koht, hoiame marsruutimistabelit (ja teisi sageli nÔutavaid andmeid) mÀlus.
Kui tellija andmebaas hakkab pidurdama, jagame selle osadeks. Teistes projektides kasutame suurte tabelite partitsioneerimiseks .
Kuna kasutajate sĂ”numite kaotamine on halb, hoiame oma andmebaase koopiatega. SĂŒnkroonsete ja asĂŒnkroonsete koopiate kombinatsioon vĂ”imaldab end kaitsta peamise andmebaasi kaotuse korral. SĂ”numi kaotus toimub ainult siis, kui peamine andmebaas ja selle sĂŒnkroonne koopia ebaĂ”nnestuvad samal ajal.
Kui sĂŒnkroonne koopia kaob, muutub asĂŒnkroonne koopia sĂŒnkroonseks.
Kui peamine andmebaas kaob, muutub sĂŒnkroonne koopia peamiseks andmebaasiks, asĂŒnkroonne koopia â sĂŒnkroonseks koopiaks.
Elasticsearch otsinguks
Kuna lisaks muule on SV ka sĂ”numivahetus, vajatakse siin kiiret, mugavat ja paindlikku otsingut, arvestades morfoloogiat ja ebatĂ€pset vastavust. Otsustasime mitte ratast leiutada ja kasutame avatud allika otsingusĂŒsteemi Elasticsearch, mis on loodud Lucene raamatukogul. . Elasticsearchi kĂ€itame samuti klustis (master â data â data), et vĂ€ltida probleeme, kui rakenduse sĂ”lmed ebaĂ”nnestuvad.
Githubl leidsime Elasticsearchi jaoks ja kasutame seda. Elasticsearchi indeksis hoiame sÔnade juuri (mida mÀÀratleb plugin) ja N-gramme. Kui kasutaja sisestab otsinguteksti, otsime sisestatud teksti N-grammide hulgast. Indeksisse salvestamisel jaguneb sÔna «tekstid» jÀrgnevateks N-grammideks:
[te, tek, tekst, tekstid, ek, eks, ekst, ekstid, ks, kst, kstid, st, stid, id,],
Samuti salvestatakse sÔna «tekst» juur. Selline lÀhenemine vÔimaldab otsida nii sÔna alguses, keskel kui ka lÔpus.
Ălevaade
Pilt, mille kordame artikli alguses, kuid nĂŒĂŒd koos selgitustega:
- Tasakaalustaja, mis on seatud internetti; meil on â nginx, see vĂ”ib olla mis tahes.
- Java rakenduste instantsid suhtlevad omavahel lÀbi Hazelcasti.
- Veebivoodete haldamiseks kasutame .
- Java rakendus on kirjutatud Java 8 keeles ja koosneb bÀndlitest . Plaanis on migreerida Java 10 peale ja liikuda moodulite juurde.
Arendamine ja testimine
Arendamise ja testimise protsessis kohtasime mitmeid huvitavaid tooteomadusi, mida kasutasime.
Koormustestimine ja mÀlu leke
Iga vÀljaande koormustestimine on koormustestimine. See on edukalt lÀbitud, kui:
- Test töötas mitmeid ööpÀevi ja teeninduses ei olnud katkestusi
- Peamiste toimingute vastuse aeg ei ĂŒletanud mugavat piiri
- Tootlikuse halvenemine vĂ”rreldes eelmisel versiooniga ei ĂŒletanud 10%
Testimisandmebaasi tĂ€idame andmetega â selleks saame tootmisserverilt kĂ”ige aktiivsema abonendi andmed, korrutame tema numbrid 5-ga (sĂ”numite, arutelude, kasutajate arv) ja testime nii.
Teeme sĂŒsteemi koormustestimist kolmes konfiguratsioonis:
- Stressitest
- Ainult ĂŒhendused
- Abonentide registreerimine
Stressitestis kĂ€ivitame mitusada lĂ”ime, mis pidevalt koormavad sĂŒsteemi: saadavad sĂ”numeid, loovad arutelusid, saavad sĂ”numite nimekirja. Simuleerime tavaliste kasutajate (oma lugemata sĂ”numite nimekirja saamine, kellelegi kirjutamine) ja tarkvaralahenduste tegevust (paketi edastamine teise konfiguratsiooni, teate töötlemine).
NĂ€iteks selline on osa stressitestist:
- Kasutaja siseneb sĂŒsteemi
- KĂŒsimus oma lugemata arutelude kohta
- 50% tÔenÀosusega loeb sÔnumeid
- 50% tÔenÀosusega kirjutab sÔnumeid
- Siiski kasutaja:
- Loob uue arutelu 20% tÔenÀosusega
- Valib juhuslikult mÔne oma arutelu
- Siseneb sisse
- KĂŒsimus sĂ”numite, kasutajaprofiilide kohta
- Loob viis sÔnumit, mis on suunatud juhuslikele kasutajatele sellest arutelust
- VĂ€ljub arutelust
- Kordab 20 korda
- Logib vÀlja, naaseb tagasi stsenaariumi algusesse
- SĂŒsteemi siseneb vestlusrobot (emuleerib sĂ”numite vahetust rakenduste koodist)
- Loob 50% tÔenÀosusega uue kanali andmevahetuseks (eriline arutelu)
- Kirjutab 50% tÔenÀosusega sÔnumi mis tahes olemasolevatesse kanalitesse
Stsenaarium âAinult ĂŒhendusedâ ei ilmunud lihtsalt juhuslikult. On olukordi: kasutajad on sĂŒsteemi ĂŒhendatud, kuid pole veel sellesse sisse harjunud. Iga kasutaja kĂ€ivitab hommikul kell 09:00 arvuti, loob ĂŒhenduse serveriga ja vaikib. Need mehed on ohtlikud, neid on palju â paketides on vaid PING/PONG, kuid nad hoidke ĂŒhendust serveriga (nad ei saa mitte hoida â Ă€kki tuleb uus sĂ”num). Test korratakse olukorras, kus kahe tunni jooksul pĂŒĂŒab suure arv kasutajaid sĂŒsteemi autoriseerida. See sarnaneb stressitestiga, kuid keskendub just sellele esimesele sisenemisele â et poleks tĂ”rkeid (inimene ei kasuta sĂŒsteemi, kuid see juba kukub vĂ€lja â raske on vĂ€lja mĂ”elda midagi hullemat).
Tellijate registreerimise stsenaarium algab esimese kĂ€ivitamisega. Me tegime stressitesti ja olime kindlad, et kirjavahetuses sĂŒsteem ei tĂ”rgu. Kuid kasutajad hakkasid tulema ja registreerimine hakkas aeganĂ”udlikult vĂ€lja kukkuma. Registreerimisel kasutasime , mis on seotud sĂŒsteemi entropiaga. Server ei jĂ”udnud koguda piisavalt entropiat ja uue SecureRandom'i pĂ€ringu juures hangus see kĂŒmneteks sekunditeks. Sellest olukorrast on palju vĂ€ljapÀÀse, nĂ€iteks: minna vĂ€hem turvaliselt /dev/urandom'i, paigaldada eraldi plaat, mis genereerib entropiat, genereerida juhuslikke numbreid eelnevalt ja hoida neid basseinides. Me sulgesime probleemi ajutiselt basseiniga, kuid alates sellest ajast teeme eraldi testi uute tellijate registreerimiseks.
Koormuse generaatorina kasutame . Töötada veebisoketiga ei oska, vajame plugina. Esimeste seas otsingutulemustes otsides âjmeter websocketâ tulevad , milles soovitatakse .
Seda me otsustasime alustada.
Peaaegu kohe pÀrast tÔsise testimise alustamist avastasime, et JMeteris on hakanud esinema mÀlulekkeid.
Plugin â see on eraldi suur lugu, 176 tĂ€hte on tal 132 forkâi githubis. Autor ei ole sellesse alates 2015. aastast kommenteerinud (me vĂ”tsime selle 2015. aastal, siis see ei tekitanud kahtlusi), mitmed githubi probleemid mĂ€lulekete osas, 7 lahendamata pull requesti.
Kui otsustate seda pluginit koormustestimiseks kasutada, siis pöörake tÀhelepanu jÀrgmistele aruteludele:
- Mitme lĂ”ime keskkonnas kasutati tavalist LinkedListâi, mille tulemusena saime kĂ€itusaegsel. Probleem lahendatakse kas ĂŒleminekuga ConcurrentLinkedDequeâile vĂ”i sĂŒnkroniseeritud plokkidega. Valisime enda jaoks esimese variandi ().
- MĂ€luleke, ĂŒhenduse katkestamisel ei kustutata ĂŒhenduse teavet ().
- Streaming reĆŸiimis (kui websocket ei suletud lĂ”pliku nĂ€itamises, vaid seda kasutatakse edasi plaanis) ei tööta Response patternâid ().
See on ĂŒks neist, mis on githubis. Mida me tegime:
- VĂ”tsime (@elyrank) â seal on lahendatud probleemid 1 ja 3
- Lahendasime probleemi 2
- Uuendasime jetty 9.2.14 versioonilt 9.3.12-le
- MĂ€hkime SimpleDateFormatâi ThreadLocalâisse; SimpleDateFormat ei ole lĂ”ime ohutu, mis pĂ”hjustas NPE kĂ€itusaegsel
- Selle mĂ€lulekke kĂ”rvaldasime (ĂŒhendus ei olnud katkestatud Ă”igesti)
Ja siiski, see lekib!
MĂ€lu hakkas otsa saama mitte pĂ€evaga, vaid kahega. Aega ei jÀÀnud ĂŒldse, otsustasime kĂ€ivitada vĂ€hem lĂ”ime, kuid neljal agendil. Seda peaks piisama vĂ€hemalt nĂ€dalaks.
Kaks pĂ€eva möödusâŠ
NĂŒĂŒd hakkas Hazelcastâil mĂ€lu otsa saama. Logides oli nĂ€ha, et paar pĂ€eva testimist jĂ€rel hakkab Hazelcast kurtma mĂ€lu puuduse ĂŒle, ja mĂ”ne aja pĂ€rast kaob klaster ja nodid jĂ€tkavad ĂŒksikute hukkumist. Ăhendatud JVisualVM Hazelcastâiga ja nĂ€gime "ĂŒles jĂ”udvat sae" â see kutsus regulaarselt vĂ€lja GC, kuid ei suutnud kuidagi mĂ€lu puhastada.
Selgus, et hazelcast 3.4 versioonis ei vabastata mÀlumaalt tÀielikult: map / multiMap'i kustutamisel (map.destroy())
NĂŒĂŒd on viga parandatud 3.5 versioonis, kuid tol hetkel oli see probleem. Loodime uusi multiMapâe dĂŒnaamiliste nimedega ja kustutasime vastavalt meie loogikale. Kood nĂ€gi vĂ€lja umbes nii:
public void join(Authentication auth, String sub) {
MultiMap sessions = instance.getMultiMap(sub);
sessions.put(auth.getUserId(), auth);
}
public void leave(Authentication auth, String sub) {
MultiMap sessions = instance.getMultiMap(sub);
sessions.remove(auth.getUserId(), auth);
if (sessions.size() == 0) {
sessions.destroy();
}
}Kutsumine:
service.join(auth1, "UUED_SĂNUMID_ARUTEL_UUID1");
service.join(auth2, "UUED_SĂNUMID_ARUTEL_UUID1");multiMap loodi iga tellimuse jaoks ja eemaldati, kui see ei olnud enam vajalik. Otsustasime, et loome Map ning vĂ”ti on tellimuse nimi ja vÀÀrtused on seansi identifikaatorid (mille kaudu saab hiljem vajadusel kasutajate identifikaatoreid kĂ€tte).
public void join(Authentication auth, String sub) {
addValueToMap(sub, auth.getSessionId());
}
public void leave(Authentication auth, String sub) {
removeValueFromMap(sub, auth.getSessionId());
}Graafikud on korrigeeritud.
Mida me veel Ôppisime koormustestimise kohta
- JSR223 tuleb kirjutada groovy's ning lisada koostamise vahemÀlu - see on oluliselt kiirem. .
- Jmeter-Plugins graafikud on lihtsamad mÔista kui standardsed. .
Meie kogemus Hazelcast'iga
Hazelcast oli meile uus toode, alustasime selle kasutamist versiooniga 3.4.1, praegu on meie tootmiserveris versioon 3.9.2 (artikli kirjutamise hetkel on viimane versioon Hazelcast 3.10).
ID genereerimine
Alustasime tĂ€isarvuliste identifikaatoritega. Kujutame ette, et me vajame uut Long uut tĂŒĂŒpi entiteedi jaoks. JĂ€rjekord andmebaasis ei sobi, tabelid osalevad jagamises - tuleb vĂ€lja, et andmebaasis 1 on sĂ”num ID=1 ja andmebaasis 2 on sĂ”num ID=1, Elasticsearch'is sellise ID-ga sa ei saa, Hazelcast'is samuti, aga kĂ”ige hullem on, kui soovid andmed kahest andmebaasist ĂŒheks koos viia (nt kui otsustad, et ĂŒks andmebaas piisab nende tellijate jaoks). Hazelcast'is saab luua mitu AtomicLong'i ja hoida loenduri seal, siis on uue ID saamise efektiivsus - incrementAndGet pluss aeg Hazelcast'isse pĂ€ringu tegemiseks. Kuid Hazelcast'is on midagi veel optimaalsemat - FlakeIdGenerator. Iga kliendi juurde, kui ta pĂ€rib, antakse ID-de vahemik, nĂ€iteks esimesena - 1 kuni 10 000, teise jaoks - 10 001 kuni 20 000 ja nii edasi. NĂŒĂŒd vĂ”ib klient ise uusi identifikaatoreid vĂ€ljastada, kuni tema antud vahemik saab otsa. See töötab kiiresti, kuid rakenduse (ja Hazelcast'i kliendi) taaskĂ€ivitamisel algab uus jĂ€rjestus - sealt tulenevad vaheajaks jÀÀvad ja jne. Lisaks ei ole arendajatele kuigi selge, miks ID-d on tĂ€isarvud, kuid nad on nii korralikult valdavalt segaduses. Me kaalusime kĂ”ik ĂŒle ja lĂ€ksime UUID-dele ĂŒle.
Ăks asi, mis puudutab neid, kes tahavad olla nagu Twitter, on olemas selline teek, nagu Snowcast - see on Snowflake'i rakendus Hazelcast'i peal. Vaadata saab siit:
Aga me pole veel sinna jÔudnud.
TransactionalMap.replace
Veel ĂŒks ĂŒllatus: TransactionalMap.replace ei tööta. Siin on selline test:
@Test
public void replaceInMap_putsAndGetsInsideTransaction() {
hazelcastInstance.executeTransaction(context -> {
HazelcastTransactionContextHolder.setContext(context);
try {
context.getMap("map").put("key", "oldValue");
context.getMap("map").replace("key", "oldValue", "newValue");
String value = (String) context.getMap("map").get("key");
assertEquals("newValue", value);
return null;
} finally {
HazelcastTransactionContextHolder.clearContext();
}
});
}
Oodatud: newValue
Tegelik: oldValuePidime kirjutama oma replace'i, kasutades getForUpdate:
protected boolean replaceInMap(String mapName, K key, V oldValue, V newValue) {
TransactionalTaskContext context = HazelcastTransactionContextHolder.getContext();
if (context != null) {
log.trace("[CACHE] Asendamine vÀÀrtusele tehingulises kaardis");
TransactionalMap map = context.getMap(mapName);
V value = map.getForUpdate(key);
if (oldValue.equals(value)) {
map.put(key, newValue);
return true;
}
return false;
}
log.trace("[CACHE] Asendamine vÀÀrtusele mitte tehingulises kaardis");
IMap map = hazelcastInstance.getMap(mapName);
return map.replace(key, oldValue, newValue);
}Testige mitte ainult tavalisi andmestruktuure, vaid ka nende tehingulisi versioone. Juhtub, et IMap töötab, aga TransactionalMap ei töötata.
Uue JAR'i allalaadimine ilma katkestuseta
Esialgu otsustasime salvestada Hazelcast'i oma klasside objekte. NĂ€iteks, meil on klass Application, me tahame selle salvestada ja lugeda. Salvestame:
IMap map = hazelcastInstance.getMap("application");
map.set(id, application);Loeme:
IMap map = hazelcastInstance.getMap("application");
return map.get(id);KÔik töötab. Siis otsustasime luua Hazelcast'is indeksi, et selle kaudu otsida:
map.addIndex("subscriberId", false);Ja kui salvestasime uue ĂŒksuse, hakkasime saama ClassNotFoundException'i. Hazelcast ĂŒritas indeksi tĂ€iendada, kuid ei teadnud meie klassist midagi ja tahtis, et me pakuksime selle klassi JAR'i. Me tegime seda ja kĂ”ik töötas, kuid tekkis uus probleem: kuidas uuendada JAR'i ilma klastrite tĂ€ieliku peatamiseta? Hazelcast ei vĂ”ta uut JAR'i vastu versioonivĂ€rskenduse ajal. Sel hetkel otsustasime, et saame elada ilma indeksi otsimiseta. LĂ”ppude lĂ”puks, kui kasutada Hazelcast'i vĂ”tme-vÀÀrtuse salvestusena, kas kĂ”ik toimib? Mitte pĂ€ris. Siin on jĂ€lle erinev kĂ€itumine IMap'i ja TransactionalMap'i vahel. Seal, kus IMap'il pole vahet, TransactionalMap viskab vea.
IMap. Salvestame 5000 objekti, loeme sisse. KÔik on ootuspÀrane.
@Test
void get5000() {
IMap map = hazelcastInstance.getMap("application");
UUID subscriberId = UUID.randomUUID();
for (int i = 0; i < 5000; i++) {
UUID id = UUID.randomUUID();
String title = RandomStringUtils.random(5);
Application application = new Application(id, title, subscriberId);
map.set(id, application);
Application retrieved = map.get(id);
assertEquals(id, retrieved.getId());
}
}Aga tehingutes ei tööta, saame ClassNotFoundException:
@Test
void get_transaction() {
IMap map = hazelcastInstance.getMap("application_t");
UUID subscriberId = UUID.randomUUID();
UUID id = UUID.randomUUID();
Application application = new Application(id, "qwer", subscriberId);
map.set(id, application);
Application retrievedOutside = map.get(id);
assertEquals(id, retrievedOutside.getId());
hazelcastInstance.executeTransaction(context -> {
HazelcastTransactionContextHolder.setContext(context);
try {
TransactionalMap transactionalMap = context.getMap("application_t");
Application retrievedInside = transactionalMap.get(id);
assertEquals(id, retrievedInside.getId());
return null;
} finally {
HazelcastTransactionContextHolder.clearContext();
}
});
}3.8 versioonis ilmus User Class Deployment mehhanism. Saate mÀÀrata ĂŒhe peamise sĂ”lme ja vĂ€rskendada JAR-faili sellel.
NĂŒĂŒd oleme tĂ€ielikult lĂ€henemist muutnud: ise serializeerime JSON-iks ja salvestame Hazelcasti. Hazelcast ei pea teadma meie klasside struktuuri ning me saame vĂ€rskendusi teha ilma seiskamiseta. Domeeniobjektide versioonimist haldab rakendus. Erinevad rakenduse versioonid vĂ”ivad töötada samaaegselt, ja vĂ”ib esineda olukord, kus uus rakendus kirjutab objekte uute vĂ€ljadega, samas kui vana rakendus neid vĂ€lju ei tunne. Ja samal ajal loeb uus rakendus objekte, mille on kirjutanud vana rakendus, millel ei ole uusi vĂ€ljasid. Selliseid olukordi kĂ€sitleme rakenduse sees, kuid lihtsuse huvides ei muuda ega kustuta vĂ€lju, vaid laiendame klasse, lisades uusi vĂ€lju.
Kuidas me tagame kÔrge jÔudluse
Neli pĂ€ringut Hazelcastis â hea, kaks andmebaasis â halb
Andmete hankimine vahemĂ€lust on alati parem kui andmebaasist, kuid ei soovi ka hoida kasutamata kirjeid. Otsuse selle kohta, mida vahemĂ€lus hoida, lĂŒkkame arenduse viimasesse etappi. Kui uus funktsionaalsus on kodeeritud, aktiveerime PostgreSQL-is kĂ”igi pĂ€ringute logimise (log_min_duration_statement 0-le) ja viime lĂ€bi koormustestimise umbes 20 minutiks. Kogutud logide pĂ”hjal suudavad sellised utiliidid nagu pgFouine ja pgBadger koostada analĂŒĂŒtilisi raportite. Raportis otsime esmalt aeglaseid ja sagedasi pĂ€ringuid. Aeglaste pĂ€ringute puhul koostame teostusplaani (EXPLAIN) ja hindame, kas sellist pĂ€ringut on vĂ”imalik kiirendada. Sageli esinevad pĂ€ringud, mis tuginevad samadele sisenditele, sobivad hĂ€sti vahemĂ€lus hoidmiseks. PĂŒĂŒame hoida pĂ€ringud "tasapinnalised", kĂ€sitledes ĂŒhte tabelit ĂŒhes pĂ€ringus.
KĂ€itus
SV kui veebiteenus kÀivitus 2017. aasta kevadel ja kui eraldi toode ilmus SV novembris 2017 (tol hetkel beetaversioonina).
Ăhe aasta jooksul ei ole SV veebiteenuse töös tĂ”siseid probleeme olnud. JĂ€lgime veebiteenust lĂ€bi , kogume ja paigaldame lĂ€bi .
SV serveri installatsioon pakutakse natiivsete paketina: RPM, DEB, MSI. Lisaks pakume Windowsile ĂŒhte installijat, mis on ĂŒhe EXE vormis, mis installeerib serveri, Hazelcasti ja Elasticsearchi ĂŒhele masinale. Alguses nimetasime seda installatsiooni "demonstreerivaks" versiooniks, kuid nĂŒĂŒd on selge, et see on kĂ”ige populaarsem juurutusvariant.
Allikas: habr.com
