Jinsi na kwa nini tuliandika huduma ya upakiaji wa juu kwa 1C: Biashara: Java, PostgreSQL, Hazelcast

Katika makala hii tutazungumza juu ya jinsi na kwa nini tuliendeleza Mfumo wa Mwingiliano – utaratibu unaohamisha taarifa kati ya programu za mteja na 1C:Seva za Biashara - kutoka kwa kuweka kazi hadi kufikiria kupitia usanifu na maelezo ya utekelezaji.

Mfumo wa Mwingiliano (hapa unajulikana kama SV) ni mfumo uliosambazwa, unaostahimili hitilafu na uwasilishaji wa uhakika. SV imeundwa kama huduma ya upakiaji wa hali ya juu yenye uzani wa hali ya juu, inayopatikana kama huduma ya mtandaoni (inayotolewa na 1C) na kama bidhaa inayozalishwa kwa wingi ambayo inaweza kutumwa kwenye vifaa vyako vya seva.

SV hutumia hifadhi iliyosambazwa hazelcast na injini ya utafutaji Elasticsearch. Tutazungumza pia kuhusu Java na jinsi tunavyopanua PostgreSQL kwa usawa.
Jinsi na kwa nini tuliandika huduma ya upakiaji wa juu kwa 1C: Biashara: Java, PostgreSQL, Hazelcast

Taarifa ya tatizo

Ili kuifanya iwe wazi kwa nini tuliunda Mfumo wa Mwingiliano, nitakuambia kidogo kuhusu jinsi usanidi wa programu za biashara katika 1C unavyofanya kazi.

Kuanza, machache kutuhusu kwa wale ambao bado hawajui tunachofanya :) Tunatengeneza jukwaa la teknolojia la 1C:Enterprise. Jukwaa linajumuisha zana ya ukuzaji wa programu za biashara, na vile vile muda wa utekelezaji unaoruhusu programu za biashara kuendeshwa katika mazingira ya jukwaa tofauti.

Mtazamo wa ukuzaji wa seva ya mteja

Programu za biashara zilizoundwa kwenye 1C:Enterprise hufanya kazi katika ngazi tatu mteja-seva usanifu "DBMS - seva ya maombi - mteja". Nambari ya maombi iliyoandikwa ndani lugha iliyojengwa ndani ya 1C, inaweza kutekelezwa kwenye seva ya programu au kwa mteja. Kazi zote na vitu vya maombi (saraka, nyaraka, nk), pamoja na kusoma na kuandika database, hufanyika tu kwenye seva. Utendaji wa fomu na kiolesura cha amri pia hutekelezwa kwenye seva. Mteja hufanya kupokea, kufungua na kuonyesha fomu, "kuwasiliana" na mtumiaji (maonyo, maswali ...), mahesabu madogo katika fomu zinazohitaji majibu ya haraka (kwa mfano, kuzidisha bei kwa wingi), kufanya kazi na faili za ndani, kufanya kazi na vifaa.

Katika msimbo wa programu, vichwa vya taratibu na utendakazi lazima vionyeshe kwa uwazi mahali ambapo msimbo utatekelezwa - kwa kutumia &AtClient / &AtServer maagizo (&AtClient / &AtServer katika toleo la Kiingereza la lugha). Wasanidi wa 1C sasa watanirekebisha kwa kusema kwamba maagizo ni kweli zaidi ya, lakini kwa ajili yetu hii si muhimu sasa.

Unaweza kupiga msimbo wa seva kutoka kwa msimbo wa mteja, lakini huwezi kupiga msimbo wa mteja kutoka kwa msimbo wa seva. Hiki ni kikwazo cha kimsingi tulichoweka kwa sababu kadhaa. Hasa, kwa sababu msimbo wa seva lazima uandikwe kwa namna ambayo inatekeleza kwa njia sawa bila kujali inaitwa wapi - kutoka kwa mteja au kutoka kwa seva. Na katika kesi ya kupiga nambari ya seva kutoka kwa nambari nyingine ya seva, hakuna mteja kama huyo. Na kwa sababu wakati wa utekelezaji wa nambari ya seva, mteja aliyeiita anaweza kufunga, kutoka kwa programu, na seva haitakuwa na mtu wa kupiga simu tena.

