-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sprint 04 #6
Sprint 04 #6
Conversation
d5e9ac0
to
3833023
Compare
5c53bca
to
6675a9a
Compare
6675a9a
to
30ed88c
Compare
098a6b0
to
ee2c6bd
Compare
38a3711
to
6966ab7
Compare
) | ||
|
||
type bulkSender struct { | ||
msCtx context.Context |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
контекст нежелательно хранить в рамках описания структур
придерживаться правила keep Context out of structs
использовать контекст в рамках передаче параметров, таймаута при вызовах API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
client *resty.Client | ||
metrics []*model.Metric | ||
batchLimit int | ||
mutex sync.RWMutex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
можно использовать возможности эмбеддинга без указания названия параметра (Anonymous Embedded Fields
)
type bulkSender struct {
...
sync.RWMutex
}
при таком описании вызовы можно сократить до
s.Lock()
defer s.Unlock()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
cmd/agent/configs/config.go
Outdated
return useBuffSendClient | ||
} | ||
|
||
func GetBuffBatchLimit() int { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
реализация методов аналогична пакету
можно переиспользовать его
cmd/agent/configs/config.go
Outdated
} | ||
|
||
func GetBuffSendInterval() time.Duration { | ||
buffSendInterval := os.Getenv("BUFF_SEND_INTERVAL") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BUFF_SEND_INTERVAL
- неизменняеые переменные (текст, числа) лучше определять как константы
@@ -46,3 +49,37 @@ func GetServerAddress() string { | |||
func GetHashKey() string { | |||
return os.Getenv("KEY") | |||
} | |||
|
|||
func UseBuffSenderClient() bool { | |||
useBuffSendClient, err := strconv.ParseBool(os.Getenv("USE_BUFF_SEND_CLIENT")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
можно не использовать дополнительный флаг, а использовать ранее описанную переменную BUFF_BATCH_LIMIT
:
если значение 0 или -1, то обычная отправка
если значение не 0 (в идеале >= 2), то использовать отправку метрик "пачками"
metrics: make([]*model.Metric, 0, batchLimit), | ||
batchMetricsCh: make(chan []*model.Metric), | ||
} | ||
go sender.startSenderListener(msCtx, sendInterval) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
пожелание
порядок описания методов упорядочить по их непосредственному вызову
если метод содержит в себе доп.вызовы, то располагать их сразу же за вызывающей функцией
такой подход увеличивает удобстов и читабельность:
реализации вызываемых функций располагаются рядом и можно просматривать их "сверху вниз", не перескакивая по всему файлу
например,
func myFunc1():
func2()
func3()
func func2() {
func4()
...
}
func func4() {
...
func func3() {
...
для данного файла:
NewBulkMetricSender()
startSenderListener()
uploadMetrics()
sendMetricsAsync()
sendMetrics()
SendMetric() <- можно в начало, сразу же после "конструктора" т.к. метод публичный
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
ticker.Stop() | ||
return | ||
} | ||
if len(metrics) != 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
отправка данных только по интервалу, заданному при старте сервиса:
весь ранее собранный список метрик делится чанки, заданного размера и отправляется на сторону сервера
сейчас отправка происходит сразу же, как только количество метрик превысило размер чанка
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
в этом и была идея, если чанк заполнен - отправлять
если не заполнен и что то есть, то отправить через интервал, чтоб данные не зависли до след сбора
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
такое поведение будет неявным, т.к. нельзя с уверенностью сказать, в какой именно период данные будут отправляться: интенсивно в начале периода, интенсивно в конце периода, хаотично
изначально, в конфигурации аганта уже задан параметр reportInterval
, определяющий периоды отправки
до этого момента метрики будут копиться в некотором буфере, а далее отправляться
такое поведение эмулирует штатные ситуации, например:
- метрики нужно отсылать с определенной периодичностью - 1/5/10м/30 мин, 1/4/12 часов - системы мониторинга вроде Zabbix, Nagios, Cacti, Prometheus, etc конфигурируются по такому принципу;
- на сервере есть ограничение на отправку, которое обнуляется по некоторому периоду - но в такой ситуации лучше дополнительно обрабатывать ответ и повторять отправку n-е количество раз или с некоторой задержкой;
в этих кейсах ожидается, что данные будут отпрявляться только с некоторой периодичностью, но никак иначе
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
отправку данных сразу же при наполнении буфера можно предусмотреть, когда reportInterval
равен 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
func (s *bulkSender) uploadMetrics() []*model.Metric { | ||
s.mutex.Lock() | ||
metrics := s.metrics | ||
s.metrics = make([]*model.Metric, 0, s.batchLimit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предложение подумать, над текущим решением и архитектурой
использование make
каждый раз переаллоцирует занимаемую под структуру память, что затратно
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
if len(s.metrics) >= s.batchLimit { | ||
log.Printf("Flush batch of '%v' metrics\n", len(s.metrics)) | ||
s.batchMetricsCh <- s.metrics | ||
s.metrics = make([]*model.Metric, 0, s.batchLimit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предложение подумать, над текущим решением и архитектурой
использование make
каждый раз переаллоцирует занимаемую под структуру память, что затратно
можно попробовать:
- оставить только канал, как единую структуру взаимодействия
- использовать слайсы
детально про массив и слайсы
внутреннее устройство
так же посмотреть, как работает append/make с массивами/слайсами, и как меняется адресация, len, cap
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
func (s *bulkSender) startSenderListener(ctx context.Context, sendInterval time.Duration) { | ||
ticker := time.NewTicker(sendInterval) | ||
for { | ||
var metrics []*model.Metric |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
метод усложнен
хотелось бы, чтобы вызовы происходили последовательно, т.е.
при кейсе с тикером - вся лоигка отправки данных
при кейсе с контекстом - завершение и освобождение ресурсов
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
689362d
to
4b046f2
Compare
4b046f2
to
f9d0871
Compare
internal/exit_handler.go
Outdated
@@ -41,6 +41,7 @@ func (eh *ExitHandler) shutdown() { | |||
select { | |||
case <-successfullyFinished: | |||
log.Println("System finished work, graceful shutdown") | |||
//time.Sleep(time.Second) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
неиспользуемый код лучше сразу же вычищать
стараться не увеличивать энтропию ( :
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ок
} | ||
} | ||
|
||
// Looks like useless for current project specific :(((( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
неиспользумый код лучше сразу же вычищать
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
нуу ок
cmd/agent/service/collector.go
Outdated
} | ||
|
||
func (cmr *commonMetricCollector) processGopsMetrics() { | ||
metrics := make([]*model.Metric, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
можно сразу же задать емкость структуры:
минимум - 3 метрики (общая память, свободная память, загрузка 1го процессора), максимум - динамическое значение, в зависимости от количества ядер
metrics := make([]*model.Metric, 0, 3)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
cmd/agent/service/collector.go
Outdated
memoryStat, _ := mem.VirtualMemory() | ||
metrics = append(metrics, cmr.mf.NewGaugeMetric("TotalMemory", model.GaugeVT(memoryStat.Total))) | ||
metrics = append(metrics, cmr.mf.NewGaugeMetric("FreeMemory", model.GaugeVT(memoryStat.Free))) | ||
cpuUsed, _ := cpu.Percent(time.Second*10, true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"магическое число" в параметре вызова
параметр периода опроса можно задать как 0
If an interval of 0 is given it will compare the current cpu times against the last call.
или пробрасывать из конфигурации
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Магическим его сложно назвать, согалсно документации оно задано однозначно и не предполагает изменений в дальнейшем через параметры или флаги :)
Имя метрики: "CPUutilization1", тип: gauge - загрузка ядра в процентах за 10 секунд (точное количество - по числу CPU определяемое во время исполнения)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
при изменении ТЗ придется изменять все значения в кода, которые используют данное значение
при выносе в константы или в рамках параметра структуры получаем некоторую параметризацию
и минимальный дифф для изменений
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
добавил константу
cmd/agent/repositories/repository.go
Outdated
func (cmr *commonMetricRepository) GetMetrics() []*model.Metric { | ||
cmr.Lock() | ||
defer cmr.Unlock() | ||
metrics := make([]*model.Metric, 0, len(cmr.cache)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
начиная с 1.18 версии, появился аналогичный фунционал получения значений - map.Values
values := maps.Values(<map>)
пакет экспериментальный: использование на свое усмотрение
можно ознакомиться с реализациями, как примеры использования дженериков
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
в целом там тоже самое, тащить експериментальный импорт ради одной функции мб не лучшая идея, но использовал для "пусть будет так"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
можно не тащить весь пакет, а только скопипастить реализации
и дополнить некоторым комментом, что взято из некоторого пакета: на случай, если реализации добавят в основные батарейки
cmd/agent/service/poller.go
Outdated
@@ -49,9 +49,9 @@ func (cmp *commonMetricPoller) PollMetrics() chan struct{} { | |||
case <-ticker.C: | |||
start := time.Now() | |||
log.Println("Poll metrics start") | |||
metrics := cmp.mr.GetMetricsList() | |||
metrics := cmp.mr.GetMetrics() | |||
cmp.sendMetrics(metrics) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
текущий вызов может содержать ошибки при выполнении
которые стоит обрабатывать и в зависимости от уровня критичности соответствующе обрабатывать или завершать работу сервиса
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
обновил
err := js.SendMetrics(js.buffer) | ||
if err != nil { | ||
return fmt.Errorf("cannot send batch of metrics: %v", err) | ||
func (js *jsonSender) SendMetrics(ctx context.Context, metrics []*model.Metric) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
методы дублируется в text_sender
и bulk_sender
стоит подумать над объединением общего кода и выноса в некоторую абстракцию или независимый метод
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
text и json согласен,
в bulk все же по другому
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
выделил разные интерфейсы MetricSender - MetricsSender и композицию для общего Sender
case metrics := <-s.batchMetricsCh: | ||
log.Printf("Sending bulk %d metrics", len(metrics)) | ||
err := s.sendMetrics(metrics) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
хорошая практика возвращать ошибку в рамках выполнения метода
но не "глушить" явно
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
обновил
//} | ||
|
||
func (s *bulkSender) startSendMetricsListener(ctx context.Context) { | ||
go func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
горутины можно запускать явно через указание go
перед вызываемым методом
go sender.startSendMetricsListener(msCtx)
такой подход дает возможность запускать метод как синхронно, так и асинхронно
нет необходимости определять и вызывать анонимные функции в рамках метода
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
убрал листенер, тк в целом все тормозилось об каналы и в асинхронности нет смысла + обработка ошибок затрудняется - нужен до канал на них
sender := &bulkSender{ | ||
client: client, | ||
batchLimit: batchLimit, | ||
metrics: make([]*model.Metric, 0, batchLimit), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
неиспользуемый параметр
можно убрать из определения
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
убрал
edca830
to
d8fa5bf
Compare
Огромное спасибо за ревью! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
if dbConfig != "" { | ||
repository = repositories.NewPgRepository(dbConfig, ctx) | ||
|
||
if appConfig.DBConfig != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
27-45 можно инкапсулировать в рамках пакета: вынести в отдельный метод в рамках хранилища/repositories
сейчас реализация копирует "фабричный метод": по параметрам конфига возвращается нужная реализацию хранилища
No description provided.