Kif u għaliex ktibna servizz skalabbli b'tagħbija għolja għal 1C: Intrapriża: Java, PostgreSQL, Hazelcast

F'dan l-artikolu ser nitkellmu dwar kif u għaliex żviluppajna Sistema ta' Interazzjoni – mekkaniżmu li jittrasferixxi informazzjoni bejn l-applikazzjonijiet tal-klijenti u s-servers 1C:Enterprise - mill-iffissar ta' kompitu għal ħsieb permezz tal-arkitettura u d-dettalji tal-implimentazzjoni.

Is-Sistema ta' Interazzjoni (minn hawn 'il quddiem imsejħa SV) hija sistema ta' messaġġi mqassma u tolleranti għall-ħsarat b'kunsinna garantita. SV huwa ddisinjat bħala servizz ta 'tagħbija għolja bi skalabbiltà għolja, disponibbli kemm bħala servizz onlajn (provdut minn 1C) kif ukoll bħala prodott prodott bil-massa li jista' jiġi skjerat fuq il-faċilitajiet tas-server tiegħek stess.

SV juża ħażna mqassma hazelcast u search engine Elasticsearch. Aħna ser nitkellmu wkoll dwar Java u kif niskalaw orizzontalment PostgreSQL.
Kif u għaliex ktibna servizz skalabbli b'tagħbija għolja għal 1C: Intrapriża: Java, PostgreSQL, Hazelcast

Dikjarazzjoni tal-problema

Biex nagħmilha ċara għaliex ħloqna s-Sistema ta’ Interazzjoni, ngħidlek ftit dwar kif jaħdem l-iżvilupp tal-applikazzjonijiet tan-negozju f’1C.

Biex nibdew, ftit dwarna għal dawk li għadhom ma jafux x'nagħmlu :) Qed nagħmlu l-pjattaforma tat-teknoloġija 1C:Enterprise. Il-pjattaforma tinkludi għodda għall-iżvilupp tal-applikazzjonijiet tan-negozju, kif ukoll runtime li tippermetti li l-applikazzjonijiet tan-negozju jitħaddmu f'ambjent ta 'cross-platform.

Paradigma ta' żvilupp klijent-server

L-applikazzjonijiet tan-negozju maħluqa fuq 1C:Enterprise joperaw fi tliet livelli klijent-server arkitettura “DBMS – application server – client”. Kodiċi tal-applikazzjoni miktuba fi lingwa 1C mibnija, jistgħu jiġu esegwiti fuq is-server tal-applikazzjoni jew fuq il-klijent. Ix-xogħol kollu ma 'oġġetti ta' applikazzjoni (direttorji, dokumenti, eċċ.), kif ukoll il-qari u l-kitba tad-database, jitwettaq biss fuq is-server. Il-funzjonalità tal-formoli u l-interface tal-kmand hija implimentata wkoll fuq is-server. Il-klijent iwettaq forom li jirċievi, jiftaħ u juri, "jikkomunika" mal-utent (twissijiet, mistoqsijiet...), kalkoli żgħar f'formoli li jeħtieġu rispons rapidu (per eżempju, jimmultiplika l-prezz bil-kwantità), jaħdem ma 'fajls lokali, taħdem ma 'tagħmir.

Fil-kodiċi tal-applikazzjoni, l-intestaturi tal-proċeduri u l-funzjonijiet għandhom jindikaw b'mod espliċitu fejn se jiġi esegwit il-kodiċi - bl-użu tad-direttivi &AtClient / &AtServer (&AtClient / &AtServer fil-verżjoni Ingliża tal-lingwa). L-iżviluppaturi 1C issa se jikkoreġuni billi jgħidu li d-direttivi huma fil-fatt aħjar, iżda għalina dan mhux importanti issa.

Tista' ċċempel kodiċi tas-server mill-kodiċi tal-klijent, iżda ma tistax issejjaħ kodiċi tal-klijent mill-kodiċi tas-server. Din hija limitazzjoni fundamentali li għamilna għal numru ta’ raġunijiet. B'mod partikolari, minħabba li l-kodiċi tas-server għandu jinkiteb b'tali mod li jesegwixxi bl-istess mod irrispettivament minn fejn tissejjaħ - mill-klijent jew mis-server. U fil-każ ta 'sejħa tal-kodiċi tas-server minn kodiċi tas-server ieħor, m'hemm l-ebda klijent bħala tali. U minħabba li waqt l-eżekuzzjoni tal-kodiċi tas-server, il-klijent li sejħilha seta' jagħlaq, joħroġ mill-applikazzjoni, u s-server ma jibqax ikollu lil xi ħadd biex iċempel.