Jinsi na kwa nini tuliandika huduma ya upakiaji wa juu kwa 1C: Biashara: Java, PostgreSQL, Hazelcast
Nambari inayoshughulikia kubofya kitufe: kuita utaratibu wa seva kutoka kwa mteja utafanya kazi, kuita utaratibu wa mteja kutoka kwa seva hautafanya

Hii inamaanisha kuwa ikiwa tunataka kutuma ujumbe fulani kutoka kwa seva hadi kwa programu ya mteja, kwa mfano, kwamba utayarishaji wa ripoti ya "muda mrefu" umekamilika na ripoti inaweza kutazamwa, hatuna njia kama hiyo. Lazima utumie hila, kwa mfano, mara kwa mara uchague seva kutoka kwa nambari ya mteja. Lakini mbinu hii hupakia mfumo na simu zisizohitajika, na kwa ujumla haionekani kifahari sana.

Na pia kuna haja, kwa mfano, simu inapofika SIP- unapopiga simu, ijulishe programu ya mteja kuhusu hili ili iweze kutumia nambari ya mpiga simu kuipata kwenye hifadhidata ya mshirika mwingine na kuonyesha maelezo ya mtumiaji kuhusu anayepiga simu. Au, kwa mfano, agizo linapofika kwenye ghala, julisha maombi ya mteja kuhusu hili. Kwa ujumla, kuna matukio mengi ambapo utaratibu huo ungekuwa muhimu.

Uzalishaji yenyewe

Unda utaratibu wa kutuma ujumbe. Haraka, ya kuaminika, na uwasilishaji wa uhakika, na uwezo wa kutafuta ujumbe kwa urahisi. Kulingana na utaratibu, tekeleza mjumbe (ujumbe, simu za video) inayoendeshwa ndani ya programu za 1C.

Tengeneza mfumo ili uweze kupanuka kwa usawa. Mzigo unaoongezeka lazima ufunikwa na kuongeza idadi ya nodes.

Utekelezaji

Tuliamua kutojumuisha sehemu ya seva ya SV moja kwa moja kwenye jukwaa la 1C:Enterprise, lakini kuitekeleza kama bidhaa tofauti, API yake ambayo inaweza kuitwa kutoka kwa msimbo wa suluhu za maombi ya 1C. Hii ilifanyika kwa sababu kadhaa, moja kuu ambayo nilitaka kufanya iwezekanavyo kubadilishana ujumbe kati ya maombi tofauti ya 1C (kwa mfano, kati ya Usimamizi wa Biashara na Uhasibu). Programu tofauti za 1C zinaweza kufanya kazi kwenye matoleo tofauti ya 1C: jukwaa la Biashara, liwe kwenye seva tofauti, nk. Katika hali kama hizi, utekelezaji wa SV kama bidhaa tofauti iko "upande" wa mitambo ya 1C ndio suluhisho bora.

