Aleksey
sql.Open() возвращает у тебя в DB, в этот момент ты берешь database.DB и обращаешься к нему.
В какой этот, ты делаешь Open() по сути ещё даже с базой соединение не устанавливается.
heavycharged
heavycharged
ладно, забей
Maxim
Это пока устраивает. А потом не будет устраивать, но забудется и придется искать причину ошибки. Так что лучше сразу нормально сделать.
Если задача требует высокой производительности, мьютексы являются узким местом (а они не то чтобы очень быстрые) и в софте race не приведет к пиздецу то можно и выпилить.
Maxim
Правда пример такого софта я не могу привести) Но есть софт где локи много выедают.
Aleksey
go-database-sql.org/accessing.html Perhaps counter-intuitively, sql.Open() does not establish any connections to the database, nor does it validate driver connection parameters. Instead, it simply prepares the database abstraction for later use. 
Andrey
go-database-sql.org/accessing.html Perhaps counter-intuitively, sql.Open() does not establish any connections to the database, nor does it validate driver connection parameters. Instead, it simply prepares the database abstraction for later use. 
Самое интересное, что он даже не проверяет, что соединение может быть установлено. Поэтому после этого мы при ините вызываем db.Ping() Чтобы оно проверило и ругнулось в случае чего
heavycharged
ладно, забей
Aleksey
ладно, забей
Смотри https://github.com/Supme/gonder/blob/master/models/config.go#L33 Это потом используется во всём приложении и для рассылки в тысячи потоков и для статистики и для апи. Если не ограничить коннекты к базе, то база будет через какое то время делать отлуп
Andrey
Правда пример такого софта я не могу привести) Но есть софт где локи много выедают.
Еще очень интересно как работает RWMutex. Допустим есть 1000 горутин, которые вызвали RLock() и в этот момент читают данные. Вызываем в другой рутине Lock(), она будет ждать пока эта 1000 дочитает, это предсказуемо. Но в тоже время, если у нас появятся еще 500 читателей, то они будут ждать пока первая 1000 дочитает, потом, когда запишется и только потом смогут получить свои данные и это мне показалось несколько странно. Потому, что за это время уже можно ответить на запросы из тех данных, что есть.
heavycharged
поднимать коннект в init, это шляпа
Andrey
Lock приоритетнее чем RLock
Lock будет ждать пока существующие RLock не разблокируются. И заблокирует все новые RLock.
Aleksey
поднимать коннект в init, это шляпа
Нормально работает, а тот селект 1 это проверка что не голая база
Aleksey
Инит один раз происходит
Maxim
Lock будет ждать пока существующие RLock не разблокируются. И заблокирует все новые RLock.
Да, ты же можешь изменить данные поэтому и остальные читатели ждут, потому что ты уведомил их что сейчас будешь что-то изменять.
heavycharged
Нормально работает, а тот селект 1 это проверка что не голая база
я ж говорю, в твоем случае, да, и пусть весь мир подождет, пока твой инит поднимет коннект и удостоверится. в других приложениях иногда важно не копить в пул коннекты, особенно если прет сильный трафик, твоему серверу просто не дадут подняться и разгрести всю работу. проще начать отшивать коннекты по одному, после чего, когда база поднимется, уже отвечать реальным ответом рабочим, а не ошибкой.
Andrey
Я сейчас либо найду информацию что указатель при состоянии гонки может повредиться, либо так и оставлю.
Maxim
Я не понимаю, что показалось странным.
Вторые 500 читателей появились уже после того как я уведомил, что хочу изменить данные. Что в этом странного)
Andrey
Вторые 500 читателей появились уже после того как я уведомил, что хочу изменить данные. Что в этом странного)
В том, что если вас устраивает, что они могут получить за время лока старые данные и это будет корректно - то они лочатся напрасно.
heavycharged
ещё разок
Aleksey
я ж говорю, в твоем случае, да, и пусть весь мир подождет, пока твой инит поднимет коннект и удостоверится. в других приложениях иногда важно не копить в пул коннекты, особенно если прет сильный трафик, твоему серверу просто не дадут подняться и разгрести всю работу. проще начать отшивать коннекты по одному, после чего, когда база поднимется, уже отвечать реальным ответом рабочим, а не ошибкой.
После рассылок в сотни тысяч, люди сотнями в секунду открывают письма, даже, в эти моменты рестартовали, не потеряв ни одного открытого письма в статистике, потому что когда рестартуем, http сервер не слушает, он начинает слушать когда всё готово, для клиентов это затык в сети меньше чем 100мс
Andrey
Юзайте пакет unsafe) Только осторожно)
какую именно возможность из него стоит изучить?
Maxim
какую именно возможность из него стоит изучить?
Ну, возможность у него одна - читать и записывать произвольную память. С тех времен как конкуретное чтение мапок стало алертить он спасает)
Andrey
Ну, возможность у него одна - читать и записывать произвольную память. С тех времен как конкуретное чтение мапок стало алертить он спасает)
охох) нет, это не наш выбор. мы пошли намного более безопасным и быстрым путём в вопросе параллельной записи и чтения мап
Andrey
Хотя и чуть более отъедает память
Andrey
Шардирование?
Нет. У нас задача как можно быстрее отдавать ответ, не меняя данные в процессе ответа. Поэтому мы имеем "кеш" в работе, который только читается и для всех новых клиентов подменяем указатель на новый прогретый кеш.
Andrey
Поэтому в существующем кеше нет состояния гонки в мапах (они только читаются) и при этом мы имеем возможность кеш обновлять.
Andrey
Не понял вашего вопроса
Andrey
Если горутины уже не будут ссылаться на старый кеш - он его соберет
Andrey
Если будут ссылаться - не соберет. Логично же?
Aleksey
Не понял вашего вопроса
И попортит данные предыдущие
Zver
А как вы заполняете второй кэш?
Andrey
Указатель будет замкнут в горутине. Почему сборщик может попортить данные?
Andrey
А как вы заполняете второй кэш?
В отдельной горутине
Andrey
Там все медленные процессы хождения в базу и подготовки данных
Zver
А если в момент подмены ещё и сборщик придёт?
Он их не соберет, пока используется.
Andrey
По порядку)
Aleksey
А, понял рабочая ссылка одна, а меняем её на обновлённую в которой данные, ок.
Maxim
По порядку)
Да не, можно не отвечать уже) Я понял, тогда ваш костыль будет норм работать)
Andrey
1. На каждый запрос мы в канал пишем id сущности которую запросили 2. В отдельной горутине канал слушаем и проверяем, что данные устарели (были обновлены n секунд назад) или вообще не сущетсвуют 3. Обновляем 4. Меняем указатель
Andrey
Магия, но быстрее решения не придумал
Maxim
Магия, но быстрее решения не придумал
а bigcache пробовали? Я не уверен что он быстрее, но он очень интересно хранит данные в одной куче и по оффсетам достает. Должно быть очень быстро и конкуретно)
Zver
Магия, но быстрее решения не придумал
Есть вероятность, что все гоурутины встанут в ожидании, пока наполнитель кэша будет обрабатывать данные на пополнение кэша.
Andrey
а, кстати, я его изучал. Шардирование - тоже рассматривали как вариант. Но он внутри все равно с лочками. И в нашем варианте выглядит все проще.
Aleksey
А какая нагрузка то?
Andrey
А какая нагрузка то?
Да никакой) просто развлекаюсь
Zver
Почему?
Потому что запись в канал блокирующая операция (в которой, кстати мютексы используются) и пока данные не изымут из канала горутина будет висеть. Либо делать буфер с запасом.
Andrey
В проде сейчас в среднем 800 запросов в секунду, но там пхп и тоже все оптимизированно, что даже на 10% проц не грузит.
Aleksey
Гошка с шаблонами штатными гигабитный канал запросто забивала, причём был ещё xorm но с включеным кэшем
Andrey
Покажите.
select{ case ch <- id: case default: }
Andrey
канал с большим буфером, естественно
heavycharged
Можно шардить мапы, в каждой мапе есть RWMutex, сами сущности кеша через бинарный семафор и закрытый канал работают. Если канал закрыт, чтение мгновенное, отдаем значение. Если канал открыт, тогда за значением уже кто-то пришел, стоит очередь, и когда значение получено, канал закрывается и все получают свои значения. Т.о. чтение значения entity сопровождается чтением из канала в пустоту. Сами мапы можно и без RWMutex сделать на каналах. Но каналы по 100 нс выжирают. Это как раз ваш кейс, когда за одним значением пришло несколько горутин, все получат один и тот же ответ, полученный единоразово из базы или откуда-то.
Aleksey
В проде сейчас в среднем 800 запросов в секунду, но там пхп и тоже все оптимизированно, что даже на 10% проц не грузит.
Я когда впервые гошку пробовал, было откровение после пыха 5.6 , что время ответов с другой буквы м указываются.
heavycharged
вы на глаз определили? или как? конечно держать извечно прогретый кеш и подменять указатель будет быстрее, но по памяти - вряд ли.
heavycharged
к слову, в вашем кейсе вместо того чтобы копить очередь на открытом канале, можно отдавать oldValue, который создан перед тем как пойти за значением
Daniel
коллеги, что тут у вас за содомия?