Kif u għaliex ktibna servizz skalabbli b'tagħbija għolja għal 1C: Intrapriża: Java, PostgreSQL, Hazelcast
Kodiċi li jimmaniġġja klikk ta’ buttuna: is-sejħa ta’ proċedura ta’ server mill-klijent se taħdem, is-sejħa ta’ proċedura ta’ klijent mis-server mhux se taħdem

Dan ifisser li jekk irridu nibagħtu xi messaġġ mis-server lill-applikazzjoni tal-klijent, pereżempju, li l-ġenerazzjoni ta 'rapport ta' "tul" intemmet u r-rapport jista 'jaraha, m'għandniex metodu bħal dan. Int trid tuża tricks, pereżempju, perjodikament poll is-server mill-kodiċi tal-klijent. Iżda dan l-approċċ jgħabbi s-sistema b'sejħiet bla bżonn, u ġeneralment ma jidhirx eleganti ħafna.

U hemm bżonn ukoll, pereżempju, meta tasal telefonata SIP- meta tagħmel sejħa, avża lill-applikazzjoni tal-klijent dwar dan sabiex tkun tista’ tuża n-numru ta’ min iċempel biex issibha fid-database tal-kontroparti u turi lill-utent l-informazzjoni dwar il-kontroparti li qed iċempel. Jew, pereżempju, meta tasal ordni fil-maħżen, avża lill-applikazzjoni tal-klijent tal-klijent dwar dan. B'mod ġenerali, hemm ħafna każijiet fejn mekkaniżmu bħal dan ikun utli.

Il-produzzjoni nnifisha

Oħloq mekkaniżmu ta 'messaġġi. Mgħaġġel, affidabbli, bi kunsinna garantita, bil-kapaċità li tfittex messaġġi b'mod flessibbli. Ibbażat fuq il-mekkaniżmu, implimenta messaġġier (messaġġi, sejħiet bil-vidjo) li jaħdem ġewwa applikazzjonijiet 1C.

Iddisinja s-sistema biex tkun skalabbli orizzontalment. It-tagħbija li qed tiżdied għandha tkun koperta billi jiżdied in-numru ta 'nodi.

Реализация

Iddeċidejna li ma nintegrawx il-parti tas-server ta 'SV direttament fil-pjattaforma 1C:Enterprise, iżda li nimplimentawha bħala prodott separat, li l-API tiegħu jista' jissejjaħ mill-kodiċi ta 'soluzzjonijiet ta' applikazzjoni 1C. Dan sar għal għadd ta' raġunijiet, li waħda ewlenija minnhom kienet li ridt nagħmilha possibbli li jiġu skambjati messaġġi bejn applikazzjonijiet 1C differenti (per eżempju, bejn Trade Management u Accounting). Applikazzjonijiet 1C differenti jistgħu jaħdmu fuq verżjonijiet differenti tal-pjattaforma 1C:Enterprise, ikunu jinsabu fuq servers differenti, eċċ. F'kundizzjonijiet bħal dawn, l-implimentazzjoni ta 'SV bħala prodott separat li jinsab "fuq il-ġenb" ta' installazzjonijiet 1C hija l-aħjar soluzzjoni.

