Како и зашто смо написали скалабилну услугу великог оптерећења за 1Ц: Ентерприсе: Јава, ПостгреСКЛ, Хазелцаст

У овом чланку ћемо говорити о томе како и зашто смо се развили Интеракциони систем – механизам који преноси информације између клијентских апликација и 1Ц:Ентерприсе сервера – од постављања задатка до промишљања архитектуре и детаља имплементације.

Интеракциони систем (у даљем тексту СВ) је дистрибуирани систем за размену порука отпоран на грешке са гарантованом испоруком. СВ је дизајниран као услуга високог оптерећења са високом скалабилношћу, доступна и као онлајн услуга (обезбеђена од 1Ц) и као производ масовне производње који се може применити на сопственим серверским објектима.

СВ користи дистрибуирано складиште Хазелцаст и претраживач Еластицсеарцх. Такође ћемо говорити о Јави и о томе како хоризонтално скалирамо ПостгреСКЛ.
Како и зашто смо написали скалабилну услугу великог оптерећења за 1Ц: Ентерприсе: Јава, ПостгреСКЛ, Хазелцаст

Проблем статемент

Да би било јасно зашто смо креирали Интеракциони систем, рећи ћу вам мало о томе како функционише развој пословних апликација у 1Ц.

За почетак, мало о нама за оне који још не знају шта радимо :) Правимо технолошку платформу 1Ц:Ентерприсе. Платформа укључује алат за развој пословних апликација, као и рунтиме који омогућава да пословне апликације раде у вишеплатформском окружењу.

Парадигма развоја клијент-сервер

Пословне апликације креиране на 1Ц: Ентерприсе раде на три нивоа клијент-сервер архитектура „ДБМС – сервер апликација – клијент”. Код апликације уписан уграђени 1Ц језик, може се извршити на серверу апликација или на клијенту. Сав рад са објектима апликације (директорији, документи и сл.), као и читање и писање базе података, обавља се само на серверу. Функционалност форми и командног интерфејса је такође имплементирана на серверу. Клијент обавља пријем, отварање и приказивање формулара, „комуникацију“ са корисником (упозорења, питања...), мале калкулације у формуларима које захтевају брз одговор (нпр. множење цене са количином), рад са локалним фајловима, рад са опремом.

У коду апликације, заглавља процедура и функција морају експлицитно да назначе где ће се код извршавати – користећи &АтЦлиент / &АтСервер директиве (&АтЦлиент / &АтСервер у енглеској верзији језика). Програмери 1Ц ће ме сада исправити говорећи да су директиве заправо више од, али за нас то сада није важно.

Можете позвати серверски код из клијентског кода, али не можете позвати клијентски код из кода сервера. Ово је основно ограничење које смо направили из више разлога. Конкретно, зато што серверски код мора бити написан тако да се извршава на исти начин без обзира где се зове - са клијента или са сервера. А у случају позивања серверског кода са другог серверског кода, не постоји клијент као такав. И зато што је током извршавања кода сервера клијент који га је позвао могао да затвори, изађе из апликације и сервер више не би имао никога да позове.

Како и зашто смо написали скалабилну услугу великог оптерећења за 1Ц: Ентерприсе: Јава, ПостгреСКЛ, Хазелцаст
Код који управља кликом на дугме: позивање серверске процедуре са клијента ће радити, позивање клијентске процедуре са сервера неће

То значи да ако желимо да пошаљемо неку поруку са сервера клијентској апликацији, на пример, да је генерисање „дуготрајног” извештаја завршено и да се извештај може погледати, немамо такав метод. Морате користити трикове, на пример, периодично анкетирати сервер из клијентског кода. Али овај приступ оптерећује систем непотребним позивима и генерално не изгледа баш елегантно.

А постоји и потреба, на пример, када стигне телефонски позив СИП- када упућујете позив, обавестите клијентску апликацију о томе како би могла да користи број позиваоца да га пронађе у бази података друге стране и покаже кориснику информације о другој страни која позива. Или, на пример, када поруџбина стигне у складиште, обавестите клијентову апликацију о томе. Генерално, постоји много случајева у којима би такав механизам био користан.

Сама производња

Направите механизам за размену порука. Брз, поуздан, са гарантованом испоруком, са могућношћу флексибилне претраге порука. На основу механизма имплементирајте мессенгер (поруке, видео позиве) који ради унутар 1Ц апликација.

