SlideShare a Scribd company logo

Разбор и сравнение данных в большом XML на маленькой VDS

Philipp Kulin
Philipp Kulin
Philipp KulinGolang developer at SPbEC Mining

A-level meetup. 08 февраля 2020, Казань. Разбор XML и оптимизации на примере разбора списка запрещенных сайтов Роскомнадзора: https://youtu.be/7LwL0mtBBjc

Разбор и сравнение данных в большом XML на маленькой VDS

1 of 75
Download to read offline
Разбор и сравнение данных в большом
XML на маленькой VDS
Филипп Кулин (Эшер II)
08 февраля 2020 года, Казань
2 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань
Откиньтесь на спинку кресла
• Эта презентация сделана с помощью L
A
TEX1
• Избежать большого количества кода не удалось
• Материал основан на работающем сервисе3
• Значительная часть кода написана сообществом
3 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань
Задача
Что надо было сделать
• Разобрать XML-файл в 160Mb и положить в базу
• Обновлять базу по новым XML-файлам
• Предоставить интерфейс для доступа к базе
3 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань
Задача
Что надо было сделать
• Разобрать XML-файл в 160Mb и положить в базу
• Обновлять базу по новым XML-файлам
• Предоставить интерфейс для доступа к базе
Условия
• Скорость разбора — единицы минут
• Недорогой виртуальный сервер
• Приоритет стандартных решений
4 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань
Интересная задача
• Никаких инноваций и ”rocket science”
• Навязанные условия
• Чувствительность к работе памяти
• Чувствительность к ресурсам
• Хрестоматийные решения
5 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань
Гадание
• Не всегда очевидны «тонкие» места
• Абстракции — «тихие омуты»
Ad

Recommended

Lambda architecture для realtime-аналитики — риски и преимущества / Николай Г...
Lambda architecture для realtime-аналитики — риски и преимущества / Николай Г...Lambda architecture для realtime-аналитики — риски и преимущества / Николай Г...
Lambda architecture для realtime-аналитики — риски и преимущества / Николай Г...Ontico
 
Pulsedb — система хранения временных рядов
Pulsedb — система хранения временных рядовPulsedb — система хранения временных рядов
Pulsedb — система хранения временных рядовMax Lapshin
 
