1C: Enterprise: Java, PostgreSQL, Hazelcast үчүн жогорку жүктөмдүү масштабдуу кызматты кантип жана эмне үчүн жаздык

Бул макалада биз кантип жана эмне үчүн иштелип чыккандыгы жөнүндө сүйлөшөбүз Өз ара аракеттенүү системасы – кардар тиркемелери менен 1C: Enterprise серверлеринин ортосунда маалыматты өткөрүп берүүчү механизм - тапшырма коюудан баштап архитектура жана ишке ашыруунун деталдары аркылуу ойлонууга чейин.

Өз ара аракеттенүү системасы (мындан ары - SV) - кепилденген жеткирүү менен бөлүштүрүлгөн, каталарга чыдамдуу билдирүү системасы. SV онлайн кызматы (1С тарабынан берилген) жана өзүңүздүн сервердик жайларыңызга жайылтууга мүмкүн болгон массалык түрдө өндүрүлгөн продукт катары да жеткиликтүү, масштабдуулугу жогору, жогорку жүктөмдүү кызмат катары иштелип чыккан.

SV бөлүштүрүлгөн сактагычты колдонот hazelcast жана издөө системасы ElasticSearch. Биз ошондой эле Java жөнүндө жана PostgreSQLди горизонталдуу масштабда кантип кеңейтебиз.
1C: Enterprise: Java, PostgreSQL, Hazelcast үчүн жогорку жүктөмдүү масштабдуу кызматты кантип жана эмне үчүн жаздык

Тапшырманын коюлушу

Эмне үчүн өз ара аракеттенүү тутумун жаратканыбызды түшүнүү үчүн, мен 1Сте бизнес тиркемелерди иштеп чыгуу кандайча иштээри жөнүндө бир аз айтып берем.

Баштоо үчүн, эмне кылаарыбызды билбегендер үчүн биз жөнүндө бир аз :) Биз 1С: Enterprise технологиялык платформасын жасап жатабыз. Платформа бизнес тиркемелерин иштеп чыгуу куралын, ошондой эле бизнес тиркемелерин платформалар аралык чөйрөдө иштетүүгө мүмкүндүк берген иштөө убактысын камтыйт.

Кардар-сервер өнүктүрүү парадигмасы

1С: Enterpriseде түзүлгөн бизнес тиркемелер үч деңгээлде иштейт кардар-сервер архитектурасы «МБС – колдонмо сервери – кардар». Колдонмонун коду жазылган камтылган 1С тили, колдонмо серверинде же кардарда аткарылышы мүмкүн. Колдонмо объекттери (каталогдор, документтер ж.б.) менен бардык иштер, ошондой эле маалымат базасын окуу жана жазуу серверде гана аткарылат. Формалардын функционалдуулугу жана командалык интерфейс да серверде ишке ашырылат. Кардар формаларды кабыл алууну, ачууну жана көрсөтүүнү, колдонуучу менен “байланышты” (эскертүү, суроолор...), тез жооп берүүнү талап кылган формалардагы чакан эсептөөлөрдү (мисалы, бааны санга көбөйтүү), локалдык файлдар менен иштөөнү, жабдуулар менен иштөө.

Колдонмо кодунда процедуралардын жана функциялардын аталыштары коддун кайсы жерде аткарыла турганын ачык көрсөтүшү керек - &AtClient / &AtServer директивалары (&AtClient / &AtServer тилдин англис версиясында). 1C иштеп чыгуучулары эми директивалар чындыгында бар деп мени оңдошот көп, бирок биз үчүн бул азыр маанилүү эмес.

Сиз кардар кодунан сервер кодун чакыра аласыз, бирок сервер кодунан кардар кодун чакыра албайсыз. Бул биз бир нече себептерден улам негизги чектөө болуп саналат. Атап айтканда, сервердин коду, ал кайсы жерде чакырылбасын - кардардан же серверден бирдей аткарыла тургандай жазылышы керек. Ал эми сервер кодун башка сервердик коддон чакырган учурда, андай кардар жок. Ал эми сервердик коддун аткарылышы учурунда, аны чакырган кардар жабылып, тиркемеден чыгып кетиши мүмкүн жана серверде чалууга эч ким калбай калат.