Għalhekk, iddeċidejna li nagħmlu SV bħala prodott separat. Nirrakkomandaw li kumpaniji żgħar jużaw is-server CB li installajna fis-sħab tagħna (wss://1cdialog.com) biex jevitaw l-ispejjeż ġenerali assoċjati mal-installazzjoni u l-konfigurazzjoni lokali tas-server. Klijenti kbar jistgħu jsibuha rakkomandabbli li jinstallaw is-server CB tagħhom stess fil-faċilitajiet tagħhom. Aħna użajna approċċ simili fil-prodott SaaS tal-cloud tagħna 1cFrisk – jiġi prodott bħala prodott magħmul bil-massa għall-installazzjoni fis-siti tal-klijenti, u jiġi skjerat ukoll fil-cloud tagħna https://1cfresh.com/.

Applikazzjoni

Biex tqassam it-tolleranza tat-tagħbija u l-ħsarat, aħna se niskjeraw mhux applikazzjoni Java waħda, iżda bosta, b'bilanċjar tat-tagħbija quddiemhom. Jekk għandek bżonn tittrasferixxi messaġġ minn node għal nodu, uża publish/subscribe f'Hazelcast.

Il-komunikazzjoni bejn il-klijent u s-server hija permezz tal-websocket. Huwa adattat tajjeb għal sistemi f'ħin reali.

Cache imqassam

Għażilna bejn Redis, Hazelcast u Ehcache. Huwa l-2015. Redis għadu kif ħareġ cluster ġdid (ġdid wisq, tal-biża), hemm Sentinel b'ħafna restrizzjonijiet. Ehcache ma jafx kif jinġabar fi cluster (din il-funzjonalità dehret aktar tard). Iddeċidejna li nippruvawha b'Hazelcast 3.4.
Hazelcast huwa mmuntat fi cluster barra mill-kaxxa. Fil-modalità ta 'nodu wieħed, mhuwiex utli ħafna u jista' jintuża biss bħala cache - ma jafx kif iddampja d-data fuq disk, jekk titlef l-uniku nodu, titlef id-data. Aħna niskjeraw diversi Hazelcasts, li bejniethom nagħmlu backup tad-dejta kritika. Aħna ma nappoġġjawx il-cache - ma nimpurtahx.

Għalina, Hazelcast huwa:

  • Ħażna ta' sessjonijiet ta' l-utenti. Tieħu ħafna żmien biex tmur fid-database għal sessjoni kull darba, għalhekk inpoġġu s-sessjonijiet kollha f'Hazelcast.
  • Cache. Jekk qed tfittex profil tal-utent, iċċekkja l-cache. Kitbet messaġġ ġdid - poġġih fil-cache.
  • Suġġetti għall-komunikazzjoni bejn istanzi ta' applikazzjoni. In-nodu jiġġenera avveniment u jpoġġih fis-suġġett Hazelcast. Nodi ta' applikazzjoni oħra abbonati għal dan is-suġġett jirċievu u jipproċessaw l-avveniment.
  • Cluster serraturi. Pereżempju, noħolqu diskussjoni billi tuża ċavetta unika (diskussjoni waħda fid-database 1C):

conversationKeyChecker.check("БЕНЗОКОЛОНКА");

      doInClusterLock("БЕНЗОКОЛОНКА", () -> {

          conversationKeyChecker.check("БЕНЗОКОЛОНКА");

          createChannel("БЕНЗОКОЛОНКА");
      });

Aħna vverifikajna li m'hemm l-ebda kanal. Ħadna s-serratura, erġajna ċċekkjana, u ħloqnieha. Jekk ma tiċċekkjax is-serratura wara li tieħu s-serratura, allura hemm ċans li ħajt ieħor iċċekkjat ukoll f'dak il-mument u issa se tipprova toħloq l-istess diskussjoni - iżda diġà teżisti. Ma tistax tissakkar billi tuża java Sinkronizzata jew regolari Lock. Permezz tad-database - huwa bil-mod, u hija ħasra għad-database; permezz ta 'Hazelcast - dak li għandek bżonn.

Għażla ta' DBMS

Għandna esperjenza estensiva u ta 'suċċess naħdmu ma' PostgreSQL u nikkollaboraw mal-iżviluppaturi ta 'dan id-DBMS.

Mhux faċli bi cluster PostgreSQL - hemm XL, XC, Citus, iżda b'mod ġenerali dawn mhumiex NoSQLs li jitilgħu barra mill-kaxxa. Aħna ma qisniex NoSQL bħala l-ħażna ewlenija; kien biżżejjed li ħadna Hazelcast, li ma konna ma ħdimna miegħu qabel.

Jekk għandek bżonn tiskala database relazzjonali, dan ifisser sharding. Kif tafu, bi sharding naqsmu d-database f'partijiet separati sabiex kull wieħed minnhom ikun jista 'jitqiegħed fuq server separat.

L-ewwel verżjoni tat-sharding tagħna assumiet il-kapaċità li tqassam kull waħda mit-tabelli tal-applikazzjoni tagħna fuq servers differenti fi proporzjonijiet differenti. Hemm ħafna messaġġi fuq is-server A - jekk jogħġbok, ejja nċaqalqu parti minn din it-tabella għas-server B. Din id-deċiżjoni sempliċement screamed dwar ottimizzazzjoni prematura, għalhekk iddeċidejna li nillimitaw lilna nfusna għal approċċ b'ħafna kerrejja.

Tista 'taqra dwar multi-kerrej, pereżempju, fuq il-websajt Dejta Citus.

SV għandu l-kunċetti ta 'applikazzjoni u abbonat. Applikazzjoni hija installazzjoni speċifika ta' applikazzjoni tan-negozju, bħal ERP jew Accounting, bl-utenti tagħha u d-dejta tan-negozju. Abbonat huwa organizzazzjoni jew individwu li f'ismu l-applikazzjoni hija rreġistrata fis-server SV. Abbonat jista' jkollu diversi applikazzjonijiet reġistrati, u dawn l-applikazzjonijiet jistgħu jiskambjaw messaġġi ma' xulxin. L-abbonat sar kerrej fis-sistema tagħna. Messaġġi minn diversi abbonati jistgħu jinstabu f'database fiżika waħda; jekk naraw li abbonat beda jiġġenera ħafna traffiku, nimxu f'database fiżika separata (jew anke server database separat).

Għandna database prinċipali fejn tinħażen tabella tar-routing b'informazzjoni dwar il-post tad-databases kollha tal-abbonati.

Kif u għaliex ktibna servizz skalabbli b'tagħbija għolja għal 1C: Intrapriża: Java, PostgreSQL, Hazelcast

Biex tipprevjeni li d-database prinċipali tkun ostakolu, inżommu t-tabella tar-routing (u data oħra meħtieġa ta’ spiss) f’cache.

Jekk id-database tal-abbonat tibda tonqos, aħna naqtgħuha f'diviżorji ġewwa. Fuq proġetti oħra nużaw pg_pathman.

Peress li jitilfu l-messaġġi tal-utent huwa ħażin, aħna nżommu d-databases tagħna b'repliki. Il-kombinazzjoni ta 'repliki sinkroniċi u mhux sinkroniċi tippermettilek tassigura lilek innifsek f'każ ta' telf tad-database prinċipali. It-telf tal-messaġġ iseħħ biss jekk id-database primarja u r-replika sinkronika tagħha jfallu fl-istess ħin.

Jekk tintilef replika sinkronika, ir-replika asinkronika ssir sinkronika.
Jekk id-database prinċipali tintilef, ir-replika sinkronika ssir id-database prinċipali, u r-replika asinkronika ssir replika sinkronika.

Elasticsearch għat-tfittxija

Peress li, fost affarijiet oħra, SV huwa wkoll messaġġier, jeħtieġ tfittxija veloċi, konvenjenti u flessibbli, b'kont meħud tal-morfoloġija, bl-użu ta 'logħbiet impreċiżi. Iddeċidejna li ma nivvintax ir-rota mill-ġdid u nużaw il-magna tat-tiftix b'xejn Elasticsearch, maħluqa abbażi tal-librerija Lucene. Aħna wkoll niskjeraw Elasticsearch fi cluster (master - data - data) biex neliminaw il-problemi fil-każ ta 'falliment tan-nodi tal-applikazzjoni.

Fuq github sibna Plugin tal-morfoloġija Russa għal Elasticsearch u użah. Fl-indiċi Elasticsearch aħna naħżnu għeruq tal-kliem (li l-plugin jiddetermina) u N-grammi. Hekk kif l-utent idaħħal test biex ifittex, infittxu t-test ittajpjat fost N-grammi. Meta tiġi ffrankata fl-indiċi, il-kelma "testi" tinqasam f'N-grammi li ġejjin:

[dawk, tek, tex, test, testi, ek, ex, ext, testi, ks, kst, ksty, st, sty, int],

U l-għerq tal-kelma "test" se jiġi ppreservat ukoll. Dan l-approċċ jippermettilek li tfittex fil-bidu, fin-nofs, u fl-aħħar tal-kelma.

L-istampa l-kbira

Kif u għaliex ktibna servizz skalabbli b'tagħbija għolja għal 1C: Intrapriża: Java, PostgreSQL, Hazelcast
Irrepeti l-istampa mill-bidu tal-artiklu, iżda bi spjegazzjonijiet:

  • Balancer espost fuq l-Internet; għandna nginx, jista 'jkun kwalunkwe.
  • L-istanzi tal-applikazzjoni Java jikkomunikaw ma' xulxin permezz ta' Hazelcast.
  • Biex naħdmu ma 'web socket nużaw Netty.
  • L-applikazzjoni Java hija miktuba f'Java 8 u tikkonsisti f'qatet OSGi. Il-pjanijiet jinkludu migrazzjoni għal Java 10 u transizzjoni għal moduli.

Żvilupp u ttestjar

Fil-proċess tal-iżvilupp u l-ittestjar tal-SV, iltqajna ma 'numru ta' karatteristiċi interessanti tal-prodotti li nużaw.

Ittestjar tat-tagħbija u tnixxijiet tal-memorja

Ir-rilaxx ta 'kull rilaxx SV jinvolvi ittestjar tat-tagħbija. Huwa ta' suċċess meta:

  • It-test ħadem għal diversi jiem u ma kien hemm l-ebda ħsarat fis-servizz
  • Il-ħin ta' rispons għal operazzjonijiet ewlenin ma qabiżx limitu komdu
  • Id-deterjorazzjoni tal-prestazzjoni meta mqabbla mal-verżjoni preċedenti mhix aktar minn 10%

Aħna nimlew id-database tat-test bid-dejta - biex nagħmlu dan, nirċievu informazzjoni dwar l-aktar abbonat attiv mis-server tal-produzzjoni, immoltiplika n-numri tagħha b'5 (in-numru ta 'messaġġi, diskussjonijiet, utenti) u nittestjawha b'dan il-mod.