Дизајнирајте систем тако да буде хоризонтално скалабилан. Повећано оптерећење мора бити покривено повећањем броја чворова.

Имплементација

Одлучили смо да серверски део СВ-а не интегришемо директно у платформу 1Ц:Ентерприсе, већ да га имплементирамо као посебан производ, чији се АПИ може позвати из кода 1Ц апликативних решења. Ово је урађено из више разлога, од којих је главни био тај што сам желео да омогућим размену порука између различитих 1Ц апликација (на пример, између управљања трговином и рачуноводства). Различите 1Ц апликације могу да раде на различитим верзијама платформе 1Ц: Ентерприсе, да се налазе на различитим серверима итд. У таквим условима, имплементација СВ као засебног производа који се налази „са стране“ 1Ц инсталација је оптимално решење.

Дакле, одлучили смо да направимо СВ као посебан производ. Препоручујемо малим компанијама да користе ЦБ сервер који смо инсталирали у нашем облаку (всс://1цдиалог.цом) како би избегли режијске трошкове повезане са локалном инсталацијом и конфигурацијом сервера. Велики клијенти могу сматрати да је препоручљиво да инсталирају сопствени ЦБ сервер у својим објектима. Сличан приступ смо користили у нашем СааС производу у облаку 1цФресх – производи се као производ масовне производње за инсталацију на сајтовима клијената, а такође се примењује у нашем облаку https://1cfresh.com/.

апликација

Да бисмо распоредили оптерећење и толеранцију грешака, ми ћемо применити не једну Јава апликацију, већ неколико, са балансатором оптерећења испред њих. Ако треба да пренесете поруку са чвора на чвор, користите публисх/субсцрибе у Хазелцаст-у.

Комуникација између клијента и сервера је преко вебсоцкета. Погодан је за системе у реалном времену.

Дистрибуирани кеш

Бирали смо између Редис, Хазелцаст и Ехцацхе. 2015. је. Редис је управо објавио нови кластер (превише нов, застрашујући), постоји Сентинел са пуно ограничења. Ехцацхе не зна како да се састави у кластер (ова функционалност се појавила касније). Одлучили смо да пробамо са Хазелцаст 3.4.
Хазелцаст се склапа у кластер из кутије. У режиму са једним чвором, није много користан и може се користити само као кеш – не зна како да избацује податке на диск, ако изгубите једини чвор, губите податке. Ми примењујемо неколико Хазелцаст-ова, између којих правимо резервне копије критичних података. Не правимо резервну копију кеша – не смета нам.

За нас, Хазелцаст је:

  • Складиштење корисничких сесија. Потребно је много времена да се сваки пут иде у базу података за сесију, тако да смо све сесије ставили у Хазелцаст.
  • Цацхе. Ако тражите кориснички профил, проверите кеш меморију. Написао нову поруку - стави је у кеш.
  • Теме за комуникацију између инстанци апликације. Чвор генерише догађај и смешта га у тему Хазелцаст. Други апликациони чворови претплаћени на ову тему примају и обрађују догађај.
  • Кластер браве. На пример, креирамо дискусију користећи јединствени кључ (појединачна дискусија унутар 1Ц базе података):

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

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

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

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

Проверили смо да нема канала. Узели смо браву, поново је проверили и креирали. Ако не проверите закључавање након што сте га закључали, постоји шанса да је у том тренутку проверила и друга нит и да ће сада покушати да креира исту дискусију - али она већ постоји. Не можете закључати помоћу синхронизованог или редовног јава закључавања. Преко базе података - споро је и штета за базу података; преко Хазелцаст-а - то вам треба.

Избор ДБМС-а

Имамо велико и успешно искуство у раду са ПостгреСКЛ-ом и сарадњи са програмерима овог ДБМС-а.

Није лако са ПостгреСКЛ кластером - постоји XL, XC, Цитус, али генерално ово нису НоСКЛ-ови који се прилагођавају изван оквира. Нисмо сматрали НоСКЛ као главну меморију; било је довољно да смо узели Хазелцаст, са којим раније нисмо радили.

Ако треба да скалирате релациону базу података, то значи схадинг. Као што знате, помоћу шардовања базу података делимо на засебне делове тако да сваки од њих може да се постави на посебан сервер.

Прва верзија нашег шардинга је претпостављала могућност дистрибуције сваке од табела наше апликације на различитим серверима у различитим пропорцијама. Има много порука на серверу А – молим вас, преместимо део ове табеле на сервер Б. Ова одлука је једноставно вриштала о преурањеној оптимизацији, па смо одлучили да се ограничимо на приступ са више закупаца.

На пример, на веб локацији можете прочитати о мулти-станарима Цитус Дата.

СВ има концепте апликације и претплатника. Апликација је специфична инсталација пословне апликације, као што је ЕРП или Рачуноводство, са својим корисницима и пословним подацима. Претплатник је организација или појединац у чије име је апликација регистрована на СВ серверу. Претплатник може имати неколико регистрованих апликација и ове апликације могу међусобно да размењују поруке. Претплатник је постао закупац у нашем систему. Поруке од неколико претплатника могу се налазити у једној физичкој бази података; ако видимо да је претплатник почео да генерише много саобраћаја, премештамо га у засебну физичку базу података (или чак на посебан сервер базе података).

Имамо главну базу података у којој се чува табела рутирања са информацијама о локацији свих база података претплатника.

Како и зашто смо написали скалабилну услугу великог оптерећења за 1Ц: Ентерприсе: Јава, ПостгреСКЛ, Хазелцаст

Да бисмо спречили да главна база података буде уско грло, табелу рутирања (и друге често потребне податке) чувамо у кешу.

Ако база података претплатника почне да успорава, исећи ћемо је на партиције унутра. На другим пројектима које користимо пг_патхман.

Пошто је губитак корисничких порука лош, одржавамо наше базе података са репликама. Комбинација синхроне и асинхроне реплике омогућава вам да се осигурате у случају губитка главне базе података. Губитак поруке ће се десити само ако примарна база података и њена синхрона реплика не успеју истовремено.

Ако се синхрона реплика изгуби, асинхрона реплика постаје синхрона.
Ако се главна база података изгуби, синхрона реплика постаје главна база података, а асинхрона реплика постаје синхрона реплика.

Еластицсеарцх за претрагу

Пошто је, између осталог, СВ и месинџер, он захтева брзу, згодну и флексибилну претрагу, узимајући у обзир морфологију, користећи непрецизна подударања. Одлучили смо да не измишљамо точак и користимо бесплатни претраживач Еластицсеарцх, креиран на основу библиотеке Луцене. Такође примењујемо Еластицсеарцх у кластеру (мастер – подаци – подаци) да елиминишемо проблеме у случају квара апликационих чворова.

На гитхуб-у смо пронашли Руски додатак за морфологију за Еластицсеарцх и користите га. У Еластицсеарцх индексу чувамо корене речи (које додатак одређује) и Н-граме. Док корисник уноси текст за претрагу, тражимо укуцани текст међу Н-грамима. Када се сачува у индексу, реч „текстови“ ће бити подељена на следеће Н-граме:

[они, тек, текс, текст, текстови, ек, ек, ект, текстови, кс, кст, ксти, ст, сти, ти],

И корен речи „текст“ ће такође бити сачуван. Овај приступ вам омогућава да претражујете на почетку, у средини и на крају речи.

Генерал пицтуре

Како и зашто смо написали скалабилну услугу великог оптерећења за 1Ц: Ентерприсе: Јава, ПостгреСКЛ, Хазелцаст
Понављање слике са почетка чланка, али са објашњењима:

  • Балансер изложен на Интернету; имамо нгинк, може бити било који.
  • Инстанце Јава апликације комуницирају једна са другом преко Хазелцаст-а.
  • За рад са веб утичницом користимо Нетти.
  • Јава апликација је написана у Јави 8 и састоји се од пакета ОСГи. Планови укључују миграцију на Јаву 10 и прелазак на модуле.

Развој и тестирање

У процесу развоја и тестирања СВ-а, наишли смо на низ занимљивих карактеристика производа које користимо.

Тестирање оптерећења и цурење меморије

Издање сваког СВ издања укључује тестирање оптерећења. Успешан је када:

  • Тест је радио неколико дана и није било кварова на сервису
  • Време одговора за кључне операције није премашило удобан праг
  • Погоршање перформанси у односу на претходну верзију није више од 10%

Тестну базу попуњавамо подацима - да бисмо то урадили, добијамо информације о најактивнијем претплатнику са производног сервера, помножимо његове бројеве са 5 (број порука, дискусија, корисника) и тестирамо га на тај начин.

Тестирање оптерећења система интеракције вршимо у три конфигурације:

  1. Стрес тест
  2. Само везе
  3. Регистрација претплатника

Током стрес теста покрећемо неколико стотина нити, а оне учитавају систем без престанка: писање порука, креирање дискусија, примање листе порука. Симулирамо радње обичних корисника (добијем листу мојих непрочитаних порука, пишем некоме) и софтверска решења (преносимо пакет другачије конфигурације, обрађујемо упозорење).

На пример, овако изгледа део стрес теста:

  • Корисник се пријављује
    • Захтева ваше непрочитане дискусије
    • 50% вероватно ће читати поруке
    • 50% вероватноће да ће послати поруку
    • Следећи корисник:
      • Има 20% шансе да створи нову дискусију
      • Насумично бира било коју од својих дискусија
      • Улази унутра
      • Захтева поруке, корисничке профиле
      • Креира пет порука упућених насумичним корисницима из ове дискусије
      • Оставља дискусију
      • Понавља 20 пута
      • Одјављује се, враћа се на почетак скрипте

    • Цхатбот улази у систем (емулира поруке из кода апликације)
      • Има 50% шансе да створи нови канал за размену података (посебна дискусија)
      • 50% вероватно ће написати поруку на било који од постојећих канала

Сценарио „Само везе“ појавио се с разлогом. Постоји ситуација: корисници су повезали систем, али се још нису укључили. Сваки корисник укључује рачунар у 09:00 ујутру, успоставља везу са сервером и ћути. Ови момци су опасни, има их много - једини пакети које имају су ПИНГ/ПОНГ, али они одржавају везу са сервером (не могу да издрже - шта ако постоји нова порука). Тест репродукује ситуацију у којој велики број таквих корисника покушава да се пријави на систем за пола сата. Слично је стрес тесту, али му је фокус управо на овом првом уносу – да не би било кварова (човек не користи систем, а он већ пада – тешко је смислити нешто горе).

Скрипта за регистрацију претплатника почиње од првог покретања. Спровели смо стрес тест и били сигурни да систем није успорио током дописивања. Али корисници су дошли и регистрација је почела да не успева због истека времена. Приликом регистрације користили смо / дев / рандом, што је повезано са ентропијом система. Сервер није имао времена да акумулира довољно ентропије и када је затражен нови СецуреРандом, замрзнуо се на десетине секунди. Постоји много излаза из ове ситуације, на пример: пређите на мање безбедни /дев/урандом, инсталирајте посебну плочу која генерише ентропију, генерише насумичне бројеве унапред и складишти их у базену. Привремено смо затворили проблем са пулом, али од тада водимо посебан тест за регистрацију нових претплатника.

Користимо се као генератор оптерећења ЈМетер. Не зна како да ради са вебсоцкетом; потребан му је додатак. Први у резултатима претраге за упит „јметер вебсоцкет“ су: чланци са БлазеМетер-а, који препоручују додатак од Мациеја Залеског.

Одатле смо одлучили да почнемо.

Скоро одмах након почетка озбиљног тестирања, открили смо да је ЈМетер почео да цури меморија.

Додатак је посебна велика прича; са 176 звездица, има 132 виљушке на гитхубу. Сам аутор се није обавезао на то од 2015. (узели смо га 2015. године, тада није изазвало сумњу), неколико питања гитхуб-а у вези са цурењем меморије, 7 незатворених захтева за повлачење.
Ако одлучите да извршите тестирање оптерећења помоћу овог додатка, обратите пажњу на следеће дискусије:

  1. У окружењу са више нити, коришћена је обична ЛинкедЛист, а резултат је био НПЕ у времену извођења. Ово се може решити или преласком на ЦонцуррентЛинкедДекуе или синхронизованим блоковима. Изабрали смо прву опцију за себе (https://github.com/maciejzaleski/JMeter-WebSocketSampler/issues/43).
  2. Цурење меморије; приликом прекида везе, информације о вези се не бришу (https://github.com/maciejzaleski/JMeter-WebSocketSampler/issues/44).
  3. У режиму стримовања (када веб соцкет није затворен на крају узорка, већ се користи касније у плану), обрасци одговора не раде (https://github.com/maciejzaleski/JMeter-WebSocketSampler/issues/19).

Ово је један од оних на гитхуб-у. Шта смо урадили:

  1. Су узели виљушка Елиран Коган (@елиранк) – решава проблеме 1 и 3
  2. Решен проблем 2
  3. Ажуриран пристаниште са 9.2.14 на 9.3.12
  4. Умотан СимплеДатеФормат у ТхреадЛоцал; СимплеДатеФормат није безбедан за нити, што је довело до НПЕ током извршавања
  5. Поправљено још једно цурење меморије (веза је била погрешно затворена када је прекинута)

А ипак тече!

Памћење је почело да понестаје не за дан, већ за два. Апсолутно није преостало времена, па смо одлучили да покренемо мање нити, али на четири агента. Ово је требало да буде довољно за најмање недељу дана.

Прошла су два дана...

Сада Хазелцасту понестаје меморије. Дневници су показали да је након неколико дана тестирања Хазелцаст почео да се жали на недостатак меморије, а након неког времена кластер се распао, а чворови су наставили да умиру један по један. Повезали смо ЈВисуалВМ на хазелцаст и видели „тестеру у успону“ – редовно је звала ГЦ, али није могла да обрише меморију.

Како и зашто смо написали скалабилну услугу великог оптерећења за 1Ц: Ентерприсе: Јава, ПостгреСКЛ, Хазелцаст

Испоставило се да у хазелцаст 3.4, приликом брисања мапе / мултиМап (мап.дестрои()), меморија није потпуно ослобођена:

гитхуб.цом/хазелцаст/хазелцаст/иссуес/6317
гитхуб.цом/хазелцаст/хазелцаст/иссуес/4888

Грешка је сада исправљена у верзији 3.5, али је тада била проблем. Направили смо нове мултиМапе са динамичким именима и избрисали их према нашој логици. Код је изгледао отприлике овако:

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

Позовите:

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

мултиМап је креиран за сваку претплату и обрисан када није био потребан. Одлучили смо да покренемо Мапу , кључ ће бити назив претплате, а вредности ће бити идентификатори сесије (од којих онда можете добити идентификаторе корисника, ако је потребно).

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

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

Графикони су се побољшали.

Како и зашто смо написали скалабилну услугу великог оптерећења за 1Ц: Ентерприсе: Јава, ПостгреСКЛ, Хазелцаст

Шта смо још научили о тестирању оптерећења?

  1. ЈСР223 треба да буде написан у гроови-у и да укључи кеш компилације - много је бржи. Линк.
  2. Јметер-Плугинс графикони су лакши за разумевање од стандардних. Линк.

О нашем искуству са Хазелцастом

Хазелцаст је био нови производ за нас, почели смо да радимо са њим од верзије 3.4.1, сада наш производни сервер ради на верзији 3.9.2 (у време писања, најновија верзија Хазелцаст-а је 3.10).

Генерисање ИД-а

Почели смо са целобројним идентификаторима. Замислимо да нам је потребан још један Лонг за нови ентитет. Секвенца у бази података није прикладна, табеле су укључене у сердинг - испоставило се да постоји порука ИД=1 у ДБ1 и порука ИД=1 у ДБ2, не можете ставити овај ИД у Еластицсеарцх, нити у Хазелцаст , али најгоре је ако желите да комбинујете податке из две базе у једну (на пример, одлучите да је једна база довољна за ове претплатнике). Можете додати неколико АтомицЛонгова у Хазелцаст и задржати бројач тамо, тада је учинак добијања новог ИД-а инцрементАндГет плус време за захтев за Хазелцаст. Али Хазелцаст има нешто оптималније - ФлакеИдГенератор. Приликом контактирања сваког клијента добијају распон ИД-а, на пример, први – од 1 до 10, други – од 000 до 10 и тако даље. Сада клијент може сам да издаје нове идентификаторе док се не заврши опсег који му се издаје. Ради брзо, али када поново покренете апликацију (и Хазелцаст клијент), почиње нова секвенца - дакле прескакања итд. Поред тога, програмери заправо не разумеју зашто су ИД-ови целобројни, али су толико недоследни. Све смо одмерили и прешли на УУИД.

Узгред, за оне који желе да буду као Твитер, постоји таква Сновцаст библиотека - ово је имплементација Сновфлаке-а на врху Хазелцаст-а. Можете га погледати овде:

гитхуб.цом/ноцтариус/сновцаст
гитхуб.цом/твиттер/сновфлаке

Али нисмо више стигли до тога.

ТрансацтионалМап.реплаце

Још једно изненађење: ТрансацтионалМап.реплаце не ради. Ево теста:

@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

Морао сам да напишем сопствену замену користећи гетФорУпдате:

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

Тестирајте не само обичне структуре података, већ и њихове трансакционе верзије. Дешава се да ИМАп ради, али ТрансацтионалМап више не постоји.

Уметните нови ЈАР без застоја

Прво смо одлучили да снимимо предмете наших часова у Хазелцасту. На пример, имамо класу Апплицатион, желимо да је сачувамо и прочитамо. Сачувати:

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

Читамо:

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

Све ради. Затим смо одлучили да направимо индекс у Хазелцаст-у за претрагу према:

map.addIndex("subscriberId", false);

И када су писали нови ентитет, почели су да примају ЦлассНотФоундЕкцептион. Хазелцаст је покушао да дода индексу, али није знао ништа о нашој класи и желео је да јој се достави ЈАР са овом класом. Управо смо то урадили, све је функционисало, али се појавио нови проблем: како ажурирати ЈАР без потпуног заустављања кластера? Хазелцаст не преузима нови ЈАР током ажурирања чвор по чвор. У овом тренутку смо одлучили да можемо да живимо без претраживања индекса. На крају крајева, ако користите Хазелцаст као складиште кључ-вредност, онда ће све радити? Не баш. И овде је понашање ИМАп-а и ТрансацтионалМап-а другачије. Тамо где ИМАп није стало, ТрансацтионалМап даје грешку.

ИМАп. Напишемо 5000 објеката, прочитамо их. Све је очекивано.

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

Али то не ради у трансакцији, добијамо ЦлассНотФоундЕкцептион:

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

У верзији 3.8 појавио се механизам за постављање класе корисника. Можете одредити један главни чвор и ажурирати ЈАР датотеку на њему.

Сада смо потпуно променили наш приступ: сами га серијализујемо у ЈСОН и чувамо у Хазелцаст-у. Хазелцаст не мора да зна структуру наших класа и можемо да ажурирамо без застоја. Апликација контролише верзију објеката домена. Различите верзије апликације могу да раде истовремено, а могућа је ситуација да нова апликација уписује објекте са новим пољима, али стара још не зна за та поља. И у исто време, нова апликација чита објекте које је написала стара апликација који немају нова поља. Такве ситуације решавамо унутар апликације, али због једноставности не мењамо и не бришемо поља, већ само проширујемо класе додавањем нових поља.

Како обезбеђујемо високе перформансе

Четири путовања у Хазелцаст - добро, два у базу података - лоше

Одлазак у кеш за податке је увек бољи од одласка у базу података, али не желите ни да чувате неискоришћене записе. Одлуку о томе шта кеширати остављамо до последње фазе развоја. Када је нова функционалност кодирана, укључујемо евидентирање свих упита у ПостгреСКЛ-у (лог_мин_дуратион_статемент на 0) и покрећемо тестирање оптерећења у трајању од 20 минута. Користећи прикупљене евиденције, услужни програми као што су пгФоуине и пгБадгер могу да праве аналитичке извештаје. У извештајима првенствено тражимо споре и честе упите. За споре упите градимо план извршења (ЕКСПЛАИН) и процењујемо да ли се такав упит може убрзати. Чести захтеви за истим улазним подацима добро се уклапају у кеш меморију. Трудимо се да упити буду „равни“, једна табела по упиту.

Операција

СВ као онлајн сервис пуштен је у рад у пролеће 2017. године, а као посебан производ, СВ је пуштен у продају у новембру 2017. (у то време у статусу бета верзије).

За више од годину дана рада није било озбиљнијих проблема у раду ЦБ онлајн сервиса. Пратимо онлајн услугу преко Заббик, прикупити и применити из бамбус.

Дистрибуција СВ сервера се испоручује у облику изворних пакета: РПМ, ДЕБ, МСИ. Плус за Виндовс нудимо један инсталатер у облику једног ЕКСЕ-а који инсталира сервер, Хазелцаст и Еластицсеарцх на једној машини. Првобитно смо ову верзију инсталације назвали „демо“ верзијом, али је сада постало јасно да је ово најпопуларнија опција постављања.

Извор: ввв.хабр.цом

Додај коментар