1C: Enterprise: Java, PostgreSQL, Hazelcast үчүн жогорку жүктөмдүү масштабдуу кызматты кантип жана эмне үчүн жаздык
Баскычты басууну иштеткен код: серверден сервер процедурасын чакыруу иштейт, серверден кардар процедурасын чакыруу иштебейт

Демек, эгерде биз серверден кардар тиркемесине кандайдыр бир билдирүү жөнөткүбүз келсе, мисалы, "узак мөөнөттүү" отчетту түзүү аяктады жана отчетту көрүүгө болот, бизде мындай ыкма жок. Сиз трюктарды колдонушуңуз керек, мисалы, серверди кардар кодунан мезгил-мезгили менен сурамжылоо. Бирок бул ыкма системаны керексиз чалуулар менен жүктөйт жана жалпысынан өтө эле жарашыктуу көрүнбөйт.

Жана ошондой эле муктаждык бар, мисалы, телефон чалуу келгенде SIP- чалуу учурунда, бул тууралуу кардар тиркемесин кабарлаңыз, ал чалуучунун номерин контрагенттин маалымат базасынан таап, колдонуучуга чалып жаткан контрагент жөнүндө маалыматты көрсөтө алат. Же болбосо, мисалы, кампага заказ келгенде, бул тууралуу кардардын кардардын арызына билдириңиз. Негизинен мындай механизм пайдалуу боло турган учурлар көп.

Өндүрүштүн өзү

Кабарлашуу механизмин түзүү. Тез, ишенимдүү, кепилденген жеткирүү, билдирүүлөрдү ийкемдүү издөө мүмкүнчүлүгү менен. Механизмдин негизинде 1С тиркемелеринин ичинде иштеген мессенджерди (билдирүүлөрдү, видео чалууларды) ишке ашырыңыз.

Тутумду горизонталдуу масштабдуу кылып долбоорлоңуз. Көбөйүп жаткан жүк түйүндөрдүн санын көбөйтүү менен жабылышы керек.

Реализация

Биз SV сервердик бөлүгүн түздөн-түз 1C: Enterprise платформасына интеграциялоону чечтик, бирок аны өзүнчө продукт катары ишке ашырууну чечтик, анын API'син 1С колдонмо чечимдеринин кодунан чакырса болот. Бул бир нече себептерден улам жасалды, алардын эң негизгиси, мен ар кандай 1С тиркемелеринин ортосунда (мисалы, Соода менеджменти менен Бухгалтердик эсептин ортосунда) билдирүүлөрдү алмашууга мүмкүндүк бергим келди. Ар кандай 1С тиркемелери 1C: Enterprise платформасынын ар кандай версияларында иштей алат, ар кандай серверлерде жайгаша алат ж.б. Мындай шарттарда, SV 1C орнотуулардын "капталында" жайгашкан өзүнчө продукт катары ишке ашыруу оптималдуу чечим болуп саналат.