Aħna nwettqu ttestjar tat-tagħbija tas-sistema ta 'interazzjoni fi tliet konfigurazzjonijiet:

  1. test tal-istress
  2. Konnessjonijiet biss
  3. Reġistrazzjoni tal-abbonat

Matul it-test tal-istress, inniedu diversi mijiet ta 'ħjut, u jgħabbu s-sistema mingħajr ma jieqfu: jiktbu messaġġi, joħolqu diskussjonijiet, jirċievu lista ta' messaġġi. Nissimulaw l-azzjonijiet ta 'utenti ordinarji (ikseb lista tal-messaġġi tiegħi mhux moqrija, ikteb lil xi ħadd) u soluzzjonijiet ta' softwer (jitrasmetti pakkett ta 'konfigurazzjoni differenti, ipproċessa twissija).

Pereżempju, dan huwa kif tidher parti mit-test tal-istress:

  • L-utent jidħol
    • Jitlob id-diskussjonijiet mhux moqrija tiegħek
    • 50% probabbli li jaqraw messaġġi
    • 50% probabbli li jikteb
    • Utent li jmiss:
      • Għandu 20% ċans li joħloq diskussjoni ġdida
      • B'mod każwali tagħżel kwalunkwe diskussjoni tagħha
      • Jmur ġewwa
      • Talbiet messaġġi, profili tal-utenti
      • Joħloq ħames messaġġi indirizzati lil utenti każwali minn din id-diskussjoni
      • Iħalli diskussjoni
      • Irrepeti 20 darba
      • Jilloggja, imur lura għall-bidu tal-iskrittura

    • Chatbot jidħol fis-sistema (jemula l-messaġġi mill-kodiċi tal-applikazzjoni)
      • Għandu 50% ċans li joħloq kanal ġdid għall-iskambju tad-dejta (diskussjoni speċjali)
      • 50% probabbli li jikteb messaġġ lil xi wieħed mill-kanali eżistenti

Ix-xenarju "Konnessjonijiet Biss" deher għal raġuni. Hemm sitwazzjoni: l-utenti kkonnettjaw is-sistema, iżda għadhom ma nvolvux. Kull utent jixgħel il-kompjuter fid-09:00 ta' filgħodu, jistabbilixxi konnessjoni mas-server u jibqa' sieket. Dawn il-ġuvini huma perikolużi, hemm ħafna minnhom - l-uniċi pakketti li għandhom huma PING/PONG, iżda jżommu l-konnessjoni mas-server (ma jistgħux iżommuha - x'jiġri jekk ikun hemm messaġġ ġdid). It-test jirriproduċi sitwazzjoni fejn numru kbir ta' utenti bħal dawn jippruvaw jidħlu fis-sistema f'nofs siegħa. Huwa simili għal test ta 'tensjoni, iżda l-fokus tiegħu huwa preċiżament fuq dan l-ewwel input - sabiex ma jkunx hemm fallimenti (persuna ma tużax is-sistema, u diġà taqa' - huwa diffiċli li wieħed jaħseb f'xi ħaġa agħar).

L-iskript tar-reġistrazzjoni tal-abbonat jibda mill-ewwel tnedija. Għamilna stress test u konna ċerti li s-sistema ma naqsitx waqt il-korrispondenza. Iżda ġew utenti u r-reġistrazzjoni bdiet tfalli minħabba timeout. Meta nirreġistraw użajna / dev / każwali, li hija relatata mal-entropija tas-sistema. Is-server ma kellux ħin biex jakkumula biżżejjed entropija u meta ntalbet SecureRandom ġdid, ffriżat għal għexieren ta’ sekondi. Hemm ħafna modi biex toħroġ minn din is-sitwazzjoni, pereżempju: taqleb għall-inqas sigur /dev/urandom, tinstalla bord speċjali li jiġġenera entropy, iġġenera numri bl-addoċċ bil-quddiem u aħżenhom f'pool. Għalaqna temporanjament il-problema bil-pool, iżda minn dakinhar ilna għaddejjin test separat biex nirreġistraw abbonati ġodda.

Aħna nużaw bħala ġeneratur tat-tagħbija JMeter. Ma jafx kif jaħdem mal-websocket; jeħtieġ plugin. L-ewwel fir-riżultati tat-tfittxija għall-mistoqsija “jmeter websocket” huma: artikli minn BlazeMeter, li jirrakkomandaw plugin minn Maciej Zaleski.

Hemmhekk iddeċidejna li nibdew.

Kważi immedjatament wara li bdejna l-ittestjar serju, skoprejna li JMeter beda jnixxi l-memorja.

Il-plugin huwa storja kbira separata; b'176 stilla, għandu 132 frieket fuq github. L-awtur innifsu ilu mpenja ruħu għaliha mill-2015 (ħadna fl-2015, imbagħad ma qajjimx suspetti), diversi kwistjonijiet ta 'github dwar tnixxijiet ta' memorja, 7 talbiet ta 'ġibda mhux magħluqa.
Jekk tiddeċiedi li twettaq ittestjar tat-tagħbija billi tuża dan il-plugin, jekk jogħġbok oqgħod attent għad-diskussjonijiet li ġejjin:

  1. F'ambjent b'ħafna kamini, intużat LinkedList regolari, u r-riżultat kien NPE fir-runtime. Dan jista' jiġi solvut jew billi taqleb għal ConcurrentLinkedDeque jew bi blokki sinkronizzati. Għażilna l-ewwel għażla għalina nfusna (https://github.com/maciejzaleski/JMeter-WebSocketSampler/issues/43).
  2. Tnixxija tal-memorja; meta tiskonnettja, l-informazzjoni tal-konnessjoni ma titħassarx (https://github.com/maciejzaleski/JMeter-WebSocketSampler/issues/44).
  3. Fil-modalità streaming (meta l-websocket ma jkunx magħluq fl-aħħar tal-kampjun, iżda jintuża aktar tard fil-pjan), mudelli ta 'rispons ma jaħdmux (https://github.com/maciejzaleski/JMeter-WebSocketSampler/issues/19).

Dan huwa wieħed minn dawk fuq github. Dak li għamilna:

  1. Ħadu furketta Elyran Kogan (@elyrank) - issolvi l-problemi 1 u 3
  2. Problema solvuta 2
  3. Moll aġġornat mid-9.2.14 sad-9.3.12
  4. SimpleDateFormat imgeżwer f'ThreadLocal; SimpleDateFormat mhuwiex thread-safe, li wassal għal NPE waqt ir-runtime
  5. Iffissat tnixxija oħra tal-memorja (il-konnessjoni kienet magħluqa ħażin meta skonnettjata)

U madankollu jiċċirkola!

Il-memorja bdiet tispiċċa mhux f’ġurnata, iżda f’tnejn. Ma kien fadal assolutament l-ebda ħin, għalhekk iddeċidejna li nniedu inqas ħjut, iżda fuq erba 'aġenti. Dan kellu jkun biżżejjed għal mill-inqas ġimgħa.

Għaddew jumejn...

Issa Hazelcast qed jispiċċa bla memorja. Ir-zkuk wrew li wara ftit jiem ta 'ttestjar, Hazelcast beda jilmenta dwar nuqqas ta' memorja, u wara xi żmien il-cluster waqa 'farrak, u n-nodi komplew imutu wieħed wieħed. Aħna konnessi JVisualVM ma hazelcast u rajna "serrieq li qed jogħlew" - issejjaħ regolarment il-GC, iżda ma setgħetx tnaddaf il-memorja.

Kif u għaliex ktibna servizz skalabbli b'tagħbija għolja għal 1C: Intrapriża: Java, PostgreSQL, Hazelcast

Irriżulta li f'hazelcast 3.4, meta tħassar mappa / multiMap (map.destroy()), il-memorja mhix kompletament meħlusa:

github.com/hazelcast/hazelcast/issues/6317
github.com/hazelcast/hazelcast/issues/4888

Il-bug issa huwa ffissat fi 3.5, iżda dakinhar kienet problema. Ħloqna multiMaps ġodda b'ismijiet dinamiċi u ħassarhom skont il-loġika tagħna. Il-kodiċi deher xi ħaġa bħal din:

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();
    }
}

Ċempel:

service.join(auth1, "НОВЫЕ_СООБЩЕНИЯ_В_ОБСУЖДЕНИИ_UUID1");
service.join(auth2, "НОВЫЕ_СООБЩЕНИЯ_В_ОБСУЖДЕНИИ_UUID1");

multiMap inħoloq għal kull abbonament u mħassar meta ma kienx meħtieġ. Iddeċidejna li se nibdew il-Mappa , iċ-ċavetta tkun l-isem tal-abbonament, u l-valuri se jkunu identifikaturi tas-sessjoni (li minnhom tista 'mbagħad tikseb identifikaturi tal-utent, jekk meħtieġ).

public void join(Authentication auth, String sub) {
    addValueToMap(sub, auth.getSessionId());
}

public void leave(Authentication auth, String sub) { 
    removeValueFromMap(sub, auth.getSessionId());
}

Iċ-ċarts tjiebu.

Kif u għaliex ktibna servizz skalabbli b'tagħbija għolja għal 1C: Intrapriża: Java, PostgreSQL, Hazelcast

X'aktar tgħallimna dwar l-ittestjar tat-tagħbija?

  1. JSR223 jeħtieġ li jinkiteb fi groovy u jinkludi cache ta 'kumpilazzjoni - huwa ħafna aktar mgħaġġel. Link.
  2. Il-grafiċi Jmeter-Plugins huma aktar faċli biex jinftiehmu minn dawk standard. Link.

Dwar l-esperjenza tagħna ma Hazelcast

Hazelcast kien prodott ġdid għalina, bdejna naħdmu miegħu mill-verżjoni 3.4.1, issa s-server tal-produzzjoni tagħna qed jaħdem verżjoni 3.9.2 (fil-ħin tal-kitba, l-aħħar verżjoni ta 'Hazelcast hija 3.10).

Ġenerazzjoni tal-ID

Bdejna b'identifikaturi interi. Ejja nimmaġinaw li għandna bżonn Long ieħor għal entità ġdida. Is-sekwenza fid-database mhix adattata, it-tabelli huma involuti fil-sharding - jirriżulta li hemm messaġġ ID=1 f'DB1 u messaġġ ID=1 f'DB2, ma tistax tpoġġi din l-ID f'Elasticsearch, u lanqas f'Hazelcast , iżda l-agħar ħaġa hija jekk trid tgħaqqad id-dejta minn żewġ databases f'waħda (per eżempju, tiddeċiedi li database waħda hija biżżejjed għal dawn l-abbonati). Tista 'żżid diversi AtomicLongs ma' Hazelcast u żżomm il-counter hemmhekk, allura l-prestazzjoni tal-kisba ta 'ID ġdida hija incrementAndGet flimkien mal-ħin għal talba lil Hazelcast. Iżda Hazelcast għandu xi ħaġa aktar ottimali - FlakeIdGenerator. Meta tikkuntattja lil kull klijent, jingħataw firxa ta 'ID, pereżempju, l-ewwel waħda - minn 1 sa 10, it-tieni - minn 000 sa 10, eċċ. Issa l-klijent jista 'joħroġ identifikaturi ġodda waħdu sakemm tintemm il-firxa maħruġa lilu. Taħdem malajr, iżda meta terġa 'tibda l-applikazzjoni (u l-klijent Hazelcast), tibda sekwenza ġdida - għalhekk l-iskips, eċċ. Barra minn hekk, l-iżviluppaturi ma tantx jifhmu għaliex l-IDs huma sħaħ, iżda huma tant inkonsistenti. Iżenna kollox u qlibna għall-UUIDs.

Mill-mod, għal dawk li jridu jkunu bħal Twitter, hemm tali librerija Snowcast - din hija implimentazzjoni ta 'Snowflake fuq Hazelcast. Tista' tarah hawn:

github.com/noctarius/snowcast
github.com/twitter/snowflake

Imma m’għadniex wasalna.

TransactionalMap.replace

Sorpriża oħra: TransactionalMap.replace ma taħdimx. Hawn 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();
        }        
    });
}