Разработка real-time приложений с RethinkDB / Илья Вербицкий (Независимый кон...
Разработка real-time приложений с RethinkDB / Илья Вербицкий (Независимый кон...Разработка real-time приложений с RethinkDB / Илья Вербицкий (Независимый кон...
Разработка real-time приложений с RethinkDB / Илья Вербицкий (Независимый кон...Ontico
 
Машинное обучение в электронной коммерции — практика использования и подводны...
Машинное обучение в электронной коммерции — практика использования и подводны...Машинное обучение в электронной коммерции — практика использования и подводны...
Машинное обучение в электронной коммерции — практика использования и подводны...Ontico
 
A popular DNS security overview
A popular DNS security overviewA popular DNS security overview
A popular DNS security overviewPhilipp Kulin
 
Технические аспекты блокировки интернета в России. Проблемы и перспективы
Технические аспекты блокировки интернета в России. Проблемы и перспективыТехнические аспекты блокировки интернета в России. Проблемы и перспективы
Технические аспекты блокировки интернета в России. Проблемы и перспективыPhilipp Kulin
 
A popular DNS security overview. Modern theory and practice
A popular DNS security overview. Modern theory and practiceA popular DNS security overview. Modern theory and practice
A popular DNS security overview. Modern theory and practicePhilipp Kulin
 
ENOG-14. Руководство оператора DNSSEC
ENOG-14. Руководство оператора DNSSECENOG-14. Руководство оператора DNSSEC
ENOG-14. Руководство оператора DNSSECPhilipp Kulin
 

More Related Content

More from Philipp Kulin

ENOG-14. Ограничение доступа в России
ENOG-14. Ограничение доступа в РоссииENOG-14. Ограничение доступа в России
ENOG-14. Ограничение доступа в РоссииPhilipp Kulin
 
Опыт использования IPv6 год спустя
Опыт использования IPv6 год спустяОпыт использования IPv6 год спустя
Опыт использования IPv6 год спустяPhilipp Kulin
 
Как взломать WordPress/Joomla за 5 минут
Как взломать WordPress/Joomla за 5 минутКак взломать WordPress/Joomla за 5 минут
Как взломать WordPress/Joomla за 5 минутPhilipp Kulin
 
Опыт внедрения DNSSEC
Опыт внедрения DNSSECОпыт внедрения DNSSEC
Опыт внедрения DNSSECPhilipp Kulin
 
Опыт внедрения IPv6 и статистика
Опыт внедрения IPv6 и статистикаОпыт внедрения IPv6 и статистика
Опыт внедрения IPv6 и статистикаPhilipp Kulin
 
Внедрение IPv6
Внедрение IPv6Внедрение IPv6
Внедрение IPv6Philipp Kulin
 
Хостинг-провайдер и противоправный контент
Хостинг-провайдер и противоправный контентХостинг-провайдер и противоправный контент
Хостинг-провайдер и противоправный контентPhilipp Kulin
 
перспективы черного списка
перспективы черного спискаперспективы черного списка
перспективы черного спискаPhilipp Kulin
 

More from Philipp Kulin (9)

ENOG-14. Ограничение доступа в России
ENOG-14. Ограничение доступа в РоссииENOG-14. Ограничение доступа в России
ENOG-14. Ограничение доступа в России
 
Опыт использования IPv6 год спустя
Опыт использования IPv6 год спустяОпыт использования IPv6 год спустя
Опыт использования IPv6 год спустя
 
Как взломать WordPress/Joomla за 5 минут
Как взломать WordPress/Joomla за 5 минутКак взломать WordPress/Joomla за 5 минут
Как взломать WordPress/Joomla за 5 минут
 
Опыт внедрения DNSSEC
Опыт внедрения DNSSECОпыт внедрения DNSSEC
Опыт внедрения DNSSEC
 
Опыт внедрения IPv6 и статистика
Опыт внедрения IPv6 и статистикаОпыт внедрения IPv6 и статистика
Опыт внедрения IPv6 и статистика
 
DNSSEC
DNSSECDNSSEC
DNSSEC
 
Внедрение IPv6
Внедрение IPv6Внедрение IPv6
Внедрение IPv6
 
Хостинг-провайдер и противоправный контент
Хостинг-провайдер и противоправный контентХостинг-провайдер и противоправный контент
Хостинг-провайдер и противоправный контент
 
перспективы черного списка
перспективы черного спискаперспективы черного списка
перспективы черного списка
 

Разбор и сравнение данных в большом XML на маленькой VDS

  • 1. Разбор и сравнение данных в большом XML на маленькой VDS Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань
  • 2. 2 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Откиньтесь на спинку кресла • Эта презентация сделана с помощью L A TEX1 • Избежать большого количества кода не удалось • Материал основан на работающем сервисе3 • Значительная часть кода написана сообществом
  • 3. 3 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Задача Что надо было сделать • Разобрать XML-файл в 160Mb и положить в базу • Обновлять базу по новым XML-файлам • Предоставить интерфейс для доступа к базе
  • 4. 3 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Задача Что надо было сделать • Разобрать XML-файл в 160Mb и положить в базу • Обновлять базу по новым XML-файлам • Предоставить интерфейс для доступа к базе Условия • Скорость разбора — единицы минут • Недорогой виртуальный сервер • Приоритет стандартных решений
  • 5. 4 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Интересная задача • Никаких инноваций и ”rocket science” • Навязанные условия • Чувствительность к работе памяти • Чувствительность к ресурсам • Хрестоматийные решения
  • 6. 5 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Гадание • Не всегда очевидны «тонкие» места • Абстракции — «тихие омуты»
  • 7. 5 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Гадание • Не всегда очевидны «тонкие» места • Абстракции — «тихие омуты» • Тесты, бенчмарки, профилирование
  • 8. 6 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Архитектура • База данных • Индексы по значениям для поиска • Функционал наполнения базы из исходных данных • Функционал обновления данных • Функционал поиска данных
  • 9. 7 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Формат исходных данных. XML • 250 тысяч элементов content • Размер каждого от сотни байт до 6MB • Общий размер данных свыше 150MB <?xml version=”1.0” encoding=”windows-1251”?> <reg:register ...> <content id=”656” ...> ... </content> ... <content id=”2062369” ...> ... </content> </reg:register>
  • 10. 7 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Формат исходных данных. XML • 250 тысяч элементов content • Размер каждого от сотни байт до 6MB • Общий размер данных свыше 150MB • XML в кодировке CP1251 <?xml version=”1.0” encoding=”windows-1251”?> <reg:register ...> <content id=”656” ...> ... </content> ... <content id=”2062369” ...> ... </content> </reg:register>
  • 11. 8 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Элемент Content <content id=”680741”...> <decision .../> <domain><![CDATA[example.com]]></domain> <url><![CDATA[https://example.com/smt]]></url> ... <ip>10.0.0.1</ip> ... <ipv6>fc00::beef</ipv6> ... <ipSubnet>10.1.0.0/16</ipSubnet> ... <ipSubnet6>fd00::/48</ipSubnet6> ... </content> • IP-адреса могут быть поштучно тысячами
  • 12. 9 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Потоковый разбор XML import ”encoding/xml” ... decoder := xml.NewDecoder(dumpFile) decoder.CharsetReader = charset.NewReaderLabel for { t, err := decoder.Token() ... switch _e := t.(type) { case xml.StartElement: switch _e.Name.Local { case ”content”: ...
  • 13. 9 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Потоковый разбор XML • Создаем декодер import ”encoding/xml” ... decoder := xml.NewDecoder(dumpFile) decoder.CharsetReader = charset.NewReaderLabel for { t, err := decoder.Token() ... switch _e := t.(type) { case xml.StartElement: switch _e.Name.Local { case ”content”: ...
  • 14. 9 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Потоковый разбор XML • Создаем декодер • Не забываем про кодировку import ”encoding/xml” ... decoder := xml.NewDecoder(dumpFile) decoder.CharsetReader = charset.NewReaderLabel for { t, err := decoder.Token() ... switch _e := t.(type) { case xml.StartElement: switch _e.Name.Local { case ”content”: ...
  • 15. 9 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Потоковый разбор XML • Создаем декодер • Не забываем про кодировку • Ловим каждый элемент import ”encoding/xml” ... decoder := xml.NewDecoder(dumpFile) decoder.CharsetReader = charset.NewReaderLabel for { t, err := decoder.Token() ... switch _e := t.(type) { case xml.StartElement: switch _e.Name.Local { case ”content”: ...
  • 16. 10 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Выбор формы хранения данных • Время разбора XML — 10-200 секунд
  • 17. 10 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Выбор формы хранения данных • Время разбора XML — 10-200 секунд • База нужна только для хранения
  • 18. 10 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Выбор формы хранения данных • Время разбора XML — 10-200 секунд • База нужна только для хранения • bbolt — заполнение час+
  • 19. 10 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Выбор формы хранения данных • Время разбора XML — 10-200 секунд • База нужна только для хранения • bbolt — заполнение час+ • map + скорость разбора = победа
  • 20. 11 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Формат исходных данных. XML • 250 тысяч элементов content • Размер каждого от сотни байт до 6MB • Общий размер данных свыше 150MB <?xml version=”1.0” encoding=”windows-1251”?> <reg:register ...> <content id=”656” ...> ... </content> ... <content id=”2062369” ...> ... </content> </reg:register>
  • 21. 11 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Формат исходных данных. XML • 250 тысяч элементов content • Размер каждого от сотни байт до 6MB • Общий размер данных свыше 150MB • XML в кодировке CP1251 <?xml version=”1.0” encoding=”windows-1251”?> <reg:register ...> <content id=”656” ...> ... </content> ... <content id=”2062369” ...> ... </content> </reg:register>
  • 22. 12 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Формат хранения данных • Каждый content имеет уникальный числовой id • id очень разреженные
  • 23. 12 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Формат хранения данных • Каждый content имеет уникальный числовой id • id очень разреженные • Решение: map[int]*TContent TContent — структура для DecodeElement() case ”content”: err := decoder.DecodeElement(&v, &_e)
  • 24. 13 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Хранение данных. Грабли • Уменьшаем аллокации
  • 25. 13 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Хранение данных. Грабли • Уменьшаем аллокации • Улучшательство: map[int]TContent
  • 26. 13 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Хранение данных. Грабли • Уменьшаем аллокации • Улучшательство: map[int]TContent • Боль
  • 27. 13 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Хранение данных. Грабли • Уменьшаем аллокации • Улучшательство: map[int]TContent • Боль программы ощущалась физически... • Расширение карты — очень дорогая операция • Всё-таки map[int]*TContent
  • 28. 14 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Хранение данных. Оптимизация • Часть элементов имеет аттрибут ts: ts=”2020-02-06T19:54:00+03:00” • IPv4-адреса представлены элементом IP: <ip ts=”2020-02-06T19:54:00+03:00”> 10.0.0.1 </ip>
  • 29. 14 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Хранение данных. Оптимизация • Часть элементов имеет аттрибут ts: ts=”2020-02-06T19:54:00+03:00” • IPv4-адреса представлены элементом IP: <ip ts=”2020-02-06T19:54:00+03:00”> 10.0.0.1 </ip> • Две строки против двух целых чисел • Миллионы структур c IPv4-адресами
  • 30. 15 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Оптимизация конвертации данных • Преобразование стандартными средствами ip := net.ParseIP(s) intIp =: binary.BigEndian.Uint32(ip[12:16])
  • 31. 15 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Оптимизация конвертации данных • Преобразование стандартными средствами ip := net.ParseIP(s) intIp =: binary.BigEndian.Uint32(ip[12:16]) • Пишем менее универсально, но без аллокаций
  • 32. 15 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Оптимизация конвертации данных • Преобразование стандартными средствами ip := net.ParseIP(s) intIp =: binary.BigEndian.Uint32(ip[12:16]) • Пишем менее универсально, но без аллокаций • Сравниваем Benchmark_Standart-4 4295910 268 ns/op 48 B/op 3 allocs/op Benchmark_Custom-4 18941194 60.8 ns/op 0 B/op 0 allocs/op
  • 33. 16 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Более детальное преобразование • Наполняем TContent «вручную» case ”content”: err := decoder.DecodeElement(&v, &_e) % err := UnmarshalContent(tempBuf, &v) ... func UnmarshalContent(b []byte, v *TContent) error { buf := bytes.NewReader(b) decoder := xml.NewDecoder(buf) ... case elementIp: ip := TXMLIp{} if err := decoder.DecodeElement(&ip, &element); err != nil {
  • 34. 16 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Более детальное преобразование • Наполняем TContent «вручную» • Значительное уменьшение потребления памяти case ”content”: % err := decoder.DecodeElement(&v, &_e) err := UnmarshalContent(tempBuf, &v) ... func UnmarshalContent(b []byte, v *TContent) error { buf := bytes.NewReader(b) decoder := xml.NewDecoder(buf) ... case elementIp: ip := TXMLIp{} if err := decoder.DecodeElement(&ip, &element); err != nil {
  • 35. 17 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Хранение данных. Индексы • Самая простая и скучная часть • map нужных данных • Значения — массивы id элементов content
  • 36. 18 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Обновление данных • Упрощаем до сравнения content целиком
  • 37. 18 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Обновление данных • Упрощаем до сравнения content целиком • Считаем контрольные суммы
  • 38. 19 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Контрольные суммы • Считал SHA256
  • 39. 19 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Контрольные суммы • Считал SHA256 • Профилирование показало, что выбор неудачный
  • 40. 19 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Контрольные суммы • Считал SHA256 • Профилирование показало, что выбор неудачный • Выбрал на 64-bit FNV-1
  • 41. 19 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Контрольные суммы • Считал SHA256 • Профилирование показало, что выбор неудачный • Выбрал на 64-bit FNV-1 • Проверил, заглянув «под капот»
  • 42. 20 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Как считаем контрольные суммы • Преобразование TContent обратно в XML
  • 43. 20 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Как считаем контрольные суммы • Преобразование TContent обратно в XML • Требует двойного преобразования каждого элемента
  • 44. 20 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Как считаем контрольные суммы • Преобразование TContent обратно в XML • Требует двойного преобразования каждого элемента • Использование io.TeeReader
  • 45. 20 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Как считаем контрольные суммы • Преобразование TContent обратно в XML • Требует двойного преобразования каждого элемента • Использование io.TeeReader • Декодируем только изменившиеся элементы content
  • 46. 21 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань TeeReader и Decoder. Грабли №1 tr := io.TeeReader(dumpFile, &buffer) decoder := xml.NewDecoder(tr) decoder.CharsetReader = charset.NewReaderLabel for { tokenStartOffset := decoder.InputOffset()
  • 47. 21 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань TeeReader и Decoder. Грабли №1 tr := io.TeeReader(dumpFile, &buffer) decoder := xml.NewDecoder(tr) decoder.CharsetReader = charset.NewReaderLabel for { tokenStartOffset := decoder.InputOffset() • ... не работает, данные не синхронны
  • 48. 21 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань TeeReader и Decoder. Грабли №1 tr := io.TeeReader(dumpFile, &buffer) decoder := xml.NewDecoder(tr) decoder.CharsetReader = charset.NewReaderLabel for { tokenStartOffset := decoder.InputOffset() • ... не работает, данные не синхронны • XML декодер «шагает» по UTF-8 строке • контрольные суммы «шагают» по CP1251 строке
  • 49. 22 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань TeeReader и Decoder. Грабли №2 decoder := xml.NewDecoder(dumpFile) decoder.CharsetReader = func(l string, i io.Reader) (io.Reader, error) { r, err := charset.NewReaderLabel(l, i) return io.TeeReader(r, &buffer), nil } for { tokenStartOffset := decoder.InputOffset()
  • 50. 22 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань TeeReader и Decoder. Грабли №2 decoder := xml.NewDecoder(dumpFile) decoder.CharsetReader = func(l string, i io.Reader) (io.Reader, error) { r, err := charset.NewReaderLabel(l, i) return io.TeeReader(r, &buffer), nil } for { tokenStartOffset := decoder.InputOffset() • ... не работает, данные не синхронны
  • 51. 22 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань TeeReader и Decoder. Грабли №2 decoder := xml.NewDecoder(dumpFile) decoder.CharsetReader = func(l string, i io.Reader) (io.Reader, error) { r, err := charset.NewReaderLabel(l, i) return io.TeeReader(r, &buffer), nil } for { tokenStartOffset := decoder.InputOffset() • ... не работает, данные не синхронны • XML декодер «перепрыгивает» через заголовок • контрольные суммы не «перепрыгивают»
  • 52. 23 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань TeeReader и Decoder Заработало! decoder := xml.NewDecoder(dumpFile) decoder.CharsetReader = func(l string, i io.Reader) (io.Reader, error) { r, err := charset.NewReaderLabel(l, i) offsetCorrection = decoder.InputOffset() return io.TeeReader(r, &buffer), nil } for { tokenStartOffset := decoder.InputOffset() - offsetCorrection
  • 53. 24 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Отличное наглядное упражнение • Ридеры/райтеры — go-way • I/O через буфер тянется ещё с 90-ых • Ридеры/райтеры на интерфейсах — новое в go • У новичков затруднено понимание этой абстракции • Хороший пример использования «замыкания» • Разобранная задача — отличное упражнение
  • 54. 25 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Подключаем gRPC • Универсальное простое рабочее решение
  • 55. 25 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Подключаем gRPC • Универсальное простое рабочее решение • Данные хранить сразу в формате gRPC
  • 56. 25 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Подключаем gRPC • Универсальное простое рабочее решение • Данные хранить сразу в формате gRPC • gRPC пытается всё хранить ссылками
  • 57. 25 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Подключаем gRPC • Универсальное простое рабочее решение • Данные хранить сразу в формате gRPC • gRPC пытается всё хранить ссылками • Несовместимо с нашей борьбой со ссылками
  • 58. 26 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Делаем промежуточный тип • Из XML преобразуем в TContent
  • 59. 26 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Делаем промежуточный тип • Из XML преобразуем в TContent • TContent пакуем в json
  • 60. 26 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Делаем промежуточный тип • Из XML преобразуем в TContent • TContent пакуем в json • Новый тип TMinContent содержит: • метаданные • данные для сравнения (и индекса) • контрольную сумму для сравнения • Полные данные TContent в виде json
  • 61. 26 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Делаем промежуточный тип • Из XML преобразуем в TContent • TContent пакуем в json • Новый тип TMinContent содержит: • метаданные • данные для сравнения (и индекса) • контрольную сумму для сравнения • Полные данные TContent в виде json • В базу кладем TMinContent
  • 62. 26 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Делаем промежуточный тип • Из XML преобразуем в TContent • TContent пакуем в json • Новый тип TMinContent содержит: • метаданные • данные для сравнения (и индекса) • контрольную сумму для сравнения • Полные данные TContent в виде json • В базу кладем TMinContent • Увеличен общий объём данных из-за дублирования
  • 63. 27 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Данные gRPC • Массив «сообщений». «Сообщение» содержит: • метаданные • полные данные в виде json-строки с TContent
  • 64. 27 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Данные gRPC • Массив «сообщений». «Сообщение» содержит: • метаданные • полные данные в виде json-строки с TContent • Буфер под отдаваемые данные минимален
  • 65. 27 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Данные gRPC • Массив «сообщений». «Сообщение» содержит: • метаданные • полные данные в виде json-строки с TContent • Буфер под отдаваемые данные минимален • Можно написать свою реализацию gRPC
  • 66. 28 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Что ещё можно «подкрутить»?
  • 67. 29 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Использование памяти Нас интересует только верхняя граница
  • 68. 30 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Настройки рантайма • Управление сборщиком мусора % GOGC=50 /bin/myapp
  • 69. 30 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Настройки рантайма • Управление сборщиком мусора % GOGC=50 /bin/myapp • Малоэффективно, «подтормаживает»
  • 70. 30 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Настройки рантайма • Управление сборщиком мусора % GOGC=50 /bin/myapp • Малоэффективно, «подтормаживает» • Возврат памяти системе % GODEBUG=madvdontneed=1 /bin/myapp
  • 71. 30 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Настройки рантайма • Управление сборщиком мусора % GOGC=50 /bin/myapp • Малоэффективно, «подтормаживает» • Возврат памяти системе % GODEBUG=madvdontneed=1 /bin/myapp • Малоэффективно в пике, «тормозит»
  • 72. 30 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Настройки рантайма • Управление сборщиком мусора % GOGC=50 /bin/myapp • Малоэффективно, «подтормаживает» • Возврат памяти системе % GODEBUG=madvdontneed=1 /bin/myapp • Малоэффективно в пике, «тормозит» Чем хуже код — тем больше негативный эффект
  • 73. 31 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Итог • Данные в map в памяти • map для индексов • Хранения на диске нет • Потоковый разбор XML с TeeReader • Оптимизация форматов данных • Сравнение через контрольные суммы • Вспомогательный тип для хранения данных
  • 74. 32 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Вопросы Избави, Боже, нас от ярости норманнов и «интересных задач» schors@gmail.com
  • 75. 33 Филипп Кулин (Эшер II) 08 февраля 2020 года, Казань Ссылки [1] Филипп Кулин. Пишем презентации в LaTeX. https://habr.com/ru/post/471352/. [2] Мониторинг реестра запрещенных сайтов. https://usher2.club/. [3] Исходный код сервиса обработки выгрузки. https://github.com/usher2/u2ckdump. [4] Исходный код Telegram-бота для проверки сайта. https://github.com/usher2/u2ckbot.