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

Генерация heap-dump-файлов

011 012

На платформе предусмотрена возможность генерации 013 heap-dump-файлов при условии, если программа превысила потребляемую 014 память больше определённого процента от предоставленного ей. Это 015 может потребоваться для анализа утечек по памяти, а так же других 016 данных.

017 018

Для настройки генерации heap-dump-файлов необходимо:

019 020
    021
  1. подготовить директорию, куда будут выгружаться эти файлы. Эта 022 директория должна быть доступна программе платформы MyBPM на 023 запись.
  2. 024 025
  3. настроить параметры генерации в конфиге 026 /mybpm/configs/HeapDumpConfig.txt
  4. 027 028
  5. прописать переменную окружения 029 MYBPM_MEMORY_LIMIT
  6. 030
031 032

После этого можно будет просматривать сгенерированные файлы и 033 выгружать их с помощью REST-сервисов.

034 035

1. Подготовка директории для выгрузки

036 037

Так как программа размещается в поде Kubernetes, то директорию 038 нужно подготовить внутри пода. Директория должна быть 039 подсоединяемым volume-ом. Иначе при падении программы все файлы 040 будут стёрты и станут недоступны для анализа.

041 042

Если директория логов уже имеет свой volume, то можно 043 использовать этот же volume.

044 045

Платформа, по умолчанию, логи выгружает в директорию 046 /var/log/mybpm. Эту директорию можно сменить 047 переменной окружения: MYBPM_LOG_DIR. Если эта 048 переменная окружения не определена, то директория будет по 049 умолчанию.

050 051

Рекомендуется создать volume и подключить его по пути 052 /var/log/mybpm внутри пода.

053 054

Платформа будет создавать логи внутри этой директории, и 055 параллельно с ними можно разместить директорию для выгрузки файлов 056 heap-dump-ов. Пусть это будет директория:

057 058
059  /var/log/mybpm/heap-dumps
060  
061  
062  
063  
064 065

Эту директорию нужно прописать в файле конфигурации генерации 066 heap-dump-файлов.

067 068

2. Настройка конфига

069 070

В системе конфигурации по пути:

071 072
073  /mybpm/configs/HeapDumpConfig.txt
074  
075  
076  
077  
078 079

Настраивается конфиг генерации heap-dump-файлов.

080 081

2.1. Настройка имени файла выгрузки

082 083

В файле конфигурации нужно прописать префикс heap-dump-файлов 084 следующим образом:

085 086
087  heapDumpFilePrefix=/var/log/mybpm/heap-dumps/DreamSkies-cons3
088  
089  
090  
091  
092 093

Префикс состоит из директории, которую мы выбрали в предыдущем 094 разделе этого документа. А дальше идёт префикс имени будущего 095 сгенерированного файла.

096 097

Вендор настойчиво рекомендует использовать префикс состоящий из 098 двух частей:

099 100
101  имя Клиента - тире - имя сервера программы
102  
103  
104  
105  
106 107

В данном примере имя Клиента - это DreamSkies, а 108 cons3 - это имя сервера. Судя по имени сервера на нём 109 запускаются Kafka Consumer-ы.

110 111

Данный префикс имени необходим вендеру, чтобы быстро понять от 112 куда файл и с какого сервера. Иначе сопровождение может 113 затянуться.

114 115

2.2. Активация процесса выгрузки

116 117

Также необходимо активировать сам процесс выгрузки, для этого в 118 конфигурационном файле нужно прописать параметр:

119 120
121  enabled=true
122  
123  
124  
125  
126 127

После чего система поймёт, что всё настроена и будет создавать 128 файлы. Но если не настроена переменная окружения 129 MYBPM_MEMORY_LIMIT, то файлы создаваться не будут. В 130 следующем разделе это описано.

131 132

2.3. Остальные параметры конфига

133 134

Остальные параметры конфига можно оставить без изменений.

135 136

Дополнительно лишь уточним, что в параметре 137 overflowRamPercent указывается процент занимаемой 138 памяти программы от ограничения наложенные на программу. Файлы 139 будут генерировать только в том случае, если этот процент будет 140 превышен.

141 142

3. Настройка переменной окружения 143 MYBPM_MEMORY_LIMIT

144 145

Чтобы сгенерировать файл программа должна понять, что это нужно 146 сделать - просто так генерировать файл расточительно. Для этого ей 147 нужно узнать превышен ли установленный процент занимаемой системой 148 памяти. Для того чтобы рассчитать этот процент, ей нужно знать 149 ограничение по памяти наложенные kubernetes на программу. Для этого 150 программе нужно сообщить с помощью переменной окружения 151 MYBPM_MEMORY_LIMIT.