Ошентип, биз SV өзүнчө продукт катары жасоону чечтик. Биз чакан компанияларга серверди жергиликтүү орнотууга жана конфигурациялоого байланыштуу кошумча чыгымдарды болтурбоо үчүн булутубузга орноткон CB серверин колдонууну сунуштайбыз (wss://1cdialog.com). Ири кардарларга өздөрүнүн CB серверин өз объектилерине орнотууну туура көрүшү мүмкүн. Булуттагы SaaS продуктусунда ушундай ыкманы колдондук 1cFresh - ал кардарлардын сайттарында орнотуу үчүн массалык түрдө өндүрүлгөн продукт катары өндүрүлгөн, ошондой эле биздин булутта жайгаштырылган https://1cfresh.com/.

арыз

Жүктөлүштү жана катага чыдамдуулукту бөлүштүрүү үчүн, биз бир Java тиркемесин эмес, алардын алдында жүк баланстоочу менен бир нечесин орнотобуз. Эгер сиз билдирүүнү түйүндөн түйүнгө өткөрүшүңүз керек болсо, Hazelcast'та жарыялоо/жазылууну колдонуңуз.

Кардар менен сервердин ортосундагы байланыш websocket аркылуу болот. Бул реалдуу убакыт системалары үчүн абдан ылайыктуу.

Бөлүштүрүлгөн кэш

Биз Redis, Hazelcast жана Ehcache ортосунда тандадык. 2015-жыл. Redis жаңы кластерди чыгарды (өтө жаңы, коркунучтуу), көптөгөн чектөөлөрү бар Sentinel бар. Ehcache кластерге кантип чогултулууну билбейт (бул функция кийинчерээк пайда болгон). Биз аны Hazelcast 3.4 менен сынап көрүүнү чечтик.
Hazelcast кутудан бир кластерге чогултулган. Жалгыз түйүн режиминде ал анчалык деле пайдалуу эмес жана кэш катары гана колдонулушу мүмкүн - ал дискке маалыматты кантип таштоону билбейт, эгер жалгыз түйүн жоголсо, анда берилиштер жоголот. Биз бир нече Hazelcasts орнотобуз, алардын ортосунда маанилүү маалыматтардын камдык көчүрмөсүн сактайбыз. Биз кэштин камдык көчүрмөсүн сактабайбыз - ага каршы эмеспиз.

Биз үчүн, Hazelcast болуп саналат:

  • Колдонуучу сеанстарды сактоо. Ар бир жолу сеанс үчүн маалымат базасына баруу көп убакытты талап кылат, ошондуктан биз бардык сессияларды Hazelcast'ке койдук.
  • Кэш. Эгер сиз колдонуучу профилин издеп жатсаңыз, кэшти текшериңиз. Жаңы билдирүү жазды - кэшке салыңыз.
  • Колдонмо инстанцияларынын ортосундагы байланыш үчүн темалар. Түйүн окуяны жаратат жана аны Hazelcast темасына жайгаштырат. Бул темага жазылган башка тиркеме түйүндөрү окуяны кабыл алып, иштетет.
  • Кластер кулпулары. Мисалы, биз уникалдуу ачкычтын жардамы менен талкуу түзөбүз (1С базасындагы синглтондук талкуу):

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

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

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

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

Канал жок экенин текшердик. Кулпуну алып, кайра текшерип, түздүк. Эгерде сиз кулпуну алгандан кийин кулпуну текшербесеңиз, анда башка жип дагы ошол учурда текшерилип, азыр ошол эле талкууну түзүүгө аракет кылышы мүмкүн - бирок ал мурунтан эле бар. Сиз шайкештештирилген же кадимки java Lock аркылуу кулпулай албайсыз. Маалыматтар базасы аркылуу - бул жай жана маалымат базасы үчүн өкүнүчтүү; Hazelcast аркылуу - бул сизге керек.

DBMS тандоо

Бизде PostgreSQL менен иштөө жана бул DBMS иштеп чыгуучулары менен кызматташуу боюнча кеңири жана ийгиликтүү тажрыйбабыз бар.

PostgreSQL кластери менен бул оңой эмес - бар XL, XC, Citus, бирок жалпысынан булар кутудан чыга турган NoSQL эмес. Биз NoSQLди негизги сактагыч деп эсептеген жокпуз; биз буга чейин иштебеген Hazelcastти алганыбыз жетиштүү болду.

Эгер сиз реляциялык маалымат базасын масштабдашыңыз керек болсо, бул дегенди билдирет бөлүү. Белгилүү болгондой, sharding менен биз маалымат базасын өзүнчө бөлүктөргө бөлүп, алардын ар бири өзүнчө серверге жайгаштырылышы мүмкүн.

Шардингибиздин биринчи версиясы биздин тиркеменин ар бир таблицасын ар кандай пропорцияларда ар кандай серверлер боюнча жайылтуу мүмкүнчүлүгүн алды. А серверинде көптөгөн билдирүүлөр бар - сураныч, бул таблицанын бир бөлүгүн В серверине көчүрөлү. Бул чечим жөн гана мөөнөтүнөн мурда оптималдаштыруу жөнүндө кыйкырды, ошондуктан биз өзүбүздү көп ижарачылардын ыкмасы менен чектөөнү чечтик.

Сиз көп ижарачы жөнүндө окуй аласыз, мисалы, веб-сайттан Citus Data.

SV колдонмо жана абонент түшүнүктөрү бар. Тиркеме – бул ERP же Бухгалтердик эсеп сыяктуу бизнес тиркемесин анын колдонуучулары жана бизнес маалыматтары менен атайын орнотуу. Абонент - бул SV серверинде анын атынан тиркеме катталган уюм же жеке жак. Абонентте бир нече тиркемелер катталган болушу мүмкүн жана бул тиркемелер бири-бири менен кабар алмаша алышат. Абонент биздин системада ижарачы болуп калды. Бир нече абоненттердин билдирүүлөрү бир физикалык маалымат базасында жайгаштырылышы мүмкүн; эгер биз абоненттин көп трафикти генерациялай баштаганын көрсөк, биз аны өзүнчө физикалык маалымат базасына (же өзүнчө маалымат базасы серверине) жылдырабыз.

Бизде негизги маалымат базасы бар, анда бардык абоненттик маалымат базаларынын жайгашкан жери жөнүндө маалымат менен маршруттук таблица сакталат.

1C: Enterprise: Java, PostgreSQL, Hazelcast үчүн жогорку жүктөмдүү масштабдуу кызматты кантип жана эмне үчүн жаздык

Негизги маалымат базасы тоскоолдук болуп калбашы үчүн, биз маршруттук таблицаны (жана башка көп керектүү маалыматтарды) кэште сактайбыз.

Абоненттин маалымат базасы жайлай баштаса, биз аны ичиндеги бөлүктөргө кесип салабыз. Башка долбоорлор боюнча биз колдонобуз pg_pathman.

Колдонуучунун билдирүүлөрүн жоготуу жаман болгондуктан, биз маалымат базаларыбызды репликалар менен сактайбыз. Синхрондук жана асинхрондук репликалардын айкалышы негизги маалымат базасы жоголгон учурда өзүңүздү камсыздандырууга мүмкүндүк берет. Эгерде негизги маалымат базасы жана анын синхрондуу репликасы бир убакта иштебей калса, билдирүү жоголот.

Эгерде синхрондуу реплика жоголсо, асинхрондуу реплика синхрондуу болуп калат.
Негизги маалымат базасы жоголсо, синхрондуу реплика негизги маалымат базасына, ал эми асинхрондуу реплика синхрондуу репликага айланат.

Издөө үчүн Elasticsearch

Башка нерселер менен катар SV да кабарчы болгондуктан, морфологияны эске алуу менен, так эмес дал келүүлөрдү колдонуу менен тез, ыңгайлуу жана ийкемдүү издөөнү талап кылат. Биз дөңгөлөктү кайра ойлоп таппоону жана китепкананын негизинде түзүлгөн Elasticsearch бекер издөө системасын колдонбоону чечтик Lucene. Колдонмо түйүндөрүнүн иштебей калышына байланыштуу көйгөйлөрдү жоюу үчүн биз Elasticsearchти кластерде (мастер – маалыматтар – маалыматтар) жайгаштырабыз.

Githubдан биз таптык Орус морфология плагини Elasticsearch үчүн жана аны колдонуңуз. Elasticsearch индексинде биз сөздүн тамырларын (плагин аныктаган) жана N-граммдарды сактайбыз. Колдонуучу издөө үчүн текстти киргизгенде, терилген текстти N-граммдардын арасынан издейбиз. Индекске сакталганда, "тексттер" сөзү төмөнкү N-граммдарга бөлүнөт:

[ошол, тек, текс, текст, тексттер, ek, ex, ext, texts, ks, kst, ksty, st, sty, you],

Ал эми «текст» деген сөздүн уңгусу да сакталып калат. Бул ыкма сөздүн башында, ортосунда жана аягында издөөгө мүмкүндүк берет.

Чоң Сүрөт

1C: Enterprise: Java, PostgreSQL, Hazelcast үчүн жогорку жүктөмдүү масштабдуу кызматты кантип жана эмне үчүн жаздык
Макаланын башынан тартып сүрөттү кайталаңыз, бирок түшүндүрмөлөр менен:

  • Балансатор Интернетте ачыкка чыгат; бизде nginx бар, ал каалаган болушу мүмкүн.
  • Java колдонмо инстанциялары бири-бири менен Hazelcast аркылуу байланышат.
  • Веб розетка менен иштөө үчүн биз колдонобуз Нетти.
  • Java тиркемеси Java 8де жазылган жана таңгактардан турат OSGi. Пландар Java 10го көчүүнү жана модулдарга өтүүнү камтыйт.

Иштеп чыгуу жана тестирлөө

SV иштеп чыгуу жана сыноо процессинде биз колдонгон продукциянын бир катар кызыктуу өзгөчөлүктөрүнө туш болдук.

Жүктөлгөн сыноо жана эс тутумдун агып кетиши

Ар бир SV релизинин релизинде жүктөмдү текшерүү кирет. Ал төмөнкү учурларда ийгиликтүү болот:

  • Сыноо бир нече күн иштеди жана эч кандай кызматта мүчүлүштүктөр болгон жок
  • Негизги операцияларга жооп берүү убактысы ыңгайлуу босогодон ашкан жок
  • Мурунку версияга салыштырмалуу майнаптуулуктун начарлашы 10% дан ашпайт

Биз тесттик базаны маалыматтар менен толтурабыз – бул үчүн өндүрүш серверинен эң активдүү абонент тууралуу маалымат алабыз, анын сандарын 5ке көбөйтөбүз (билдирүүлөрдүн, талкуулардын, колдонуучулардын саны) жана аны ушундай жол менен сынайбыз.

Биз үч конфигурацияда өз ара аракеттенүү тутумунун жүктөмдүгүн текшерүүнү жүргүзөбүз:

  1. стресс тест
  2. Туташуулар гана
  3. Абонентти каттоо

Стресс-тест учурунда биз бир нече жүз жипти ишке киргизебиз, алар системаны токтобой жүктөйт: билдирүүлөрдү жазуу, талкууларды түзүү, билдирүүлөрдүн тизмесин алуу. Биз жөнөкөй колдонуучулардын аракеттерин (окула элек билдирүүлөрүмдүн тизмесин алуу, кимдир бирөөгө жаз) жана программалык чечимдерди (башка конфигурациядагы пакетти өткөрүп берүү, эскертүүнү иштетүү) окшоштурабыз.

Мисалы, стресс-тесттин бир бөлүгү мындай көрүнөт:

  • Колдонуучу кирет
    • Окула элек талкууларыңызды сурайт
    • 50% билдирүүлөрдү окуйт
    • 50% текст жөнөтүшү мүмкүн
    • Кийинки колдонуучу:
      • Жаңы талкуу жаратууга 20% мүмкүнчүлүгү бар
      • Анын каалаган талкуусун туш келди тандайт
      • Ичине кирет
      • Билдирүүлөрдү, колдонуучунун профилдерин сурайт
      • Бул талкуудан туш келди колдонуучуларга беш билдирүү түзөт
      • Талкууну калтырат
      • 20 жолу кайталанат
      • Чыгып, скрипттин башына кайтып келет

    • Чатбот системага кирет (колдонмо кодунан билдирүүлөрдү эмуляциялайт)
      • Маалымат алмашуу үчүн жаңы каналды түзүүгө 50% мүмкүнчүлүгү бар (атайын талкуу)
      • 50% учурдагы каналдардын бирине билдирүү жазат

"Байланыштар гана" сценарийи бир себептен улам пайда болду. Кырдаал бар: колдонуучулар системаны туташтырышты, бирок али тартыла элек. Ар бир колдонуучу компьютерди таңкы саат 09:00дө күйгүзүп, серверге байланыш түзүп, унчукпай отурат. Бул балдар кооптуу, алардын көбү бар - аларда PING/PONG гана пакеттери бар, бирок алар сервер менен байланышты сактап турушат (алар аны уланта алышпайт - жаңы билдирүү болсо эмне болот). Сыноо мындай колдонуучулардын көп саны жарым сааттын ичинде системага кирүүгө аракет кылган кырдаалды чагылдырат. Бул стресс-тестке окшош, бирок анын басымы дал ушул биринчи киргизүүгө багытталган - эч кандай мүчүлүштүктөр болбошу үчүн (адам системаны колдонбойт жана ал мурунтан эле кулап калат - андан да жаман нерсе жөнүндө ойлонуу кыйын).

Абонентти каттоо скрипти биринчи ишке киргизүүдөн башталат. Биз стресс-тест өткөрүп, кат алышуу учурунда системанын басаңдабаганына ынандык. Бирок колдонуучулар келип, тайм-ауттан улам каттоо ишке ашпай калды. Каттоодон өткөндө колдонгонбуз / dev / random, бул системанын энтропиясына байланыштуу. Серверде жетиштүү энтропия топтогонго убакыт болгон жок жана жаңы SecureRandom суралганда, ал ондогон секундага катып калган. Бул абалдан чыгуунун көптөгөн жолдору бар, мисалы: коопсуздугу азыраак /dev/urandomго өтүү, энтропияны жаратуучу атайын тактаны орнотуу, алдын ала кокус сандарды түзүү жана аларды бассейнде сактоо. Биз бассейндеги көйгөйдү убактылуу жаптык, бирок ошондон бери жаңы абоненттерди каттоо үчүн өзүнчө тестирлөө жүргүзүп жатабыз.

Биз жүк генератор катары колдонобуз JMeter. Ал websocket менен кантип иштөөнү билбейт; ага плагин керек. "jmeter websocket" суроосу боюнча издөө натыйжаларында биринчи болуп төмөнкүлөр саналат: BlazeMeter макалалары, сунуштайт Maciej Zaleski тарабынан плагин.

Мына ушул жерден баштоону чечтик.

Олуттуу тестирлөө башталгандан кийин дээрлик дароо биз JMeter эс тутумун агып баштаганын байкадык.

Плагин өзүнчө чоң окуя; 176 жылдыз менен, githubда 132 айры бар. Автордун өзү буга 2015-жылдан бери киришкен эмес (биз аны 2015-жылы алганбыз, андан кийин шек жараткан эмес), эс тутумдун агып кетишине байланыштуу бир нече github маселелери, 7 жабылбаган тартуу өтүнүчү.
Эгер сиз бул плагинди колдонуу менен жүктөө тестин жүргүзүүнү чечсеңиз, төмөнкү талкууларга көңүл буруңуз:

  1. Көп жиптүү чөйрөдө кадимки LinkedList колдонулган жана натыйжасы болгон NPE иштөө убагында. Муну ConcurrentLinkedDequeге өтүү же синхрондоштурулган блоктор аркылуу чечсе болот. Биринчи вариантты өзүбүз тандап алдык (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).

Бул githubдагылардын бири. Биз эмне кылдык:

  1. Алды айры Элиран Коган (@elyrank) - 1 жана 3 көйгөйлөрдү чечет
  2. Чечилген маселе 2
  3. 9.2.14 дан 9.3.12ге чейин жаңыртылган
  4. ThreadLocal ичинде SimpleDateFormat оролгон; SimpleDateFormat жип үчүн коопсуз эмес, бул иштөө убагында NPEге алып келди
  5. Дагы бир эс тутумдун агып кетиши оңдолду (байланыш ажыратылганда туура эмес жабылган)

Бирок ал агып жатат!

Эс тутум бир күндө эмес, эки күндө түгөнө баштады. Убакыт такыр калган жок, ошондуктан биз азыраак жиптерди ачууну чечтик, бирок төрт агентте. Бул жок дегенде бир жума жетиштүү болушу керек.

Эки күн өттү...

Азыр Хазелкаст эс тутуму түгөнүп баратат. Журналдар көрсөткөндөй, бир нече күндүк тестирлөөдөн кийин Хазелкаст эс тутумдун жетишсиздигине нааразы боло баштаган жана бир нече убакыт өткөндөн кийин кластер ыдырап, түйүндөр бир-бирден өлүп кала берген. Биз JVisualVM'ди hazelcast'ка туташтырдык жана "көтөрүп келе жаткан арааны" көрдүк - ал дайыма GC деп аталат, бирок эс тутумун тазалай алган жок.

1C: Enterprise: Java, PostgreSQL, Hazelcast үчүн жогорку жүктөмдүү масштабдуу кызматты кантип жана эмне үчүн жаздык

Hazelcast 3.4 версиясында картаны/мультикартаны (map.destroy()) жок кылганда, эс толугу менен бошобойт экен:

github.com/hazelcast/hazelcast/issues/6317
github.com/hazelcast/hazelcast/issues/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");

multiMap ар бир жазылуу үчүн түзүлгөн жана кереги жок болгондо жок кылынган. Биз Картаны баштоону чечтик , ачкыч жазылуунун аталышы болот, ал эми маанилер сессиянын идентификаторлору болот (зарыл болсо, андан кийин колдонуучу идентификаторлорун ала аласыз).

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

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

Диаграммалар жакшырды.

1C: Enterprise: Java, PostgreSQL, Hazelcast үчүн жогорку жүктөмдүү масштабдуу кызматты кантип жана эмне үчүн жаздык

Жүктөлгөн тестирлөө жөнүндө дагы эмнени билдик?

  1. JSR223 укмуштуудай жазылып, компиляция кэшин камтышы керек - бул алда канча тезирээк. байланыш.
  2. Jmeter-Plugins графиктерин стандарттууларга караганда түшүнүү оңой. байланыш.

Hazelcast менен болгон тажрыйбабыз жөнүндө

Hazelcast биз үчүн жаңы продукт болду, биз аны менен 3.4.1 версиясынан иштей баштадык, азыр биздин өндүрүш серверибиз 3.9.2 версиясында иштеп жатат (жазуу учурунда, Hazelcastтын акыркы версиясы 3.10).

ID түзүү

Биз бүтүн идентификаторлордон баштадык. Келгиле, жаңы объект үчүн дагы бир Лонг керек деп элестетип көрөлү. Берилиштер базасындагы ырааттуулук ылайыктуу эмес, таблицалар бөлүштүрүүгө тартылган - DB1де ID=1 билдирүү жана DB1де ID=2 билдирүү бар экен, бул IDди Elasticsearchке да, Hazelcastка да коё албайсыз. , бирок эң жаманы, эгер сиз эки маалымат базасындагы маалыматтарды бирге бириктиргиңиз келсе (мисалы, бул абоненттер үчүн бир маалымат базасы жетиштүү деп чечим кабыл алуу). Сиз Hazelcast'ке бир нече AtomicLongs кошуп, эсептегичти ошол жерде сактасаңыз болот, анда жаңы ID алуу көрсөткүчү incrementAndGet плюс Hazelcast'ка суроо-талап үчүн убакытты түзөт. Бирок Hazelcast дагы оптималдуу нерсеге ээ - FlakeIdGenerator. Ар бир кардар менен байланышууда аларга ID диапазону берилет, мисалы, биринчиси – 1ден 10 000ге чейин, экинчиси – 10 001ден 20 000ге чейин жана башкалар. Эми кардар өзүнө берилген диапазон аяктаганга чейин жаңы идентификаторлорду өз алдынча чыгара алат. Ал тез иштейт, бирок сиз тиркемени (жана Hazelcast кардарын) кайра баштаганда жаңы ырааттуулук башталат - демек, өткөрүп жиберүү ж.б. Мындан тышкары, иштеп чыгуучулар ID'лер эмне үчүн бүтүн сан экенин түшүнүшпөйт, бирок ушунчалык карама-каршы келет. Баарын таразалап, УУИДге өттүк.

Айтмакчы, Twitter сыяктуу болгусу келгендер үчүн мындай Snowcast китепканасы бар - бул Hazelcastтын үстүндө Snowflake ишке ашыруу. Сиз бул жерден көрө аласыз:

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

Бирок биз ага дагы жете элекпиз.

TransactionalMap.replace

Дагы бир сюрприз: TransactionalMap.replace иштебейт. Бул жерде сыноо:

@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

Мен 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);
}