Expected : newValue
Actual : oldValue

Kelli nikteb is-sostituzzjoni tiegħi stess billi tuża getForUpdate:

protected <K,V> boolean replaceInMap(String mapName, K key, V oldValue, V newValue) {
    TransactionalTaskContext context = HazelcastTransactionContextHolder.getContext();
    if (context != null) {
        log.trace("[CACHE] Replacing value in a transactional map");
        TransactionalMap<K, V> map = context.getMap(mapName);
        V value = map.getForUpdate(key);
        if (oldValue.equals(value)) {
            map.put(key, newValue);
            return true;
        }

        return false;
    }
    log.trace("[CACHE] Replacing value in a not transactional map");
    IMap<K, V> map = hazelcastInstance.getMap(mapName);
    return map.replace(key, oldValue, newValue);
}

Ittestja mhux biss l-istrutturi regolari tad-dejta, iżda wkoll il-verżjonijiet transazzjonali tagħhom. Jiġri li IMap jaħdem, iżda TransactionalMap m'għadux jeżisti.

Daħħal JAR ġdid mingħajr waqfien

L-ewwel, iddeċidejna li nirreġistraw oġġetti tal-klassijiet tagħna f'Hazelcast. Pereżempju, għandna klassi ta 'Applikazzjoni, irridu nsalvawha u naqrawha. Ħlief:

