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

«Graceful Shutdown в Go-сервисах и как подружит...

Badoo Tech
March 07, 2018
8.9k

«Graceful Shutdown в Go-сервисах и как подружить его с Kubernetes» — Артемий Рябинков (Avito)

Выступление на Go 1.10 Release Party @ Badoo 24.02.2018.
Артемий расскажет про подходы к безопасному завершению работы многопоточных программ на Go, в частности о том, как контролировать горутины и управлять ими. Объяснит, почему во время выкатки сервисов в Kubernetes пользователям может возвращаться множество ошибок. Чтобы подробнее раскрыть, почему так происходит, схематично покажет, как работает Kubernetes внутри, и почему он не позволяет сделать выкатку сервисов бесшовной.

Badoo Tech

March 07, 2018
Tweet

More Decks by Badoo Tech

Transcript

  1. Подход к Graceful Shutdown в Go И почему это не

    работает в Kubernetes Артемий Рябинков Avito
  2. Что такое Graceful Shutdown и зачем он нужен? • Завершаемся

    предсказуемо • Не теряем данные
  3. Бесшовная выкатка • Выкатываем новую версию сервиса • Переключаем на

    неё трафик • Отключаем старую версию сервиса
  4. План Пишем на PHP • Слушаем сигнал • Просим потоки

    завершиться • Ждем завершения всех потоков • Выходим из процесса
  5. Ловим сигнал OS // Register signal handler sigc := make(chan

    os.Signal, 1) signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM) // Wait for signal <-sigc
  6. func main() { done := make(chan struct{}) go listen(done) //

    .. SIGTERM close(done) // .. wait for listen }
  7. Проблемы канала • Boilerplate код в Listen • Нет уверенности

    в том, что функция действительно завершилась
  8. func main() { var wg sync.WaitGroup wg.Add(1) go func() {

    listen() // blocking wg.Done() }() wg.Wait() // wait them all }
  9. func main() { ctx, cancel := context.WithCancel(...) var wg sync.WaitGroup

    wg.Add(1) go func() { listen(ctx) wg.Done() }() // .. SIGTERM cancel() wg.Wait() }
  10. func main() { ctx, cancel := context.WithCancel(...) var g errgroup.Group

    g.Go(func() error { return listen(ctx) } // .. SIGTERM cancel() if err := g.Wait(); err != nil { // Handle error } }