Кадимки маалымат структураларын гана эмес, алардын транзакциялык версияларын да сынап көрүңүз. IMap иштейт, бирок TransactionalMap мындан ары жок.

Үзгүлтүксүз жаңы JAR салыңыз

Биринчиден, биз класстарыбыздын объектилерин Хазелкастта жаздырууну чечтик. Мисалы, бизде Колдонмо классы бар, биз аны сактап, окугубуз келет. Сактоо:

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

Жана жаңы объект жазып жатканда, алар ClassNotFoundException ала башташты. Хазелкаст индексти кошууга аракет кылды, бирок биздин класс жөнүндө эч нерсе билчү эмес жана ага ушул класс менен JAR берилишин каалады. Биз дал ушундай кылдык, баары иштеди, бирок жаңы көйгөй пайда болду: кластерди толугу менен токтотпостон JARды кантип жаңыртуу керек? Hazelcast түйүн боюнча жаңыртуу учурунда жаңы JARды албайт. Бул учурда биз индексти издөөсүз жашай алабыз деп чечтик. Анткени, эгер сиз Hazelcastты негизги баалуулуктар дүкөнү катары колдонсоңуз, анда баары иштейби? Жок эле. Бул жерде дагы IMap жана TransactionalMap жүрүм-туруму башкача. IMap маани бербесе, TransactionalMap ката кетирет.

IMap. Биз 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());
    }
}

Бирок ал транзакцияда иштебейт, биз 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();
        }
    });
}

3.8-жылы Колдонуучу классын жайылтуу механизми пайда болду. Сиз бир башкы түйүндү белгилеп, андагы JAR файлын жаңырта аласыз.

Эми биз мамилебизди толугу менен өзгөрттүк: биз аны өзүбүз JSONге сериялаштырабыз жана аны Hazelcastта сактайбыз. Hazelcast биздин класстарыбыздын түзүлүшүн билүүгө муктаж эмес жана биз токтоп калбастан жаңырта алабыз. Домен объекттеринин версиясы колдонмо тарабынан көзөмөлдөнөт. Тиркеменин ар кандай версиялары бир эле учурда иштеши мүмкүн жана жаңы тиркеме жаңы талаалар менен объекттерди жазганда, бирок эскиси бул талаалар жөнүндө азырынча билбеген жагдай болушу мүмкүн. Жана ошол эле учурда, жаңы тиркеме жаңы талаалары жок эски тиркеме тарабынан жазылган объекттерди окуйт. Биз мындай жагдайларды колдонмонун ичинде чечебиз, бирок жөнөкөйлүк үчүн биз талааларды өзгөртпөйбүз же жок кылбайбыз, класстарды жаңы талааларды кошуу менен гана кеңейтебиз.