IMap<UUID, Application> map = hazelcastInstance.getMap("application");
map.set(id, application);

Naqraw:

IMap<UUID, Application> map = hazelcastInstance.getMap("application");
return map.get(id);

Kollox qed jaħdem. Imbagħad iddeċidejna li nibnu indiċi f'Hazelcast biex infittxu minn:

map.addIndex("subscriberId", false);

U meta kitbu entità ġdida, bdew jirċievu ClassNotFoundException. Hazelcast ipprova jżid mal-indiċi, iżda ma kien jaf xejn dwar il-klassi tagħna u ried li JAR b'din il-klassi jiġi fornut lilha. Għamilna hekk, kollox ħadem, iżda dehret problema ġdida: kif taġġorna l-JAR mingħajr ma twaqqaf kompletament il-cluster? Hazelcast ma jiġborx il-JAR il-ġdid waqt aġġornament nodu b'nodu. F'dan il-punt iddeċidejna li nistgħu ngħixu mingħajr tiftix bl-indiċi. Wara kollox, jekk tuża Hazelcast bħala maħżen ta 'valur ewlieni, allura kollox se jaħdem? Mhux ezatt. Hawnhekk għal darb'oħra l-imġieba ta 'IMap u TransactionalMap hija differenti. Fejn IMap ma jimpurtax, TransactionalMap jarmi żball.

IMap. Aħna niktbu 5000 oġġett, aqrawhom. Kollox mistenni.

@Test
void get5000() {
    IMap<UUID, Application> 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());
    }
}

Iżda ma taħdimx fi tranżazzjoni, aħna jkollna ClassNotFoundException:

@Test
void get_transaction() {
    IMap<UUID, Application> 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<UUID, Application> transactionalMap = context.getMap("application_t");
            Application retrievedInside = transactionalMap.get(id);

            assertEquals(id, retrievedInside.getId());
            return null;
        } finally {
            HazelcastTransactionContextHolder.clearContext();
        }
    });
}

Fi 3.8, deher il-mekkaniżmu tal-Utent Class Deployment. Tista' tinnomina nodu ewlieni wieħed u taġġorna l-fajl JAR fuqu.

Issa biddilna kompletament l-approċċ tagħna: aħna serjalilizzawh lilna nfusna f'JSON u nissejvjawh f'Hazelcast. Hazelcast m'għandux għalfejn ikun jaf l-istruttura tal-klassijiet tagħna, u nistgħu naġġornaw mingħajr waqfien. Il-verżjoni tal-oġġetti tad-dominju hija kkontrollata mill-applikazzjoni. Verżjonijiet differenti tal-applikazzjoni jistgħu jkunu qed jaħdmu fl-istess ħin, u sitwazzjoni hija possibbli meta l-applikazzjoni l-ġdida tikteb oġġetti b'oqsma ġodda, iżda l-qadima għadha ma tafx dwar dawn l-oqsma. U fl-istess ħin, l-applikazzjoni l-ġdida taqra oġġetti miktuba mill-applikazzjoni l-antika li m'għandhomx oqsma ġodda. Aħna nittrattaw sitwazzjonijiet bħal dawn fl-applikazzjoni, iżda għas-sempliċità ma nbiddlux jew inħassru oqsma, aħna nespandu biss il-klassijiet billi nżidu oqsma ġodda.