152 153

Пример yaml-файла настройки deployment для MyBPM-API:

154 155
156  apiVersion: apps/v1
157  kind: Deployment
158  metadata:
159    name: mybpm-api
160    labels:
161      app: mybpm-api
162    namespace: test
163  spec:
164    selector:
165      matchLabels:
166        app: mybpm-api
167    replicas: 1
168    template:
169      metadata:
170        labels:
171          app: mybpm-api
172          app-group: mybpm-api
173      spec:
174        containers:
175          - name: main
176            image: hub.mybpm.kz/mybpm-api
177            imagePullPolicy: Always
178            resources:
179              limits:
180                memory: "1Gi"
181              requests:
182                memory: "1Gi"
183            ports:
184              - containerPort: 8080
185            env:
186              - name: MYBPM_MEMORY_LIMIT,
187                valueFrom: { resourceFieldRef: { containerName: main, resource: limits.memory } }
188            volumeMounts:
189              - { name: log-dir, mountPath: "/var/log/mybpm" }
190        volumes:
191          - name: log-dir
192            hostPath:
193              path: /native/path/to/volume
194  
195  
196 197

В этом примере указана MYBPM_MEMORY_LIMIT, которая 198 считывает значение limit.memory у контейнера с именем 199 main, который определён чуть выше по коду.

200 201

Тем самым программе передаётся наложенное на неё ограничение по 202 памяти.

203 204

После того как переменная окружения определена программа начнёт 205 генерировать файлы (в случае превышение процента).

206 207

В нашем случае автоматически будет создана директория:

208 209
210   /var/log/mybpm/heap-dumps/
211  
212  
213  
214  
215 216

И в ней будут появляться файлы с именем, которе начинается на 217 DreamSkies-cons3- и заканчивается разрешением 218 .hprof. Так же в имя файла будет добавлена текущая 219 дата и время.

220 221

4. Предоставление файлов

222 223

Сгенерированные файлы нужно передать вендеру для анализа не 224 меняя его имя, так как в нём содержится важная информация.

225 226

Это можно сделать средствами администрирования volume-ов, 227 которые Вы используете в своей инфраструктуре.

228 229

Если же это сделать затруднительно, то для этого подготовлены 230 REST-сервисы получения сгенерированных файлов.

231 232

Вообще есть команда

233 234
235  kubectl cp
236  
237  
238  
239  
240 241

Которая предназначена для копирования файлов с пода, но для 242 больших файлов она почему-то не работает. Поэтому есть два 243 REST-сервиса для просмотра и скачивания файлов.

244 245

Эти сервисы не доступны из-вне поэтому вначале нужно получить 246 доступ к самим контейнерам. Это можно сделать с помощью 247 командны:

248 249
250   kubectl post-forward -n NS   mybpm-api-7f765bb5c5-6dxwf   13000:8080
251  
252  
253  
254  
255 256

В этой команде:

257 258 277 278

После того как эта команда запустилась, сервер MyBPM-API 279 становиться доступен по

280 281
282   localhost:13000
283  
284  
285  
286  
287 288

И можно вызывать REST-сервисы.

289 290

Просмотр доступных файлов можно сделать командой:

291 292
293   curl http://localhost:13000/inner/hot-spot/list-available-heap-dump-files | jq
294  
295  
296  
297  
298 299

На выходе можно получить что-то вроде

300 301
302   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
303                                   Dload  Upload   Total   Spent    Left  Speed
304  100   238    0   238    0     0  39403      0 --:--:-- --:--:-- --:--:-- 47600
305  [
306    {
307      "name": "DreamSkies-cons3-heap-dump-20240808-041412-916.hprof",
308      "sizeBytes": 204425284
309    },
310    {
311      "name": "DreamSkies-cons3-heap-dump-20240808-041428-817.hprof",
312      "sizeBytes": 204424631
313    },
314    {
315      "name": "DreamSkies-cons3-heap-dump-20240808-041421-141.hprof",
316      "sizeBytes": 204424551
317    }
318  ]
319  
320  
321 322

Т.е. для скачивания доступны три файла - первый самый 323 большой.

324 325

Чтобы его скачать можно выполнить команду:

326 327
328  NAME=DreamSkies-cons3-heap-dump-20240808-041412-916.hprof
329  wget -O $NAME http://localhost:13000/inner/hot-spot/download-available-heap-dump-file?name=$NAME
330  
331  
332  
333  
334 335

Убедитесь, что имя файла, которое Вы отправите вендеру, 336 останется исходным.

337
338 339 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