Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Конструкция
select
используется для обработки операций с каналами. Она позволяет горутинам ожидать на нескольких каналах одновременно. Важной особенностью select
является возможность использования блока default
, который выполняется, если ни один из каналов не готов к операции (отправке или получению данных). Это позволяет избежать блокировки горутины, если каналы не готовы.Когда
select
выполняется, он блокируется до тех пор, пока один из его case-блоков не станет готов к выполнению (т.е. канал не станет доступным для отправки или получения данных). Однако, если добавить блок default
, select
выполнит его немедленно, если ни один из других case-блоков не готов. Это позволяет избежать блокировки горутины и продолжить выполнение других задач.package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(2 * time.Second)
ch1 <- 1
}()
go func() {
time.Sleep(1 * time.Second)
ch2 <- 2
}()
for i := 0; i < 5; i++ {
select {
case val := <-ch1:
fmt.Println("Received from ch1:", val)
case val := <-ch2:
fmt.Println("Received from ch2:", val)
default:
fmt.Println("No channel is ready")
time.Sleep(500 * time.Millisecond)
}
}
}
ch1
и ch2
.select
с default
, который проверяет готовность каналов каждые 500 миллисекунд.default
, выводящий сообщение "No channel is ready".Если вы хотите проверить наличие данных на канале или возможность отправки данных без блокировки, используйте
default
.В некоторых случаях
default
может предотвратить дедлоки, позволяя горутине продолжить выполнение, даже если каналы временно недоступны.Можно использовать
default
для периодической проверки состояния канала или выполнения задач в ожидании готовности каналов.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Мапы (maps) не являются потокобезопасными по умолчанию. Если несколько горутин одновременно пытаются записывать (или читать и записывать) в одну и ту же мапу, это может привести к непредсказуемым результатам, состояниям гонки и даже краху программы (panic).
Вот пример, который иллюстрирует проблему конкурентной записи в мапу. В этом примере множество горутин одновременно записывают значения в мапу
m
, что приведет к состоянию гонки и, возможно, к панике.package main
import (
"fmt"
"sync"
)
func main() {
m := make(map[int]int)
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
m[i] = i
}(i)
}
wg.Wait()
fmt.Println("Done")
}
Позволяют синхронизировать доступ к мапе, обеспечивая эксклюзивный доступ для записи и чтения.
package main
import (
"fmt"
"sync"
)
type SafeMap struct {
mu sync.Mutex
m map[int]int
}
func NewSafeMap() *SafeMap {
return &SafeMap{
m: make(map[int]int),
}
}
func (sm *SafeMap) Store(key, value int) {
sm.mu.Lock()
defer sm.mu.Unlock()
sm.m[key] = value
}
func (sm *SafeMap) Load(key int) (int, bool) {
sm.mu.Lock()
defer sm.mu.Unlock()
value, ok := sm.m[key]
return value, ok
}
func main() {
sm := NewSafeMap()
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
sm.Store(i, i)
}(i)
}
wg.Wait()
if value, ok := sm.Load(42); ok {
fmt.Println("Found:", value)
} else {
fmt.Println("Not found")
}
}
Это потокобезопасная структура данных, специально созданная для конкурентного использования. Она предоставляет высокоуровневые методы для безопасной работы с мапой без необходимости управления мьютексами вручную.
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
m.Store(i, i)
}(i)
}
wg.Wait()
if value, ok := m.Load(42); ok {
fmt.Println("Found:", value)
} else {
fmt.Println("Not found")
}
}
Позволяет более точный контроль над доступом к мапе. Могут быть использованы для различных структур данных, не только для мап.
Упрощает код, устраняя необходимость в ручной синхронизации. Оптимизирован для сценариев с частыми чтениями и редкими записями.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
sync.Mutex
обеспечивает эксклюзивный доступ для чтения и записи.sync.RWMutex
позволяет одновременное чтение несколькими горутинами и эксклюзивный доступ для записи.var mu sync.Mutex
var rwMu sync.RWMutex
func increment() {
mu.Lock()
counter++
mu.Unlock()
}
func readCounter() int {
rwMu.RLock()
defer rwMu.RUnlock()
return counter
}
Синхронизируют горутины через передачу данных. Буферизованные каналы могут хранить несколько значений, небуферизованные требуют синхронной отправки и получения.
ch := make(chan int, 1)
go func() { ch <- 42 }()
fmt.Println(<-ch)
Позволяют основной горутине ждать завершения всех запущенных горутин.
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); /* работа */ }()
wg.Wait()
Потокобезопасная карта для конкурентного доступа.
var m sync.Map
m.Store("key", "value")
value, ok := m.Load("key")
Гарантирует выполнение кода только один раз.
var once sync.Once
once.Do(func() { /* инициализация */ })
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Предоставляют механизм для безопасного выполнения низкоуровневых операций чтения и записи данных без использования блокировок, таких как мьютексы. Эти операции гарантируют, что изменения данных будут завершены полностью и последовательно, что позволяет избежать состояний гонки.
atomic.LoadInt32
, atomic.LoadInt64
, atomic.LoadUint32
, atomic.LoadUint64
, atomic.LoadUintptr
atomic.StoreInt32
, atomic.StoreInt64
, atomic.StoreUint32
, atomic.StoreUint64
, atomic.StoreUintptr
var x int32
atomic.StoreInt32(&x, 42)
value := atomic.LoadInt32(&x)
atomic.AddInt32
, atomic.AddInt64
, atomic.AddUint32
, atomic.AddUint64
var x int32
atomic.AddInt32(&x, 1)
atomic.CompareAndSwapInt32
, atomic.CompareAndSwapInt64
, atomic.CompareAndSwapUint32
, atomic.CompareAndSwapUint64
var x int32 = 42
swapped := atomic.CompareAndSwapInt32(&x, 42, 100)
atomic.SwapInt32
, atomic.SwapInt64
, atomic.SwapUint32
, atomic.SwapUint64
var x int32
old := atomic.SwapInt32(&x, 100)
atomic.LoadPointer
, atomic.StorePointer
, atomic.SwapPointer
, atomic.CompareAndSwapPointer
var ptr unsafe.Pointer
atomic.StorePointer(&ptr, unsafe.Pointer(&x))
p := atomic.LoadPointer(&ptr)
Атомарные операции могут быть быстрее, чем использование мьютексов, так как они выполняются без блокировок. Их следует использовать, когда требуется минимальная задержка и высокая производительность.
Атомарные операции идеальны для реализации простых счетчиков, флагов или индикаторов состояния.
Когда требуется низкоуровневый контроль над синхронизацией данных без затрат на мьютексы.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int32
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt32(&counter, 1)
}()
}
wg.Wait()
fmt.Println("Final Counter:", counter)
}
Атомарные операции не подходят для более сложных операций, требующих нескольких шагов, которые должны быть атомарными. В таких случаях лучше использовать мьютексы.
Атомарные операции работают с простыми типами данных (числа, указатели). Для сложных структур данных лучше использовать другие механизмы синхронизации.
Код, использующий атомарные операции, может быть сложнее для понимания и поддержки, особенно если требуются сложные логические операции.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Создание дочернего контекста данных в Go предоставляет мощные возможности для управления временем выполнения операций, отмены и передачи метаданных.
Контексты позволяют задавать дедлайны и таймауты для операций.
context.WithTimeout
создает контекст с таймаутом, после которого операция будет автоматически отменена.ctx, cancel := context.WithTimeout(parentCtx, 2*time.Second)
defer cancel()
context.WithDeadline
создает контекст с дедлайном, который определяет точное время, после которого операция будет отменена.deadline := time.Now().Add(5 * time.Second)
ctx, cancel := context.WithDeadline(parentCtx, deadline)
defer cancel()
Контексты позволяют явно отменять операции, что полезно для управления горутинами и предотвращения утечек памяти.
context.WithCancel
создает контекст, который может быть отменен вручную с помощью функции cancel
.ctx, cancel := context.WithCancel(parentCtx)
defer cancel()
Контексты позволяют передавать данные между функциями, что полезно для передачи информации о запросах, пользователей и других данных.
context.WithValue
создает контекст, который содержит пару ключ-значение для передачи метаданных.type key string
ctx := context.WithValue(parentCtx, key("userID"), 12345)
Можно создавать иерархии контекстов, где каждый дочерний контекст наследует отмену и дедлайны от родительского.
Создание вложенных контекстов позволяет строить гибкие и сложные системы управления временем выполнения и отмены.
ctx1, cancel1 := context.WithCancel(parentCtx)
ctx2, cancel2 := context.WithTimeout(ctx1, 1*time.Second)
defer cancel1()
defer cancel2()
Контексты обеспечивают механизм для синхронизации и координации работы нескольких горутин.
Пример синхронизации горутин
var wg sync.WaitGroup
ctx, cancel := context.WithCancel(parentCtx)
defer cancel()
wg.Add(2)
go func() {
defer wg.Done()
worker(ctx, "Worker 1")
}()
go func() {
defer wg.Done()
worker(ctx, "Worker 2")
}()
wg.Wait()
func worker(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name, "stopped")
return
default:
fmt.Println(name, "working")
time.Sleep(1 * time.Second)
}
}
}
Контексты широко используются в веб-серверах для управления жизненным циклом HTTP-запросов, обеспечивая таймауты и отмену при завершении обработки запросов.
Пример использования контекста в обработчике HTTP-запроса
func handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
select {
case <-time.After(5 * time.Second):
fmt.Fprintln(w, "Request processed")
case <-ctx.Done():
err := ctx.Err()
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В Go контексты позволяют управлять временем выполнения и отменой операций в многопоточной среде. Отмена контекста распространяется на все дочерние контексты, что позволяет эффективно контролировать выполнение связанных горутин и операций.
Исходный контекст, от которого создаются дочерние контексты.
Контекст, созданный на основе родительского контекста с дополнительными свойствами, такими как таймаут, дедлайн или значение.
Когда родительский контекст отменяется, отменяются и все его дочерние контексты. Это распространяется рекурсивно на все уровни вложенности.
Корневой контекст без отмены и таймаутов.
Корневой контекст для временного использования.
Создает контекст с возможностью явной отмены.
Создает контекст с таймаутом.
Создает контекст с дедлайном.
Создает контекст с добавлением пары ключ-значение.
Отмена родительского контекста распространяется на дочерние контексты.
package main
import (
"context"
"fmt"
"time"
)
func main() {
// Создаем родительский контекст с возможностью отмены
parentCtx, cancel := context.WithCancel(context.Background())
// Создаем дочерний контекст с таймаутом на основе родительского контекста
ctx, cancelChild := context.WithTimeout(parentCtx, 2*time.Second)
defer cancelChild()
go func() {
// Дочерняя горутина, которая слушает отмену контекста
select {
case <-ctx.Done():
fmt.Println("Child context canceled:", ctx.Err())
}
}()
// Ждем некоторое время и отменяем родительский контекст
time.Sleep(1 * time.Second)
cancel()
// Ждем завершения дочерней горутины
time.Sleep(1 * time.Second)
}
Когда отменяется родительский контекст, все дочерние контексты (и их дочерние контексты) также отменяются.
Дочерние контексты могут иметь свои собственные условия отмены (например, таймауты), но отмена родительского контекста всегда приводит к отмене всех дочерних.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это метод развертывания приложений, который минимизирует время простоя и снижает риски, связанные с обновлением. Он позволяет плавно переключаться между двумя идентичными средами, называемыми "синей" (blue) и "зеленой" (green).
Синяя среда: (blue environment): Текущая версия приложения, работающая в продакшене.
Зеленая среда
(green environment): Новая версия приложения, готовая к развертыванию.
Трафик направляется на одну из сред (синюю или зеленую), в зависимости от того, какая версия приложения должна быть активной.
Новая версия приложения развертывается в неактивной среде (например, зеленой). После успешного тестирования переключается трафик на обновленную среду.
Имеются две идентичные среды: синяя и зеленая. Синяя среда обслуживает текущий трафик пользователей.
Новая версия приложения развертывается в зеленой среде, которая в данный момент не принимает пользовательский трафик.
Зеленая среда тестируется для проверки правильности работы новой версии приложения.
Если тестирование прошло успешно, трафик переключается на зеленую среду, и она становится активной. Синяя среда теперь неактивна и может быть использована для следующего обновления.
Если обнаруживаются проблемы с новой версией, трафик можно быстро переключить обратно на синюю среду.
Переключение трафика происходит мгновенно, что сводит время простоя к минимуму.
В случае проблем с новой версией можно быстро вернуться к предыдущей стабильной версии, просто переключив трафик обратно.
Новая версия приложения может быть протестирована в продакшн среде, не влияя на текущих пользователей.
Разделение процессов развертывания и переключения трафика снижает риски, связанные с обновлением.
Представим, что у нас есть веб-приложение, развернутое в синей среде. Мы хотим обновить приложение до новой версии, используя сине-зеленый деплой.
Создаем или обновляем зеленую среду с новой версией приложения.
Проверяем работу новой версии в зеленой среде, проводим необходимые тесты.
Обновляем настройки балансировщика нагрузки, чтобы направить весь пользовательский трафик на зеленую среду.
Следим за состоянием зеленой среды. Если всё работает корректно, зеленая среда остается активной.
Если возникают проблемы, переключаем трафик обратно на синюю среду.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это метод развертывания приложений, при котором новая версия программного обеспечения внедряется постепенно, направляя сначала небольшую часть трафика на новую версию. Этот метод позволяет минимизировать риски, связанные с обновлением, путем постепенного увеличения нагрузки на новую версию и мониторинга ее поведения.
Новая версия приложения внедряется в продакшен окружение, но обслуживает лишь небольшую часть пользователей. По мере успешного прохождения тестирования и мониторинга, трафик на новую версию увеличивается.
Производится непрерывный мониторинг новой версии для обнаружения возможных проблем. В случае возникновения проблем, трафик может быть быстро перенаправлен обратно на старую версию.
Позволяет выявить и исправить ошибки на ранних этапах, не затрагивая всех пользователей. Снижает вероятность массового сбоя системы.
В случае проблем можно быстро откатить изменения, направив трафик обратно на старую версию.
Поддерживает практику непрерывной интеграции и доставки (CI/CD), позволяя часто и безопасно развертывать новые версии.
Новая версия тестируется на небольшой группе реальных пользователей, что помогает выявить проблемы, которые могли быть пропущены в тестовом окружении.
Новая версия приложения развертывается на небольшое количество серверов или контейнеров.
Балансировщик нагрузки перенаправляет небольшую часть трафика на новую версию.
Постоянный мониторинг производительности и поведения новой версии.
Если новая версия работает стабильно, постепенно увеличивается объем трафика, направляемого на нее.
Если возникают проблемы, трафик быстро перенаправляется обратно на старую версию.
Текущая архитектура:
- Версия 1.0 (старая версия) на 9 серверах
- Версия 2.0 (новая версия) на 1 сервере
Балансировщик нагрузки:
- Направляет 10% трафика на сервер с версией 2.0
- Направляет 90% трафика на серверы с версией 1.0
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это метод развертывания, при котором новая версия приложения разворачивается в продакшен среде, но не обрабатывает пользовательские запросы напрямую. Вместо этого, новая версия работает в фоновом режиме, обрабатывая копии реальных запросов или синтетические запросы для проверки и мониторинга.
Новая версия разворачивается вместе с текущей версией, но не обслуживает реальные пользовательские запросы.
Новая версия обрабатывает копии запросов, направляемых на текущую версию, или синтетические запросы, созданные для тестирования. Результаты работы новой версии сравниваются с результатами текущей версии для выявления проблем.
После успешного тестирования новая версия начинает обслуживать реальные запросы.
Тестирование новой версии в реальной продакшен среде без воздействия на пользователей.
Возможность обнаружения проблем до того, как новая версия начнет обслуживать реальные запросы.
Сравнение производительности новой версии с текущей в реальных условиях.
Новая версия приложения развернута в продакшен среде.
Новая версия получает копии реальных запросов.
Результаты обработки копий запросов сравниваются с результатами текущей версии.
После успешного тестирования новая версия начинает обрабатывать реальные запросы.
Это метод развертывания, при котором одновременно используются две версии приложения (A и B), каждая из которых обрабатывает часть пользовательских запросов. Этот метод позволяет сравнивать производительность и поведение двух версий в реальных условиях.
Версия A (текущая версия) и версия B (новая версия) развернуты в продакшен среде.
Трафик распределяется между двумя версиями по определенной пропорции (например, 50% на A и 50% на B).
Производительность и поведение двух версий сравниваются для определения лучшей версии.
Возможность сравнивать две версии приложения в реальных условиях.
Получение реальных данных о предпочтениях пользователей и производительности.
Возможность плавного перехода от старой версии к новой, основываясь на результатах сравнения.
Текущая версия (A) и новая версия (B) развернуты в продакшен среде.
Балансировщик нагрузки распределяет трафик между A и B.
Производительность и поведение версий сравниваются.
На основе анализа выбирается лучшая версия для полного развертывания.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это формальный договор между поставщиком услуги и клиентом, определяющий уровень обслуживания, который поставщик обязуется предоставить. SLA описывает конкретные измеримые аспекты сервиса, такие как доступность, производительность, время отклика, а также механизмы разрешения инцидентов и компенсации за несоблюдение договоренностей.
Описание услуг, которые предоставляет поставщик, и их характеристики.
Гарантированный процент времени, в течение которого услуга будет доступна (например, 99.9% времени).
Показатели производительности, такие как время отклика, пропускная способность и другие метрики.
Среднее время, необходимое для восстановления сервиса после сбоя.
Среднее время на принятие мер после обнаружения проблемы.
Описание уровней поддержки, доступных клиенту (например, 24/7 поддержка, время реакции на запросы).
Механизмы уведомления клиента о проблемах и процедуры эскалации в случае серьезных инцидентов.
Механизмы компенсации клиенту за несоблюдение SLA, такие как кредиты или скидки на услуги.
Описание методов и частоты мониторинга выполнения SLA, а также предоставление отчетов клиенту.
"Поставщик обязуется предоставлять услуги хостинга для веб-приложений клиента с использованием своих дата-центров."
"Услуга будет доступна не менее 99.9% времени в течение календарного месяца."
"Среднее время отклика сервиса не должно превышать 200 миллисекунд."
"Среднее время восстановления после сбоя не должно превышать 4 часов."
"Поставщик обязуется предоставлять круглосуточную поддержку с максимальным временем реакции на запросы не более 30 минут."
"В случае несоблюдения уровня доступности 99.9%, клиент имеет право на компенсацию в виде 10% кредита за каждый час простоя."
SLA устанавливает четкие ожидания относительно уровня обслуживания, что снижает недоразумения между поставщиком и клиентом.
SLA способствует ответственности поставщика за предоставляемые услуги и позволяет клиенту контролировать их качество.
SLA помогает управлять рисками, связанными с отказами или снижением качества обслуживания, и обеспечивает механизмы компенсации.
Наличие SLA повышает доверие клиентов к поставщику, демонстрируя его готовность поддерживать высокий уровень обслуживания.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM