java.lang.RuntimeException: wXb6Vnl31u :: Ошибка для HTML= 001 003 004 005 006 007 008 009
010

Базовая концепция архитектуры

011 012

Требовалось создать платформу с динамической структурой данных, 013 которая, к тому же, будет изменяться в процессе эксплуатации, 014 притом на "горячую", т.е. нужна возможность изменять структуру 015 данных во время работы с этими данными, т.е. 016 добавления/изменения/удаления оных. И, при этом, обеспечивать 017 высокую нагрузку.

018 019

Логически платформа представляет набор бизнес-объектов (БО), у 020 которых есть поля различных типов. У каждого бизнес-объекта можно 021 создавать инстанции - данные. Значения полей инстанций в 022 последствии можно менять. Инстанции могут быть помечены как:

023 024

1) Актуальные - первичное состояние после создания. В этом 025 состоянии инстанция находиться при работе с ней.

026 027

2) Удалённые - такие инстанции считаются удалёнными - они не 028 участвуют в работе системы. Так же есть возможность удалить 029 физически инстанции.

030 031

3) Архивные - давно не используемые инстанции, ушедшие в 032 архив.

033 034

4) Тестовые - инстанции, которые используют для тестирования 035 системы.

036 037

Для этого были выбраны системы управления баз данных, которые 038 поддерживают масштабирование "в ширину". А именно:

039 040

1) MongoDB

041 042

2) Apache Kafka

043 044

3) ElasticSearch

045 046

4) PostgreSQL

047 048

5) Apache Zookeeper

049 050

MongoDB - главное оперативное хранилище

051 052

Главной базой данных является MongoDB. В ней хранятся все данные 053 системы в оперативном режиме.

054 055

В оперативном режиме - это значит, что, например, если у клиента 056 фамилия поменялась с "Иванова" на "Сидорова", то в MongoDB остаётся 057 только "Сидорова", а "Иванова" стирается бесследно.

058 059

Более того, база данных MongoDB используется только в режиме 060 Key-Value-Storage, это обозначает, что платформа в неё делает 061 запросы только по идентификаторам с ожиданием единичного документа 062 по этому идентификатору.

063 064

На платформе часто требуется получить списки - использовать для 065 этого MongoDB запрещено, чтобы не нагружать её. Для этого 066 используется ElasticSearch.

067 068

ElasticSearch - получение информации 069 списками

070 071

ElasticSearch используется для получения оперативной информации 072 в виде списков, которые отфильтрованы и отсортированы по желанию 073 пользователя в режиме постраничной загрузки.

074 075

В ElasticSearch тоже хранится только оперативная информация.

076 077

Для того чтобы синхронизировать данные в ElasticSearch и MongoDB 078 используется ApacheKafka.

079 080

Apache Kafka - синхронизация данных + 081 хранение истории изменений данных

082 083

Apache Kafka на платформе MyBPM используется для двух целей:

084 085

1) Хранение исторической информации;

086 087

2) Синхронизация данных между различными компонентами 088 системы.

089 090

Все изменения в данных системы сбрасывается в Kafka в виде 091 дельты данных. В дельте данных содержится только та информация, 092 которая изменилась в данный момент в системе. А именно, например, 093 если у клиента сорок полей, а изменилось только фамилия, то в 094 дельту попадёт только эта фамилия, при том, только новое значение 095 этого поля. Так же в дельте будут координаты того, что изменилось - 096 идентификатор инстанции. А также кто и когда это изменил. Резюмируя 097 сказанное, в дельте содержится следующая информацию:

098 099

1) Новые значения полей, которые изменились

100 101

2) Координаты того, что изменилось: идентификатор инстанции 102 бизнес-объекта + идентификатор самого бизнес-объекта

103 104

3) Идентификатор пользователя, кто сделал это изменение

105 106

4) Дата и время этого изменения

107 108

Дальше Kafka-Consumer-ы подгружают эти изменения и применяют их 109 для соответствующих компонентов системы. Например, соответствующий 110 Consumer обновляет данные в ElasticSearch тем самым синхронизируя 111 их с оригиналом в MongoDB.

112 113

Apache Kafka - как база исторических 114 данных

115 116

К Apache Kafka следует относиться как к базе данных, в которой 117 храниться история всех изменений системы.

118 119

На платформе Apache Kafka организована динамическая система 120 получения отчётов.

121 122

Вначале пользователь подготавливает структуру отчёта и сохраняет 123 её в БД MongoDB. Далее платформа создаёт в PostgreSQL таблицы для 124 получения данного отчёта, но эти таблицы пустые. Так как в Apache 125 Kafka храниться вся история изменений, то можно пройтись по ним и 126 подготовить данные в этих таблицах, что и делается. Эти таблицы 127 заполняются и отчёт готов для эксплуатации. Далее Kafka-Consumer 128 отслеживает дальнейшие изменения и держит таблицы в актуальном 129 состоянии.

130 131

Для того чтобы данная функциональность работала, необходимо 132 исторически данные держать постоянно в Apache Kafka и не стирать 133 их. В Apache Kafka для это есть весь необходимый инструментарий - 134 репликация, партиции и прочее доступные из коробки.

135 136

Следует отметить, что платформа MyBPM позволяет разделять данные 137 инстанций БО на разные Kafka Topic-и. Это позволяет зачищать те БО, 138 которые сильно растут в размере. При этом по ним теряется 139 историческая информация. А это означает, что по ним не должно быть 140 отчётов с исторической информацией.

141 142

Предназначение PostgreSQL

143 144

PostgreSQL используется для решения сложных логических задач. 145 Например, в PostgreSQL хранятся ловушки событий, которые 146 срабатывают, если наступает заранее ожидаемое событие, например 147 ожидание сохранение определённой инстанции БО, чтобы запустился 148 конкретный скрипт в бизнес-процессе.

149 150

Предназначение Apache Zookeeper

151 152

В Apache Zookeeper платформа MyBPM хранить всю конфигурационную 153 информацию - параметры доступа, таймауты, размеры буферов и 154 прочее.

155 156

В дальнейшем планируется перенести всю эту конфигурацию в БД 157 MongoDB и управлять ей через интерфейс.

158
159 160 at kz.greetgo.md_reader.util.MdUtil.xmlTextToDoc(MdUtil.java:80) at kz.greetgo.md_reader.core.MdConverter.prepareHtmlFileFrom(MdConverter.java:136) at kz.greetgo.md_reader.core.MdConverter.convert(MdConverter.java:208) at kz.greetgo.md_reader.controller.RenderController.downloadToc(RenderController.java:360) at kz.greetgo.md_reader.controller.RenderController.request(RenderController.java:108) at jdk.internal.reflect.GeneratedMethodAccessor3.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at kz.greetgo.md_reader.interceptors.TextReplaceFilter.doFilter(TextReplaceFilter.java:36) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:833) Caused by: java.io.IOException: Server returned HTTP response code: 429 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:2000) at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1589) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:677) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1397) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1333) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.startPE(XMLDTDScannerImpl.java:732) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.skipSeparator(XMLDTDScannerImpl.java:2101) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.scanDecls(XMLDTDScannerImpl.java:2064) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.scanDTDExternalSubset(XMLDTDScannerImpl.java:299) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1165) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(XMLDocumentScannerImpl.java:1040) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:943) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:542) at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:889) at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:825) at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) at java.xml/com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:247) at java.xml/com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:342) at java.xml/javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:122) at kz.greetgo.md_reader.util.MdUtil.xmlTextToDoc(MdUtil.java:71) ... 48 more