Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Разработка GO приложения с CGO – Олег Герасимов

Разработка GO приложения с CGO – Олег Герасимов

GopherCon Russia

April 13, 2019
Tweet

More Decks by GopherCon Russia

Other Decks in Programming

Transcript

  1. Какую задачу мы решали IPTV платформа на 10М абонентов (Wink)

    Требуемая функциональность : • API тонкого клиента • Сложная бизнес-логика фильтрации контента • Пользовательские фильтры • Полнотекстовый поиск Требуемая производительность: • ~5-10К RPS сложных запросов с одного сервера
  2. Как подключить БД к проекту - Standalone сервер коммуникация с

    БД по сети vs - Embedded библиотека коммуникация с БД через CGO (бинарный ABI)
  3. Почему профит - Нет переключения контекстов между процессами сервера и

    go приложения - Нет затрат на сериализацию данных из сервера с последующей десериализацией в клиенте - Нет затрат на запись и чтение данных в socket
  4. Горутины становятся потоками Решение: ограничиваем количество горутин проходящих в cgo:

    cgoLimiter := make(chan struct{}, cpuCount + 1) …. Перед вызовом cgo: binding.cgoLimiter <- struct{}{} defer func() { <-binding.cgoLimiter }()
  5. Память может течь - БД возвращает ресурсы выделенные C runtime

    - go после того, как их использовал должен их освободить - GC тут не помощник
  6. Освобождение ресурсов 1. На уровне API: у Iterator, который владеет

    С/С++ ресурсами делаем метод Close (), и при разработке приложения пишем как обычно iterator:= query.Exec () defer iterator.Close () … 2. Страхуемся от того, что в приложении забыли вызывать iterator.Close() – добавляем Finalizer . Finalizer не просто освобождает C/C++ ресурсы, а ругается в лог - Finalizer это дорого (+1-2 мкс и не надежно)
  7. Освобождаем ресурсы батчами Под капотом iterator.Close (): - вызывать на

    каждый Close () cgo – дорого - делаем канал и горутину, которая передает пачку освобождаемых ресурсов за один вызов cgo
  8. Фрагментация памяти В go приложении с cgo 2-е независимые кучи:

    - Go - C++ Когда освобождается память в приложении, то алокатор старается вызываеть unmap и отдать память в ОС Когда в приложении несколько куч – есть проблема с возвращением неиспользуемой памяти в систему
  9. Фрагментация памяти Методом проб и ошибок выяснили, что если в

    C части использовать tcmalloc, то проблема уходит и память освобождается!
  10. Инструментируем cgo Да, мы научили pprof работать с cgo! Добавляем

    в приложение 4 строки кода: import _ "github.com/restream/reindexer/pprof" … go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()
  11. Выводы 1. CGO не так страшен, и в некоторых случаях

    его использование дает хороший профит - когда необходимо убрать издержки уходящие на сетевое взаимодействие - когда есть библиотеки C/C++ выполняющая важную и долго-выполняющуюся функциональность 2. Но надо уметь его правильно готовить