Kwa hivyo, tuliamua kutengeneza SV kama bidhaa tofauti. Tunapendekeza kwamba makampuni madogo yatumie seva ya CB ambayo tulisakinisha katika wingu yetu (wss://1cdialog.com) ili kuepuka gharama za ziada zinazohusiana na usakinishaji wa ndani na usanidi wa seva. Wateja wakubwa wanaweza kuona inafaa kusakinisha seva yao ya CB kwenye vituo vyao. Tulitumia mbinu sawa katika bidhaa yetu ya SaaS ya wingu 1c safi - inatolewa kama bidhaa inayozalishwa kwa wingi kwa ajili ya ufungaji kwenye tovuti za wateja, na pia inatumika katika wingu letu. https://1cfresh.com/.

Programu

Ili kusambaza mzigo na uvumilivu wa kosa, hatutatumia programu moja ya Java, lakini kadhaa, na usawa wa mzigo mbele yao. Ikiwa unahitaji kuhamisha ujumbe kutoka nodi hadi nodi, tumia kuchapisha/kujisajili katika Hazelcast.

Mawasiliano kati ya mteja na seva ni kupitia websocket. Inafaa kwa mifumo ya wakati halisi.

Akiba iliyosambazwa

Tulichagua kati ya Redis, Hazelcast na Ehcache. Ni 2015. Redis ametoa kikundi kipya (mpya sana, cha kutisha), kuna Sentinel iliyo na vizuizi vingi. Ehcache hajui jinsi ya kukusanyika kwenye nguzo (utendaji huu ulionekana baadaye). Tuliamua kuijaribu na Hazelcast 3.4.
Hazelcast imekusanywa kwenye nguzo nje ya boksi. Katika hali ya node moja, sio muhimu sana na inaweza kutumika tu kama cache - haijui jinsi ya kutupa data kwenye diski, ikiwa unapoteza node pekee, unapoteza data. Tunasambaza Hazelcasts kadhaa, ambapo tunahifadhi data muhimu. Hatuhifadhi kashe - hatujali.

Kwa sisi, Hazelcast ni:

  • Uhifadhi wa vipindi vya watumiaji. Inachukua muda mrefu kwenda kwenye hifadhidata kwa kipindi kila wakati, kwa hivyo tunaweka vipindi vyote katika Hazelcast.
  • Akiba. Ikiwa unatafuta wasifu wa mtumiaji, angalia kashe. Aliandika ujumbe mpya - weka kwenye kashe.
  • Mada za mawasiliano kati ya matukio ya maombi. Nodi hutoa tukio na kuiweka katika mada ya Hazelcast. Nodi zingine za programu zilizojisajili kwa mada hii hupokea na kushughulikia tukio.
  • Kufuli za nguzo. Kwa mfano, tunaunda mjadala kwa kutumia ufunguo wa kipekee (majadiliano ya pekee ndani ya hifadhidata ya 1C):

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

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

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

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

Tulikagua kuwa hakuna chaneli. Tulichukua kufuli, tukaikagua tena, na tukaiunda. Ikiwa hutaangalia kufuli baada ya kuchukua kufuli, basi kuna uwezekano kwamba uzi mwingine pia uliangalia wakati huo na sasa utajaribu kuunda mjadala sawa - lakini tayari upo. Huwezi kufunga kwa kutumia Kufuli ya java iliyosawazishwa au ya kawaida. Kupitia hifadhidata - ni polepole, na ni huruma kwa hifadhidata; kupitia Hazelcast - ndivyo unahitaji.

Kuchagua DBMS

Tuna uzoefu wa kina na wenye mafanikio wa kufanya kazi na PostgreSQL na kushirikiana na wasanidi wa DBMS hii.

Si rahisi na nguzo ya PostgreSQL - ipo XL, XC, Citus, lakini kwa ujumla hizi sio NoSQL ambazo hutoka kwenye boksi. Hatukuzingatia NoSQL kama hifadhi kuu; ilitosha kwamba tulichukua Hazelcast, ambayo hatukuwa tumefanya nayo kazi hapo awali.

Ikiwa unahitaji kuongeza hifadhidata ya uhusiano, hiyo inamaanisha kugawanyika. Kama unavyojua, kwa sharding tunagawanya hifadhidata katika sehemu tofauti ili kila moja iweze kuwekwa kwenye seva tofauti.

Toleo la kwanza la ugawaji wetu lilichukua uwezo wa kusambaza kila jedwali la programu yetu kwenye seva tofauti kwa viwango tofauti. Kuna ujumbe mwingi kwenye seva A - tafadhali, hebu tuhamishe sehemu ya jedwali hili hadi kwenye seva B. Uamuzi huu ulipiga mayowe kuhusu uboreshaji wa mapema, kwa hivyo tuliamua kujiwekea kikomo kwa mbinu ya wapangaji wengi.

Unaweza kusoma juu ya wapangaji wengi, kwa mfano, kwenye wavuti Takwimu za Citus.

SV ina dhana ya maombi na mteja. Programu ni usakinishaji mahususi wa programu ya biashara, kama vile ERP au Uhasibu, iliyo na watumiaji wake na data ya biashara. Msajili ni shirika au mtu binafsi ambaye maombi yake yamesajiliwa katika seva ya SV. Msajili anaweza kuwa na programu kadhaa zilizosajiliwa, na programu hizi zinaweza kubadilishana ujumbe. Msajili akawa mpangaji katika mfumo wetu. Ujumbe kutoka kwa wanachama kadhaa unaweza kupatikana katika hifadhidata moja ya kimwili; ikiwa tunaona kwamba mteja ameanza kuzalisha trafiki nyingi, tunaihamisha kwenye hifadhidata tofauti ya kimwili (au hata seva tofauti ya hifadhidata).

Tuna hifadhidata kuu ambapo jedwali la uelekezaji huhifadhiwa na habari kuhusu eneo la hifadhidata zote za wasajili.

Jinsi na kwa nini tuliandika huduma ya upakiaji wa juu kwa 1C: Biashara: Java, PostgreSQL, Hazelcast

Ili kuzuia hifadhidata kuu kuwa kizuizi, tunaweka jedwali la uelekezaji (na data nyingine inayohitajika mara kwa mara) kwenye kache.

Ikiwa hifadhidata ya msajili itaanza kupungua, tutaikata katika sehemu za ndani. Kwenye miradi mingine tunayotumia pg_pathman.

Kwa kuwa kupoteza ujumbe wa mtumiaji ni mbaya, tunadumisha hifadhidata zetu na nakala. Mchanganyiko wa nakala za synchronous na asynchronous hukuruhusu kujihakikishia ikiwa utapoteza hifadhidata kuu. Upotezaji wa ujumbe utatokea tu ikiwa hifadhidata ya msingi na nakala yake iliyosawazishwa itashindwa kwa wakati mmoja.

Ikiwa nakala ya usawazishaji itapotea, nakala ya asynchronous inakuwa sawa.
Ikiwa hifadhidata kuu itapotea, nakala ya usawazishaji inakuwa hifadhidata kuu, na nakala ya asynchronous inakuwa nakala inayolingana.

Elasticsearch kwa utafutaji

Kwa kuwa, kati ya mambo mengine, SV pia ni mjumbe, inahitaji utafutaji wa haraka, rahisi na rahisi, kwa kuzingatia morphology, kwa kutumia mechi zisizo sahihi. Tuliamua kutoanzisha tena gurudumu na kutumia injini ya utafutaji isiyolipishwa ya Elasticsearch, iliyoundwa kulingana na maktaba Lucene. Pia tunapeleka Elasticsearch katika kundi (bwana - data - data) ili kuondoa matatizo katika tukio la kushindwa kwa nodes za maombi.

Kwenye github tulipata Programu-jalizi ya morphology ya Kirusi kwa Elasticsearch na uitumie. Katika faharisi ya Elasticsearch tunahifadhi mizizi ya maneno (ambayo programu-jalizi huamua) na N-gramu. Mtumiaji anapoingiza maandishi kutafuta, tunatafuta maandishi yaliyochapwa kati ya N-gramu. Likihifadhiwa kwenye faharasa, neno "maandishi" litagawanywa katika N-gramu zifuatazo:

[hizo, tek, tex, maandishi, maandishi, ek, ex, ext, maandishi, ks, kst, ksty, st, sty, wewe],

Na mzizi wa neno "maandishi" pia utahifadhiwa. Njia hii inakuwezesha kutafuta mwanzoni, katikati, na mwisho wa neno.

Picha ya jumla

Jinsi na kwa nini tuliandika huduma ya upakiaji wa juu kwa 1C: Biashara: Java, PostgreSQL, Hazelcast
Rudia picha tangu mwanzo wa kifungu, lakini kwa maelezo:

  • Balancer wazi kwenye mtandao; tuna nginx, inaweza kuwa yoyote.
  • Matukio ya programu ya Java huwasiliana kupitia Hazelcast.
  • Kufanya kazi na soketi ya wavuti tunayotumia Netty.
  • Programu ya Java imeandikwa katika Java 8 na ina vifurushi OSGi. Mipango hiyo ni pamoja na uhamiaji kwa Java 10 na mpito kwa moduli.

Maendeleo na majaribio

Katika mchakato wa kuunda na kujaribu SV, tuligundua idadi ya vipengele vya kuvutia vya bidhaa tunazotumia.

Upimaji wa mzigo na uvujaji wa kumbukumbu

Kutolewa kwa kila toleo la SV kunahusisha majaribio ya upakiaji. Inafanikiwa wakati:

  • Jaribio lilifanya kazi kwa siku kadhaa na hakukuwa na kushindwa kwa huduma
  • Muda wa kujibu kwa shughuli muhimu haukuzidi kizingiti cha starehe
  • Utendaji kuzorota ikilinganishwa na toleo la awali si zaidi ya 10%

Tunajaza hifadhidata ya majaribio na data - kufanya hivyo, tunapokea habari kuhusu mteja anayefanya kazi zaidi kutoka kwa seva ya uzalishaji, kuzidisha nambari zake na 5 (idadi ya ujumbe, majadiliano, watumiaji) na kuijaribu kwa njia hiyo.

Tunafanya upimaji wa mzigo wa mfumo wa mwingiliano katika usanidi tatu:

  1. mtihani wa dhiki
  2. Viunganisho pekee
  3. Usajili wa mteja

Wakati wa mtihani wa dhiki, tunazindua nyuzi mia kadhaa, na hupakia mfumo bila kuacha: kuandika ujumbe, kuunda majadiliano, kupokea orodha ya ujumbe. Tunaiga vitendo vya watumiaji wa kawaida (pata orodha ya ujumbe wangu ambao haujasomwa, mwandikie mtu) na suluhisho za programu (sambaza kifurushi cha usanidi tofauti, chakata arifa).

Kwa mfano, hivi ndivyo sehemu ya mtihani wa dhiki inavyoonekana:

  • Mtumiaji anaingia
    • Inaomba mijadala yako ambayo haijasomwa
    • Kuna uwezekano wa 50% kusoma ujumbe
    • 50% uwezekano wa kutuma maandishi
    • Mtumiaji anayefuata:
      • Ana nafasi ya 20% ya kuunda mjadala mpya
      • Nasibu huchagua yoyote ya majadiliano yake
      • Inaingia ndani
      • Inaomba ujumbe, wasifu wa mtumiaji
      • Huunda jumbe tano zinazoelekezwa kwa watumiaji nasibu kutoka kwa mjadala huu
      • Huacha mjadala
      • Rudia mara 20
      • Ingia nje, inarudi mwanzo wa hati

    • Chatbot inaingia kwenye mfumo (huiga ujumbe kutoka kwa msimbo wa programu)
      • Ana nafasi ya 50% ya kuunda kituo kipya cha kubadilishana data (majadiliano maalum)
      • Kuna uwezekano wa 50% kuandika ujumbe kwa chaneli zozote zilizopo

Hali ya "Viunganisho Pekee" ilionekana kwa sababu. Kuna hali: watumiaji wameunganisha mfumo, lakini bado hawajahusika. Kila mtumiaji huwasha kompyuta saa 09:00 asubuhi, huanzisha muunganisho kwenye seva na hukaa kimya. Vijana hawa ni hatari, kuna wengi wao - vifurushi pekee walivyo navyo ni PING/PONG, lakini huweka muunganisho kwenye seva (hawawezi kuiweka - vipi ikiwa kuna ujumbe mpya). Jaribio linazalisha hali ambapo idadi kubwa ya watumiaji hao hujaribu kuingia kwenye mfumo kwa nusu saa. Ni sawa na mtihani wa dhiki, lakini lengo lake ni kwa usahihi juu ya pembejeo hii ya kwanza - ili hakuna kushindwa (mtu haitumii mfumo, na tayari huanguka - ni vigumu kufikiria kitu kibaya zaidi).

Hati ya usajili wa mteja huanza kutoka kwa uzinduzi wa kwanza. Tulifanya mtihani wa dhiki na tulikuwa na uhakika kwamba mfumo haukupunguza kasi wakati wa mawasiliano. Lakini watumiaji walikuja na usajili ulianza kushindwa kwa sababu ya kuisha kwa muda. Wakati wa kusajili tulitumia / dev / bila mpangilio, ambayo inahusiana na entropy ya mfumo. Seva haikuwa na muda wa kukusanya entropy ya kutosha na wakati SecureRandom mpya ilipoombwa, iliganda kwa makumi ya sekunde. Kuna njia nyingi za kutoka kwa hali hii, kwa mfano: kubadili kwenye salama /dev/urandom isiyo salama, kufunga bodi maalum inayozalisha entropy, kuzalisha nambari za random mapema na kuzihifadhi kwenye bwawa. Tulifunga tatizo la hifadhi kwa muda, lakini tangu wakati huo tumekuwa tukifanya jaribio tofauti la kusajili wasajili wapya.

Tunatumia kama jenereta ya mzigo JMeter. Haijui jinsi ya kufanya kazi na websocket; inahitaji programu-jalizi. Ya kwanza katika matokeo ya utafutaji ya hoja "jmeter websocket" ni: makala kutoka BlazeMeter, ambayo inapendekeza programu-jalizi na Maciej Zaleski.

Hapo ndipo tulipoamua kuanza.

Karibu mara tu baada ya kuanza majaribio mazito, tuligundua kuwa JMeter ilianza kuvuja kumbukumbu.

Programu-jalizi ni hadithi kubwa tofauti; yenye nyota 176, ina uma 132 kwenye github. Mwandishi mwenyewe hajajitolea kwake tangu 2015 (tuliichukua mwaka wa 2015, basi haikuleta mashaka), masuala kadhaa ya github kuhusu uvujaji wa kumbukumbu, maombi 7 ya kuvuta ambayo hayajafungwa.
Ukiamua kufanya majaribio ya upakiaji kwa kutumia programu-jalizi hii, tafadhali zingatia mijadala ifuatayo:

  1. Katika mazingira yenye nyuzi nyingi, LinkedList ya kawaida ilitumiwa, na matokeo yake yalikuwa NPE katika wakati wa kukimbia. Hili linaweza kutatuliwa kwa kubadili hadi ConcurrentLinkedDeque au kwa vizuizi vilivyosawazishwa. Tulichagua chaguo la kwanza kwa sisi wenyewe (https://github.com/maciejzaleski/JMeter-WebSocketSampler/issues/43).
  2. Uvujaji wa kumbukumbu; wakati wa kukata, habari ya unganisho haijafutwa (https://github.com/maciejzaleski/JMeter-WebSocketSampler/issues/44).
  3. Katika hali ya utiririshaji (wakati soketi ya wavuti haijafungwa mwishoni mwa sampuli, lakini inatumiwa baadaye katika mpango), mifumo ya majibu haifanyi kazi (https://github.com/maciejzaleski/JMeter-WebSocketSampler/issues/19).

Hii ni moja ya zile kwenye github. Tulichofanya:

  1. Imechukua uma Elyran Kogan (@elyrank) - hurekebisha matatizo 1 na 3
  2. Kutatuliwa tatizo 2
  3. Gati iliyosasishwa kutoka 9.2.14 hadi 9.3.12
  4. Iliyofungwa SimpleDateFormat katika ThreadLocal; SimpleDateFormat sio salama kwa uzi, ambayo ilisababisha NPE wakati wa utekelezaji
  5. Imerekebisha uvujaji mwingine wa kumbukumbu (muunganisho ulifungwa vibaya wakati umekatika)

Na bado inapita!

Kumbukumbu ilianza kuisha si kwa siku moja, lakini kwa mbili. Hakukuwa na wakati uliobaki, kwa hivyo tuliamua kuzindua nyuzi chache, lakini kwa mawakala wanne. Hii inapaswa kuwa ya kutosha kwa angalau wiki.

Siku mbili zimepita...

Sasa Hazelcast inaishiwa na kumbukumbu. Magogo yalionyesha kuwa baada ya siku kadhaa za majaribio, Hazelcast alianza kulalamika juu ya ukosefu wa kumbukumbu, na baada ya muda nguzo hiyo ikaanguka, na nodi ziliendelea kufa moja baada ya nyingine. Tuliunganisha JVisualVM kwenye hazelcast na kuona "saha inayoinuka" - iliita GC mara kwa mara, lakini haikuweza kufuta kumbukumbu.

Jinsi na kwa nini tuliandika huduma ya upakiaji wa juu kwa 1C: Biashara: Java, PostgreSQL, Hazelcast

Ilibadilika kuwa katika hazelcast 3.4, wakati wa kufuta ramani / multiMap (map.destroy()), kumbukumbu haijaachiliwa kabisa:

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

Hitilafu sasa imerekebishwa katika 3.5, lakini ilikuwa shida wakati huo. Tuliunda Ramani nyingi mpya zenye majina yanayobadilika na tukayafuta kulingana na mantiki yetu. Nambari ilionekana kama hii:

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

Wito:

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

multiMap iliundwa kwa kila usajili na ilifutwa wakati haikuhitajika. Tuliamua kwamba tutaanzisha Ramani , ufunguo utakuwa jina la usajili, na maadili yatakuwa vitambulisho vya kikao (ambayo unaweza kupata vitambulisho vya mtumiaji, ikiwa ni lazima).

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

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

Chati zimeboreshwa.

Jinsi na kwa nini tuliandika huduma ya upakiaji wa juu kwa 1C: Biashara: Java, PostgreSQL, Hazelcast

Je, ni nini kingine tumejifunza kuhusu kupima mzigo?

  1. JSR223 inahitaji kuandikwa kwa groovy na kujumuisha kashe ya mkusanyiko - ni haraka zaidi. Kiungo.
  2. Grafu za Jmeter-Plugins ni rahisi kuelewa kuliko za kawaida. Kiungo.

Kuhusu uzoefu wetu na Hazelcast

Hazelcast ilikuwa bidhaa mpya kwetu, tulianza kufanya kazi nayo kutoka toleo la 3.4.1, sasa seva yetu ya uzalishaji inaendesha toleo la 3.9.2 (wakati wa kuandika, toleo la hivi karibuni la Hazelcast ni 3.10).

Uzalishaji wa kitambulisho

Tulianza na vitambulisho kamili. Wacha tufikirie kuwa tunahitaji Long kwa chombo kipya. Mlolongo katika hifadhidata haufai, meza zinahusika katika kugawanya - inageuka kuwa kuna ujumbe ID=1 katika DB1 na ID ya ujumbe = 1 katika DB2, huwezi kuweka kitambulisho hiki katika Elasticsearch, wala katika Hazelcast. , lakini jambo baya zaidi ni ikiwa unataka kuchanganya data kutoka kwa hifadhidata mbili hadi moja (kwa mfano, kuamua kuwa hifadhidata moja inatosha kwa wanachama hawa). Unaweza kuongeza AtomicLongs kadhaa kwa Hazelcast na kuweka kaunta hapo, kisha utendakazi wa kupata kitambulisho kipya ni ongezekoAndGet pamoja na wakati wa ombi kwa Hazelcast. Lakini Hazelcast ina kitu bora zaidi - FlakeIdGenerator. Wakati wa kuwasiliana na kila mteja, hupewa aina mbalimbali za kitambulisho, kwa mfano, moja ya kwanza - kutoka 1 hadi 10, pili - kutoka 000 hadi 10, nk. Sasa mteja anaweza kutoa vitambulisho vipya peke yake hadi safu iliyotolewa kwake iishe. Inafanya kazi haraka, lakini unapoanzisha tena programu (na mteja wa Hazelcast), mlolongo mpya huanza - kwa hivyo ruka, nk. Kwa kuongeza, wasanidi programu hawaelewi kwa nini vitambulisho ni kamili, lakini haviendani. Tulipima kila kitu na kubadili UUID.

Kwa njia, kwa wale ambao wanataka kuwa kama Twitter, kuna maktaba kama hiyo ya Snowcast - hii ni utekelezaji wa Snowflake juu ya Hazelcast. Unaweza kuitazama hapa:

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

Lakini hatujaifikia tena.

TransactionalMap.replace

Mshangao mwingine: TransactionalMap.replace haifanyi kazi. Huu hapa ni mtihani:

@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

Ilinibidi kuandika badala yangu kwa kutumia 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);
}

Jaribu sio tu miundo ya kawaida ya data, lakini pia matoleo yao ya shughuli. Inatokea kwamba IMap inafanya kazi, lakini TransactionalMap haipo tena.

Weka JAR mpya bila muda wa chini

Kwanza, tuliamua kurekodi vitu vya madarasa yetu huko Hazelcast. Kwa mfano, tuna darasa la Maombi, tunataka kuhifadhi na kuisoma. Hifadhi:

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

Читаеm:

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

Kila kitu kinafanya kazi. Kisha tuliamua kuunda faharisi huko Hazelcast kutafuta kwa:

map.addIndex("subscriberId", false);

Na wakati wa kuandika huluki mpya, walianza kupokea ClassNotFoundException. Hazelcast alijaribu kuongeza kwenye faharasa, lakini hakujua chochote kuhusu darasa letu na alitaka JAR yenye darasa hili itolewe kwake. Tulifanya hivyo, kila kitu kilifanya kazi, lakini shida mpya ilionekana: jinsi ya kusasisha JAR bila kuacha kabisa nguzo? Hazelcast haichukui JAR mpya wakati wa sasisho la nodi-kwa-nodi. Katika hatua hii tuliamua kwamba tunaweza kuishi bila kutafuta index. Baada ya yote, ikiwa unatumia Hazelcast kama duka la thamani kuu, basi kila kitu kitafanya kazi? Si kweli. Hapa tena tabia ya IMap na TransactionalMap ni tofauti. Ambapo IMap haijali, TransactionalMap hutupa hitilafu.

IMap. Tunaandika vitu 5000, tusome. Kila kitu kinatarajiwa.

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

Lakini haifanyi kazi katika shughuli, tunapata 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();
        }
    });
}

