Selles artiklis rÀÀgime, kuidas ja miks me arendasime â mehhanism, mis edastab teavet kliendirakenduste ja 1C:Enterprise serverite vahel â ĂŒlesande seadmisest arhitektuuri ja rakenduse ĂŒksikasjade vĂ€ljatöötamiseni.
Koostöö sĂŒsteem (edaspidi â KS) on hajutatud tĂ”rketaluv sĂ”numite vahetamise sĂŒsteem tagatud kohaletoimetamisega. KS on loodud kĂ”rgendatud koormuse teenusena, millel on kĂ”rge mastaapsus ning on saadaval nii veebiteenusena (mida pakub 1C) kui ka seeriatootena, mida saab juurutada oma serveriressurssidesse.
KS kasutab hajutatud salvestust ja otsingusĂŒsteemi . RÀÀgime ka Java'st ja sellest, kuidas me horisontaalselt skaleerime PostgreSQL-i.
Ălesande seadmine
Et oleks selge, miks me Koostöö sĂŒsteemi tegime, rÀÀgin veidi sellest, kuidas 1C-s Ă€rirakenduste arendamine toimub.
Alustuseks â natuke meie kohta neile, kes veel ei tea, millega me tegeleme:) Me arendame tehnoloogiaplatvormi "1C:EttevĂ”te". Platvorm sisaldab Ă€rirakenduste arendustööriistu ja runtime'i, mis vĂ”imaldab Ă€rirakendustel töötada ristplatvormil.
Kliendiserveri arenduspÔhimÔte
Ărirakendused, mis on loodud "1C:EttevĂ”tte" peal, töötavad kolmekihilise arhitektuuri "DBMS â rakendusserver â klient". Rakenduslik kood, mis on kirjutatud , vĂ”ib kĂ€ivituda kas rakendusserveris vĂ”i kliendis. KĂ”ik rakendusobjektidega (nĂ€iteks registrite, dokumentide jne) seotud tehingud, samuti andmebaasi lugemine ja kirjutamine toimub ainult serveris. Vormide ja kĂ€surea funktsionaalsus on samuti rakendatud serveris. Kliendis toimub vormide saamine, avamine ja kuvamine, kasutajaga "suhtlemine" (hoiatuste, kĂŒsimuste jne kaudu), vĂ€iksed arvutused vormides, mis vajavad kiiret reageerimist (nĂ€iteks hinna korrutamine kogusega), kohalike failidega töötamine, seadmetega töötamine.
Rakenduskoodis peavad protseduuride ja funktsioonide pealkirjades olema selgelt mĂ€rgitud, kus kood tĂ€idetakse - kasutades direktiive &ĐаĐĐ»ĐžĐ”ĐœŃĐ” / &ĐаХДŃĐČĐ”ŃĐ” (&AtClient / &AtServer ingliskeelses keeleversioonis). 1C arendajad parandavad mind nĂŒĂŒd, öeldes, et direktiive tegelikult , kuid meile pole see praegu oluline.
Kliendikoodist saab kutsuda serverikoodi, kuid serverikoodist kliendikoodi kutsuda ei saa. See on meie kehtestatud fundamentaalne piirang mitmel pĂ”hjusel. Esiteks, serverikood peab olema kirjutatud nii, et see tĂ€itub ĂŒhtemoodi, sĂ”ltumata sellest, kust seda kutsutakse - kliendilt vĂ”i serverilt. Ja juhul, kui serverikoodi kutsutakse teise serverikoodi seest, puudub klient tĂ€ielikult. Ja samuti seetĂ”ttu, et serverikoodi tĂ€itmise kĂ€igus vĂ”is klient, kes selle kutsus, sulgeda, rakendusest vĂ€lja minna, ja serveril ei ole enam kedagi, keda kutsuda.
Nupu vajutamise töötav kood: kliendi serveriprotseduuri kutsumine töötab, serverilt kliendiprotseduuri kutsumine - ei.
See tĂ€hendab, et kui me serverist tahame edastada mingit sĂ”numit kliendirakendusse, nĂ€iteks et "pikaajalise" raporti genereerimine on lĂ”ppenud ja raportit on vĂ”imalik vaadata â sellist vĂ”imalust meil ei ole. Peame kasutama trikke, nĂ€iteks kliendikoodist perioodiliselt serverit kĂŒsima. Kuid selline lĂ€henemine koormab sĂŒsteemi liigsete vĂ€ljakutsetega ja ei tundu eriti Ă©lĂ©gantsena.
Ja on ka vajadus, nĂ€iteks, kui telefonikĂ”ne -teavitada sellest klienditeavet, et see leidu jĂ€tkuvalt helistaja numbri jĂ€rgi personaalsetest andmetest ja nĂ€itaks kasutajale teavet helistava kliendi kohta. VĂ”i nĂ€iteks, kui laos on tellimus, teavitada sellest kliendi rakendust tellijale. ĂhesĂ”naga, olukordi, kus selline mehhanism vĂ”iks kasuks tulla, on palju.
Tegelikult ĂŒlesanne
Loo sÔnumite vahetamise mehhanism. Kiire, usaldusvÀÀrne, garantii kohaletoimetamine, vÔimalus sÔnumite paindlikuks otsimiseks. Mehhanismi pÔhjal rakenda sÔnumi rakendus (sÔnumid, videokÔned), mis töötab 1C rakendustes.
Kujundada horisontaalselt skaleeritav sĂŒsteem. Suurenev koormus peab olema katnud sĂ”lmede arvu suurendamisega.
Rakendus
Otsustasime, et SV serveriosa ei integreerita otse 1C:Enterprise platvormi, vaid rakendatakse eraldi tootena, mille API-d saab kutsuda 1C rakenduste lahenduste koodist. Seda tehti mitmel pĂ”hjusel, millest kĂ”ige olulisem on vĂ”imaldada sĂ”numite vahetust erinevate 1C rakenduste vahel (nĂ€iteks kaubanduse juhtimise ja raamatupidamise vahel). Erinevad 1C rakendused vĂ”ivad töötada erinevate 1C:Enterprise platvormi versioonide peal, asuda erinevates serverites jne. Sellistes tingimustes on SV teostamine eraldi tootena, mis asub 1C installatsioonidest âkĂŒlgâ - optimaalne lahendus.
Nii et, otsustasime, et teeme SV-st eraldi toote. VĂ€ikestele ettevĂ”tetele soovitame kasutada SV-serverit, mille oleme oma pilves ĂŒles seadnud (wss://1cdialog.com), et vĂ€ltida kohaliku installatsiooni ja seadistamisega seotud kulusid. Suuremad kliendid vĂ”ivad aga leida, et nende vĂ”imsustele oma SV-serveri seadmine on Ă”igustatud. Sarnast lĂ€henemist kasutasime ka oma pilvepĂ”hises SaaS-toote puhul. â see on vĂ€lja antud kui versioonitoode klientide installimiseks ning samuti on see meie pilves ĂŒles seatud. .
Rakendus
Koormuse ja tĂ”rke talumise saavutamiseks seame ĂŒles mitte ĂŒhe, vaid mitu Java-rakendust ja nende ette paneme koormuse tasakaalustaja. Kui sĂ”numit peab node'ilt node'ile edastama, kasutame Hazelcastis publish/subscribe sĂŒsteemi.
Kliendi suhtlemine serveriga toimub websocket'i kaudu. See sobib hĂ€sti reaalajas sĂŒsteemide jaoks.
Jaotatud vahemÀlu
Otsisite Redis, Hazelcasti ja Ehcache'i vahel. Aasta on 2015. Redis just lahkus uuest klastri versioonist (liialt uus, hirmutav), Sentineli kuulub hulk piiranguid. Ehcache ei oska kokku koguneda (see funktsionaalsus tuli hiljem). Otsustasime proovida Hazelcast 3.4.
Hazelcast koguneb klastri «kastist vĂ€lja». Ăhe sĂ”lme reĆŸiimis pole see eriti kasulik ja sobib ainult vahemĂ€luna â ei oska andmeid kettale salvestada; kaotasime ainulaadse sĂ”lme â kaotasime andmed. Me paigutame mitu Hazelcasti ja varundame kriitilisi andmeid nende vahel. VahemĂ€lu ei varunda â seda ei ole kahju.
Meie jaoks on Hazelcast:
- Kasutaja sessioonide salvestus. Iga kord, kui minema baasi sessiooni jĂ€rele minna â vĂ”tab kaua aega, seetĂ”ttu paneme kĂ”ik sessioonid Hazelcasti.
- VahemĂ€lu. Otsid kasutaja profiili â kontrolli vahemĂ€lus. Kirjutasid uue sĂ”numi â pane vahemĂ€llu.
- Rakenduse instantside suhtlemise teemad. SĂ”lm genereerib sĂŒndmuse ja asetab selle Hazelcasti teemasse. Teised rakenduse sĂ”lmed, mis sellele teemale on tellinud, saavad ja töötlevad sĂŒndmust.
- Klastri lukustused. NĂ€iteks loome arutelu unikaalse vĂ”tme alusel (sĂŒntesaator arutelu 1C andmebaasi raames):
conversationKeyChecker.check("BENSOKOLONKA");
doInClusterLock("BENSOKOLONKA", () -> {
conversationKeyChecker.check("BENSOKOLONKA");
createChannel("BENSOKOLONKA");
});Kontrollisime, et kanal puudub. VĂ”tsime lukustuse, kontrollisime uuesti, lĂ”ime. Kui lukustust ei kontrollita, on vĂ”imalus, et mĂ”ni teine teema, mis sel ajal samuti kontrollis, proovib luua sama arutelu â ja see juba eksisteerib. Lukustust ei saa teha synchronized vĂ”i tavalise java Lock abil. Andmebaasi kaudu â aeglane, ja andmebaasi ka kahju, Hazelcast lĂ€bi â see on just see, mida vajame.
Valime DBMS-i
Meil on suur ja edukas kogemus PostgreSQL-i ning selle andmebaasi arendajatega koostöö tegemisel.
PostgreSQL-i klustereerimine on keeruline â on , , , kuid see ei ole iseenesest noSQL, mis on vĂ€lja pakutud mastiks. Me ei pidanud noSQL-i peamise salvestuslahendusena, piisab sellest, et kasutame Hazelcasti, millega me varem pole töötanud.
Kui tuleb skaleerida relatsiooni DB â siis tĂ€hendab see . Nagu te teate, jagame shardinguga andmebaasi eraldi osadeks, nii et igaĂŒht neist saab viia eraldi serverisse.
Meie esimene sharding'i variant eeldas, et saame jagada meie rakenduse iga tabeli erinevatesse serveritesse erinevates proportsioonides. Kui serveris A on palju sĂ”numeid â palun, viige osa sellest tabelist serverisse B. See lahendus oli selgelt enneaegne optimeerimine, seetĂ”ttu otsustasime piirduda multi-tenant lĂ€henemisega.
Multi-tenant'i kohta saate lugeda nÀiteks veebisaidilt .
SV-s on mÀÀratlused rakenduse ja tellija kohta. 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 rakendus registreeritakse SV serveris. Tellijal vĂ”ib olla registreeritud mitu rakendust, ning need rakendused saavad omavahel sĂ”numeid vahetada. Tellija on meie sĂŒsteemis muutunud elanikuks (tenant). Mitme tellija sĂ”numid 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 andmebaasi serverisse).
Meil on peamine andmebaas, kus hoitakse suunamise tabelit kÔigi tellijate andmebaaside asukoha teabega.
Kuna peamine andmebaas ei tohi olla kitsaskoht, hoiame suunamise tabelit (ja muid sageli kasutatavaid andmeid) vahemÀlus.
Kui tellija andmebaas hakkab aeglustuma, lÔikame selle sees osadeks. Teistes projektides kasutame suurte tabelite partitsioneerimiseks .
Kuna kasutajate sĂ”numite kadumine on halb, toetame meie andmebaase koopiatega. SĂŒnkroonsete ja asĂŒnkroonsete koopiate kombinatsioon vĂ”imaldab meil kindlustada end peamise andmebaasi kadumise korral. SĂ”numi kadu 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, et SV on lisaks muule ka sĂ”numiteenus, on hĂ€davajalik kiire, mugav ja paindlik otsing, mis arvestab morfoloogiat ja ebakorrektseid vasteid. Otsustasime, et ei hakka ratast leiutama ja kasutame avatud otsingusĂŒsteemi Elasticsearch, mis on loodud Lucene'i raamatukogu pĂ”hjal. . Elasticsearchi deployime ka klastris (master â data â data), et vĂ€hendada rakenduse sĂ”lmede rikkeprobleemide riski.
Githubis leidsime Elasticsearchile ja kasutame seda. Elasticsearchi indeksis hoiame sĂ”nade juured (mida mÀÀrab plugin) ja N-grammid. Kui kasutaja sisestab otsinguteksti, otsime sisestatud teksti N-grammide hulgast. Indeksi salvestamisel sĂ”na âtekstidâ jaguneb jĂ€rgmistesse N-grammidesse:
[te, tek, tekste, tekst, tekstid, ek, eks, ekst, ekstid, ks, kst, kstid, st, stid, tid],
Ning ka salvestatakse sĂ”na âtekstâ juur. Selline lĂ€henemine vĂ”imaldab otsida nii sĂ”na algust, keskel kui ka lĂ”pust.
Ăldine pilt
Kuvab sama pilti artikli algusest, kuid juba seletustega:
- Tasakaalustaja, mis on Interneti-suunas; meil on nginx, vĂ”ib olla ĂŒkskĂ”ik milline.
- Java rakenduste instantsid suhtlevad omavahel lÀbi Hazelcasti.
- Veebisoketiga töötamiseks kasutame .
- Java rakendus on kirjutatud Java 8 keeles, koosneb bundeledest . Plaanides on ĂŒleminek Java 10-le ja modulaarsele arhitektuurile.
Arendus ja testimine
Arenduse ja testimise protsessis kohtasime mitmeid huvitavaid tooteomadusi, mida kasutasime.
Koormustestimine ja mÀlu leketud
Iga versi vÀljund on koormustestimine. See on edukalt lÀbitud, kui:
- Test kestis mitu pÀeva ja teenusekatkestusi ei esinenud
- Peamiste toimingute vastuse aeg ei ĂŒletanud mugavat piiri
- Tootlikuse halvenemine vĂ”rreldes eelmise versiooniga ei ole ĂŒle 10%
Testimisbaasi tĂ€idame andmetega â selleks saame tootmisserverilt teavet kĂ”ige aktiivsema tellija kohta, korrutame tema numbrid 5-ga (sĂ”numite, arutelude, kasutajate arv) ja testime nii.
Koormustestimist sĂŒsteemi interaktsiooni teeme kolmes konfiguratsioonis:
- Stressitest
- Ainult ĂŒhendused
- Tellijate registreerimine
Stressitestil kĂ€ivitame mitu sada voogu, mis pidevalt koormavad sĂŒsteemi: kirjutavad sĂ”numeid, loovad arutelusid, saadavad sĂ”numite nimekirja. Imitseerime tavaliste kasutajate tegevusi (saada oma lugemata sĂ”numite nimekiri, kellelegi kirjutada) ja programmilisi lahendusi (ĂŒle anda pakett erineva konfiguratsiooniga, töödelda teadet).
NÀiteks, nii nÀeb vÀlja osa stressitestist:
- SĂŒsteemi siseneb kasutaja
- KĂŒsimus oma lugemata arutelude kohta
- 50% tÔenÀosusega loeb sÔnumeid
- 50% tÔenÀosusega kirjutab sÔnumeid
- Edasi jÀtkab kasutaja:
- 20% tÔenÀosusega loob uue arutelu
- Valib juhuslikult mÔne oma arutelu
- Siseneb sisse
- KĂŒsimus sĂ”numeid, kasutajate profiile
- Loob viis sÔnumit, mis on suunatud juhuslikele kasutajatele sellest arutelust
- Lahkub arutelust
- Kordab 20 korda
- Lahkub sĂŒsteemist, naaseb stsenaariumi algusesse
- SĂŒsteemi siseneb chatbot (imiteerib sĂ”numivahetust rakenduste koodist)
- 50% tÔenÀosusega loob uue kanali andmevahetuseks (eriline arutelu)
- 50% tÔenÀosusega saadab sÔnumi mÔnes olemasolevas kanalisse
Skeem «Ainult ĂŒhendused» ei ilmnenud juhuslikult. On olukordi: kasutajad on sĂŒsteemi lĂŒlitanud, kuid pole veel sisse harjunud. Iga kasutaja lĂŒlitab hommikul kell 09:00 arvuti sisse, loob serveriga ĂŒhenduse ja vaikib. Need tĂŒĂŒbid on ohtlikud, neid on palju â nende paketid sisaldavad ainult PING/PONG, kuid nad hoiavad serveriga ĂŒhendust (nad ei saa seda mitte hoida â Ă€kki tuleb uus sĂ”num). Test simuleerib olukorda, kus sĂŒsteemi pĂŒĂŒab poole tunni jooksul sisse logida suur hulk selliseid kasutajaid. See on sarnane stressitestiga, kuid see keskendub just sellele esimeses sisenemises â et ei toimuks tĂ”rkeid (inimene ei kasuta sĂŒsteemi, kuid see juba ebaĂ”nnestub â raske on midagi hullemat vĂ€lja mĂ”elda).
Kasutajate registreerimise skeem algab esimesest kĂ€ivitamisest. Me tegime stressitesti ja olime kindlad, et kirjavahetuse kĂ€igus sĂŒsteem ei aeglustu. Kuid kasutajad hakkasid sisse logima ja registreerimine hakkas ajapiirangute tĂ”ttu ebaĂ”nnestuma. Registreerimisel kasutasime , mis on seotud sĂŒsteemi entropiaga. Server ei jĂ”udnud piisavalt entropiat koguda ning uue SecureRandom'i nĂ”udmisel seiskus see kĂŒmneid sekundeid. Sellest olukorrast on palju vĂ€ljapÀÀse, nĂ€iteks: minna ĂŒle vĂ€hem turvalisele /dev/urandom'ile, paigutada spetsiaalne kaart, mis genereerib entropiat, genereerida juhuslikke numbreid ette ja hoida neid teas. Me lahendasime probleemi ajutiselt puuga, kuid alates sellest ajast juhime eraldi testi uute tellijate registreerimise osas.
Koormuse generaatorina kasutame . See ei oska töötada veebipÔhiste soketitega, vajalik on plugin. Esimesed otsingutulemustes otsingus "jmeter websocket" on , milles soovitatakse .
. Sellest me ka alustasime.
Peaaegu kohe pÀrast tÔsiste testide alustamist avastasime, et JMeter'is algasid mÀluleked.
Plugin â see on eraldi suur lugu, 176 tĂ€hega on tal 132 fork'i github'is. Autor ei ole sinna 2015. aastast kommenteerinud (me kasutasime seda 2015. aastal, siis see ei tekitanud kahtlusi), mitmeid github'i probleeme seoses mĂ€luleketega, 7 lahendamata pull request'i.
Kui otsustate testida koormust selle pluginaga, pöörake tÀhelepanu jÀrgmistele aruteludele:
- Mitme haru sĂŒsteemis kasutati tavalist LinkedList'i, mille tulemusena saadi kĂ€itamisel. Selle saab lahendada, kas liikudes ConcurrentLinkedDeque'i juurde vĂ”i kasutades synchronized-blokke. Otsustasime esimese variandi kasuks ().
- MĂ€lu leke, teabe kustutamine ĂŒhenduse katkestamise korral ei toimi ().
- Streaming-reĆŸiimis (kui veebisoket ei suleta proovi lĂ”pus, vaid kasutatakse edasi) ei tööta Response pattern'id ().
See on ĂŒks neist, mis on github'is. Mida tegime:
- VĂ”tsime (@elyrank) â seal on lahendatud probleemid 1 ja 3
- Lahendasime probleemi 2
- Uuendasime jetty versioonilt 9.2.14 9.3.12-le
- Kapseldasime SimpleDateFormat'i ThreadLocal'i; SimpleDateFormat ei ole lÔimeohutu, mis tÔi kaasa NPE kÀitamisel
- Korrigeerisime veel ĂŒhe mĂ€lu leke (ĂŒhendus ei suletud Ă”igesti katkestamise korral)
Kuid siiski voolab!
MĂ€lu hakkas otsa saama mitte ĂŒhe pĂ€eva, vaid kahe pĂ€evaga. Aega ei jÀÀnud, otsustasime kĂ€ivitada vĂ€hem lĂ”ime, kuid neljal agentil. Seda pidi piisama vĂ€hemalt nĂ€dalaks.
On möödunud kaks pĂ€evaâŠ
NĂŒĂŒd hakkas Hazelcast-il mĂ€lu otsa saama. Logides oli nĂ€ha, et pĂ€rast paaripĂ€evast testimist hakkab Hazelcast kurtma mĂ€lupuuduse ĂŒle ja pĂ€rast mĂ”nda aega laguneb klaster ning sĂ”lmed jĂ€tkavad ĂŒksikult hukkumist. Me ĂŒhendasime JVisualVM hazelcast-iga ja nĂ€gime "tĂ”usvat saagi" â see kutsus regulaarselt esile GC, kuid ei suutnud kuidagi mĂ€lu puhastada.
Selgus, et hazelcast 3.4 versioonis ei vabastata mÀlu tÀielikult, kui kustutatakse map / multiMap (map.destroy()):
Praegu on viga 3.5 versioonis parandatud, kuid siis oli see probleem. Me loome uusi multiMap-e dĂŒnaamiliste nimedega ja kustutame vastavalt oma loogikale. Kood nĂ€gi vĂ€lja umbes nii:
public void join(Authentication auth, String sub) {
MultiMap<UUID, Authentication> sessions = instance.getMultiMap(sub);
sessions.put(auth.getUserId(), auth);
}
public void leave(Authentication auth, String sub) {
MultiMap<UUID, Authentication> sessions = instance.getMultiMap(sub);
sessions.remove(auth.getUserId(), auth);
if (sessions.size() == 0) {
sessions.destroy();
}
}Kutse:
service.join(auth1, "UUED_SĂNUMID_ARUTEL_UUID1");
service.join(auth2, "UUED_SĂNUMID_ARUTEL_UUID1");multiMap loodi iga tellimuse jaoks ja eemaldati, kui seda ei olnud enam vaja. Otsustasime, et kasutame Map<String,Set>, kus vĂ”tmena on tellimuse nimi ja vÀÀrtustena seansi identifikaatorid (mille alusel saab vajadusel kasutaja identifikaatoreid saada).
public void join(Authentication auth, String sub) {
addValueToMap(sub, auth.getSessionId());
}
public void leave(Authentication auth, String sub) {
removeValueFromMap(sub, auth.getSessionId());
}Graafikud on paranenud.
Mida veel oleme Ôppinud koormustestimise kohta
- JSR223 tuleb kirjutada groovy keeles ja aktiveerida kompilatsiooni vahemĂ€lu â see on oluliselt kiirem. .
- Jmeter-Plugins graafikud on lihtsamad mÔista kui standardsed. .
Meie kogemus Hazelcastiga
Hazelcast oli meie jaoks uus toode, alustasime selle kasutamist versioonist 3.4.1, praegu on meie tootmisserveris versioon 3.9.2 (artikli kirjutamise hetkel oli viimane versioon Hazelcast â 3.10).
ID genereerimine
Alustasime tĂ€isarvuliste identifikaatoritega. Kujutlegem, et vajame uue ĂŒksuse jaoks Long tĂŒĂŒpi identifikaatorit. Andmebaasi jĂ€rk ei sobi, tabelid osalevad shardingus â viib see selleni, et on sĂ”num ID=1 andmebaasis DB1 ja sĂ”num ID=1 andmebaasis DB2, Elasticsearchis sellise ID jĂ€rgi ei talletata, Hazelcastis samuti, kuid kĂ”ige hullem on see, kui soovite kahte andmebaasi ĂŒhendada ĂŒhte (nĂ€iteks otsustades, et piisab ĂŒhest andmebaasist nende abonentide jaoks). Hazelcastis saab luua mitu AtomicLong ja hoida loendurit seal, siis on uue ID saamise tulemuslikkus â incrementAndGet pluss aeg Hazelcastisse pĂ€ringu tegemiseks. Kuid Hazelcastis on midagi veel optimaalsemat â FlakeIdGenerator. Iga kliendi jaoks vĂ€ljastatakse ID vahemik, nĂ€iteks esimesena â vahemik 1 kuni 10 000, teisele â vahemik 10 001 kuni 20 000 ja nii edasi. NĂŒĂŒd saab klient uusi identifikaatoreid ise vĂ€lja anda, kuni tema antud vahemik lĂ”peb. Töötab kiiresti, kuid rakenduse (ja Hazelcasti kliendi) taaskĂ€ivitamisel algab uus jĂ€rjestus â sealt tulenevad Ă€rajÀÀnud ID-d jne. Samuti ei saa arendajad hĂ€sti aru, miks ID-d on tĂ€isarvud, kuid on nii palju segmenteeritud. Oleme kĂ”ik kaalunud ja lĂ€inud UUID-de peale.
Muide, neile, kes soovivad olla nagu Twitter, on olemas selline teek nimega Snowcast â see on Snowflake'i teostus Hazelcast'i peal. Vaadata saab siit:
Kuid me ei ole selle nii kaugele veel 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();
}
});
}
Oodatav: newValue
Tegelik: oldValuePidin kirjutama oma replace, 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ÀÀrtuse a transactioneel kaardil");
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ÀÀrtuse mitte transactioneel kaardil");
IMap map = hazelcastInstance.getMap(mapName);
return map.replace(key, oldValue, newValue);
}Testige mitte ainult tavalisi andmestruktuure, vaid ka nende tehinguversioone. Juhtub, et IMap töötab, aga TransactionalMap mitte.
Uue JAR-i paigaldamine ilma seisakute tekitamiseta
Alguses otsustasime salvestada Hazelcasti oma klasside objekte. NĂ€iteks, meil on klass Application, mida soovime salvestada ja lugeda. Salvestame:
IMap map = hazelcastInstance.getMap("application");
map.set(id, application);Lugemine:
IMap map = hazelcastInstance.getMap("application");
return map.get(id);KÔik töötab. SeejÀrel otsustasime luua Hazelcastis indeksi, et selle kaudu otsida:
map.addIndex("subscriberId", false);Ja kui me registreerisime uue ĂŒksuse, algas ClassNotFoundException. Hazelcast ĂŒritas indeksi tĂ€iendamist, kuid ei teadnud meie klassist midagi ja soovis, et me esitaksime JAR-i koos selle klassiga. Me tegime nii ja kĂ”ik töötas, kuid tekkis uus probleem: kuidas uuendada JAR-i ilma klastrit tĂ€ielikult peatamata? Hazelcast ei paku uut JAR-i pĂ€rast podide vĂ€rskendamist. Sel hetkel otsustasime, et saame ilma indeksiotsinguta ka hakkama. Kui kasutada Hazelcasti vĂ”tme-vÀÀrtuse salvestusena, kas siis kĂ”ik töötab? Mitte pĂ€ris. Siin nĂ€eme jĂ€lle erinevat kĂ€itumist IMap ja TransactionalMap vahel. Seal, kus IMap ei hooli, viskab TransactionalMap vea.
IMap. Salvestame 5000 objekti, loeme vÀlja. KÔik 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 tehingus see 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 lĂ€henemise tĂ€ielikult muutnud: me serialiseerime JSON-i ja salvestame selle Hazelcasti. Hazelcast ei pea teadma meie klasside struktuuri, mistĂ”ttu saame uuendada ilma seisakuteta. Domeeniobjektide versioneerimist juhib rakendus. Samal ajal vĂ”ivad töötada erinevad rakenduste versioonid, ja vĂ”ib juhtuda, et uus rakendus kirjutab objekte uute vĂ€ljadega, mille kohta vana veel ei tea. Ja samal ajal loeb uus rakendus objekte, mille on salvestanud vana rakendus, kus uutest vĂ€ljadest puuduvad. Sellised olukorrad kĂ€sitletakse rakenduse sees, kuid lihtsuse huvides me ei muuda ega eemalda vĂ€lju, vaid ainult laiendame klasse uute vĂ€ljade lisamisega.
Kuidas me tagame kÔrge jÔudluse
Neli kĂŒlastust Hazelcasti â hea, kaks andmebaasi â halb
Andmete toomine vahemĂ€lust on alati parem kui andmebaasist, kuid me ei taha hoida kasutut teavet. Otsuse selle kohta, mida vahemĂ€llu salvestada, lĂŒkkame arenduse viimasele etapile. Kui uus funktsionaalsus on kodeeritud, aktiveerime PostgreSQLis kĂ”ikide pĂ€ringute logimise (log_min_duration_statement seade 0) ja teeme koormustestimise umbes 20 minutiks. Kogutud logide pĂ”hjal oskavad tööriistad nagu pgFouine ja pgBadger koostada analĂŒĂŒtilisi aruandeid. Aruannetes otsime eelkĂ”ige aeglaseid ja sagedasi pĂ€ringuid. Aeglaste pĂ€ringute jaoks koostame tĂ€itmisplaani (EXPLAIN) ja hindame, kas sellist pĂ€ringut saaks kiirendada. Samade sisendandmete sagedased pĂ€ringud paigutuvad hĂ€sti vahemĂ€llu. PĂ€ringud pĂŒĂŒame hoida "tasapinnaliste" ehk ĂŒhes pĂ€ringus ainult ĂŒhte tabelit.
Töötamine
SV online-teenus kÀivitati 2017. aasta kevadel, eraldi tootena ilmus SV 2017. aasta novembris (toona beetaversioonina).
Rohkem kui aasta kasutusea jooksul ei ole SV online-teenuses olnud tÔsiseid probleeme. , kogume ja juurutame lÀbi .
SV serveri distributsioon tarnitakse natiivsete paketina: RPM, DEB, MSI. Lisaks pakume Windowsile ĂŒhte installijat, mis on ĂŒks EXE-fail, mis installib serveri, Hazelcasti ja Elasticsearchi ĂŒhele masinale. Esialgu nimetati seda installiversiooni âdemonstreerivaksâ, kuid nĂŒĂŒd on selge, et see on kĂ”ige populaarsem juurutamisviis.
Allikas: habr.com
