singleflight в Go: Схлопывание... Заметка
DEV Community на русском

singleflight в Go: Схлопывание дублирующейся работы под нагрузкой

"Стампед кэша" происходит, когда кэш истекает, и множество запросов одновременно не находят совпадений, что приводит к дублированию дорогостоящих операций. Пакет Go golang.org/x/sync/singleflight решает эту проблему, гарантируя, что для данного ключа выполняется только одно выполнение функции. Одновременные вызывающие абоненты с одинаковым ключом будут ждать и получать результат от этого единственного выполнения. Метод Do принимает ключ и функцию, выполняя функцию только для первого вызывающего абонента. Последующие вызывающие абоненты блокируются до завершения функции, а затем разделяют ее результат. Булево значение shared указывает, был ли результат распространен среди нескольких вызывающих абонентов, что полезно для метрик.Singleflight сам по себе не является кэшем; он сворачивает вызовы только тогда, когда они перекрываются во времени. Типичный шаблон включает проверку кэша, затем использование group.Do при отсутствии совпадения и, наконец, запись результата обратно в кэш. Важное предостережение заключается в том, что возвращаемое значение является общим, поэтому изменяемые типы, такие как указатели, срезы и карты, могут привести к гонкам данных, если они изменяются несколькими горутинами. Чтобы избежать этого, относитесь к возвращаемым значениям как к неизменяемым или возвращайте копии, которыми вызывающие абоненты могут владеть и изменять независимо.Для неблокирующего поведения DoChan возвращает канал, позволяя вызывающим абонентам реагировать на отмену контекста. Однако функция выполняется в контексте первого вызывающего абонента, поэтому для общих операций рекомендуется отсоединять работу от контекстов, специфичных для запроса. Метод Forget может использоваться для очистки ключа, позволяя последующим вызовам начинать новые выполнения, что полезно для ограничения радиуса поражения сбойных операций. Singleflight должен находиться на границе, где дублирование работы является дорогостоящим, например, при загрузке кэша или медленных вызовах вышестоящих систем, а не внутри логики предметной области. Две основные подводные камни — это общее значение и контекст первого вызывающего абонента.
CdXz5zHNQW_EMU9QnIza4.webp