Kif niżguraw prestazzjoni għolja

Erba' vjaġġi lejn Hazelcast - tajba, tnejn għad-database - ħażina

Li tmur fil-cache għad-dejta hija dejjem aħjar milli tmur fid-database, imma lanqas trid taħżen rekords mhux użati. Aħna nħallu d-deċiżjoni dwar x'għandek cache sal-aħħar stadju ta 'żvilupp. Meta l-funzjonalità l-ġdida tkun ikkodifikata, aħna nixgħel il-illoggjar tal-mistoqsijiet kollha f'PostgreSQL (log_min_duration_statement għal 0) u wettaq l-ittestjar tat-tagħbija għal minuti 20. Bl-użu ta 'zkuk miġbura, utilitajiet bħal pgFouine u pgBadger jistgħu jibnu rapporti analitiċi. Fir-rapporti, primarjament infittxu mistoqsijiet bil-mod u frekwenti. Għal mistoqsijiet bil-mod, aħna nibnu pjan ta 'eżekuzzjoni (SPJEGA) u nevalwaw jekk tali mistoqsija tistax tiġi aċċellerata. Talbiet frekwenti għall-istess dejta tal-input jidħlu sew fil-cache. Nippruvaw inżommu l-mistoqsijiet "ċatti", tabella waħda għal kull mistoqsija.

Isfruttament

SV bħala servizz onlajn tħaddem fir-rebbiegħa tal-2017, u bħala prodott separat, SV ġie rilaxxat f'Novembru 2017 (dak iż-żmien fl-istatus tal-verżjoni beta).

F'aktar minn sena ta' operat, ma kien hemm l-ebda problema serja fl-operat tas-servizz online CB. Aħna nissorveljaw is-servizz online permezz Zabbix, iġbor u skjerament minn bambu.

Id-distribuzzjoni tas-server SV hija fornuta fil-forma ta 'pakketti indiġeni: RPM, DEB, MSI. Barra minn hekk għall-Windows nipprovdu installatur wieħed fil-forma ta 'EXE wieħed li jinstalla s-server, Hazelcast u Elasticsearch fuq magna waħda. Inizjalment irreferejna għal din il-verżjoni tal-installazzjoni bħala l-verżjoni "demo", iżda issa deher ċar li din hija l-aktar għażla ta 'skjerament popolari.

Sors: www.habr.com

Żid kumment