Кантип биз жогорку аткарууну камсыз кылабыз

Хазелкастка төрт сапар - жакшы, эки маалымат базасына - жаман

Маалыматтар үчүн кэшке өтүү маалымат базасына барганга караганда ар дайым жакшыраак, бирок сиз пайдаланылбаган жазууларды да сактагыңыз келбейт. Эмнени кэш кылуу керектиги жөнүндө чечимди иштеп чыгуунун акыркы этабына чейин калтырабыз. Жаңы функция коддолгондо, биз PostgreSQLдеги бардык сурамдардын журналын күйгүзөбүз (log_min_duration_statement 0 чейин) жана 20 мүнөт бою жүктөө тестин жүргүзөбүз. Чогулган журналдарды колдонуу менен pgFouine жана pgBadger сыяктуу утилиталар аналитикалык отчетторду түзө алышат. Отчеттордо биз биринчи кезекте жай жана тез-тез сурамдарды издейбиз. Жай сурамдар үчүн биз аткаруу планын түзөбүз (ТҮШҮНДҮРҮҮ) жана мындай суроону тездетүүгө болорун баалайбыз. Ошол эле киргизүү маалыматтары үчүн тез-тез сурамдар кэшке жакшы туура келет. Биз суроо-талаптарды "жалпак", суроого бир таблицадан сактоого аракет кылабыз.

колдонуу

SV онлайн кызматы катары 2017-жылдын жазында ишке киргизилген, ал эми өзүнчө продукт катары SV 2017-жылдын ноябрында чыгарылган (ошол учурда бета версия статусунда).

Иштеген бир жылдан ашык убакытта КБ онлайн сервисинин иштешинде олуттуу көйгөйлөр болгон жок. аркылуу онлайн кызматын көзөмөлдөйбүз Апенди, чогултуу жана жайылтуу бамбук.

SV серверинин бөлүштүрүлүшү жергиликтүү пакеттер түрүндө берилет: RPM, DEB, MSI. Windows үчүн плюс биз серверди, Hazelcast жана Elasticsearchти бир машинага орното турган бирдиктүү EXE түрүндө бир орнотуучуну камсыздайбыз. Биз башында орнотуунун бул версиясын “демо” версия деп атаганбыз, бирок азыр бул эң популярдуу жайгаштыруу варианты экени айкын болду.

Source: www.habr.com

Комментарий кошуу