Mnamo 3.8, utaratibu wa Usambazaji wa Hatari ya Mtumiaji ulionekana. Unaweza kuteua nodi moja kuu na kusasisha faili ya JAR juu yake.

Sasa tumebadilisha kabisa mbinu yetu: tunaiweka sawa katika JSON na kuihifadhi katika Hazelcast. Hazelcast haihitaji kujua muundo wa madarasa yetu, na tunaweza kusasisha bila wakati wa kupumzika. Uchapishaji wa vipengee vya kikoa unadhibitiwa na programu. Matoleo tofauti ya programu yanaweza kufanya kazi kwa wakati mmoja, na hali inawezekana wakati programu mpya inaandika vitu na mashamba mapya, lakini ya zamani bado haijui kuhusu mashamba haya. Na wakati huo huo, programu mpya inasoma vitu vilivyoandikwa na programu ya zamani ambayo haina mashamba mapya. Tunashughulikia hali kama hizi ndani ya programu, lakini kwa unyenyekevu hatubadilishi au kufuta sehemu, tunapanua tu madarasa kwa kuongeza sehemu mpya.

Jinsi tunavyohakikisha utendaji wa juu

Safari nne kwenda Hazelcast - nzuri, mbili kwa hifadhidata - mbaya

Kwenda kwenye kache kwa data daima ni bora kuliko kwenda kwenye hifadhidata, lakini hutaki kuhifadhi rekodi ambazo hazijatumiwa pia. Tunaacha uamuzi kuhusu nini cha kuweka hadi hatua ya mwisho ya maendeleo. Wakati utendakazi mpya umewekwa msimbo, tunawasha kumbukumbu ya hoja zote katika PostgreSQL (log_min_duration_statement hadi 0) na kufanya jaribio la upakiaji kwa dakika 20. Kwa kutumia kumbukumbu zilizokusanywa, huduma kama pgFouine na pgBadger zinaweza kuunda ripoti za uchanganuzi. Katika ripoti, tunatafuta hoja za polepole na za mara kwa mara. Kwa hoja za polepole, tunaunda mpango wa utekelezaji (ELEZA) na kutathmini kama hoja kama hiyo inaweza kuharakishwa. Maombi ya mara kwa mara ya data sawa ya ingizo hutoshea vizuri kwenye akiba. Tunajaribu kuweka maswali "gorofa", meza moja kwa kila swali.

Unyonyaji

SV kama huduma ya mtandaoni ilianza kutumika katika chemchemi ya 2017, na kama bidhaa tofauti, SV ilitolewa mnamo Novemba 2017 (wakati huo katika hali ya toleo la beta).

Katika zaidi ya mwaka wa operesheni, kumekuwa hakuna matatizo makubwa katika uendeshaji wa huduma ya mtandaoni ya CB. Tunafuatilia huduma ya mtandaoni kupitia Zabbix, kukusanya na kupeleka kutoka Bamboo.

Usambazaji wa seva ya SV hutolewa kwa njia ya vifurushi asili: RPM, DEB, MSI. Pamoja na Windows tunatoa kisakinishi kimoja katika mfumo wa EXE moja ambayo husakinisha seva, Hazelcast na Elasticsearch kwenye mashine moja. Hapo awali tulirejelea toleo hili la usakinishaji kama toleo la "demo", lakini sasa imebainika kuwa hili ndilo chaguo maarufu zaidi la kusambaza.

Chanzo: mapenzi.com

Kuongeza maoni