![](https://habrastorage.org/webt/hr/6y/f5/hr6yf5w1hp0fh-i5vfa0p1pxeuy.png)
Redis Best Practices, часть 2
![](https://habrastorage.org/webt/hr/6y/f5/hr6yf5w1hp0fh-i5vfa0p1pxeuy.png)
Golang Developer
Как быть, если дерево поиска разрослось на всю оперативку и вот-вот подопрет корнями соседние стойки в серверной? Что делать с инвертированным индексом, жадным до ресурсов? Завязывать ли с разработкой под Android, если пользователю прилетает «Память телефона заполнена», а приложение едва на половине загрузки важного контейнера?
В целом, можно ли сжать структуру данных, чтобы она занимала заметно меньше места, но не теряла присущих ей достоинств? Чтобы доступ к хэш-таблице оставался быстрым, а сбалансированное дерево сохраняло свои свойства. Да, можно! Для этого и появилось направление информатики «Succinct data structures», исследующее компактное представление структур данных. Оно развивается с конца 80-х годов и прямо сейчас переживает расцвет в лучах славы big data и highload.
А тем временем на Хабре найдется ли герой, способный пересковоговорить три раза подряд
[səkˈsɪŋkt]?
Какое-то время назад перед нами встала проблема чистки кортежей в спейсах tarantool. Чистку нужно было запускать не тогда, когда у tarantool уже заканчивалась память, а заранее и с определенной периодичностью. Для этой задачи в tarantool есть модуль, написанный на Lua, под названием expirationd. После непродолжительного использования этого модуля мы поняли, что нам он не подходит: на постоянных чистках больших объемов данных Lua висел в GC. Поэтому мы задумались о разработке своего capped expirationd модуля, надеясь, что код, написанный на нативном языке программирования, решит наши задачи наилучшим образом.
Хорошим примером нам послужил модуль tarantool под названием memcached. Используемый в нем подход основывается на том, что в спейсе заводится отдельное поле, в котором указывается время жизни кортежа, иными словами, ttl. Модуль в фоне сканирует спейс, сравнивает ttl с текущим временем и принимает решение о том, удалять кортеж или нет. Код модуля memcached простой и элегантный, но слишком общий. Во-первых, он не учитывает тип индекса, по которому осуществляется обход и удаление. Во-вторых, на каждом проходе сканируются все кортежи, количество которых может быть довольно большим. И если в модуле expirationd первая проблема была решена (tree-индекс выделен в отдельный класс), то второй все так же не уделено никакого внимания. Это предопределило выбор в пользу написания своего кода.
Response View::Handle(Request&& request, const Dependencies& dependencies) {
auto cluster = dependencies.pg->GetCluster();
auto trx = cluster->Begin(storages::postgres::ClusterHostType::kMaster);
const char* statement = "SELECT ok, baz FROM some WHERE id = $1 LIMIT 1";
auto row = psql::Execute(trx, statement, request.id)[0];
if (!row["ok"].As<bool>()) {
LOG_DEBUG() << request.id << " is not OK of " << GetSomeInfoFromDb();
return Response400();
}
psql::Execute(trx, queries::kUpdateRules, request.foo, request.bar);
trx.Commit();
return Response200{row["baz"].As<std::string>()};
}
jsonb_path_query('{"a": [1,2,3,4,5]}', '$.a[*] ? (@ > 2)') возвращает 3, 4, 5
jsonb_path_query('{"a": [1,2,3,4,5]}', '$.a[*] ? (@ > 5)') возвращает 0 записей
#>>
, соответствующий функциям jsonb_each_text()
и jsonb_array_elements_text()
, раньше достаточно быстро преобразовывал JsonbValue в text, но работал неторопливо с другими типами. Сейчас всё работает быстро.Почему мы вообще хотим писать конкурентный код? Потому что процессоры перестали расти по герцовке и начали расти по ядрам. С каждым годом увеличивается количество ядер процессора, и мы хотим их эффективно утилизировать. Go — тот язык, который создан для этого. В документации так и написано.
Мы берём Go, начинаем писать конкурентный код. Конечно, ожидаем, что легко сможем обуздать мощь каждого ядра нашего процессора. Так ли это?
Меня зовут Артемий. Этот пост — вольная расшифровка моего доклада с GopherCon Russia. Он появился как попытка дать толчок людям, которые хотят разобраться, как писать хороший, конкурентный код.
Видео с конференции GopherCon Russia
interface{}
(пустой интерфейс).AMD продолжает развивать свою долгоиграющую платформу AM4. Недавно вышло новое поколение процессоров Ryzen на микроархитектуре Zen 2. Вообще, цикл развития архитектур AMD стал чем-то напоминать тик-так Intel, но не 1 в 1. Так, второе поколение Ryzen было скорее вариацией на тему изначальной архитектуры Zen с исправлением основных косяков и реализованное на чуть более тонком техпроцессе, что нашло отражение даже в названии архитектуры чипов 2xxx — Zen+. Сейчас же AMD выкатили чиплетную архитектуру. Получилась прямо классическая спираль развития — AMD в 2003 году первыми начали перенос компонент северного моста в ядра, начав с переноса в процессорах линейки K8 контроллера памяти в CPU и закончив тем, что Ryzen тысячной и двухтысячной серий представляли из себя полноценные SoC, так в 2019 они же снова вынесли северник в отдельный кристалл, пусть и на той же подложке, что и ядра.
Теоретических материалов, обзоров и тестов хватает и на русском (например Разгон Matisse или в поисках предела. Обзор архитектуры Zen 2), и на английском языках, мне же захотелось лично сравнить свежий AMD Ryzen 7 3700x с 2700x на моих тестах, аналогичным использованных в прошлых постах (пост 1, пост 2).
В тестах A/B мы попытались замедлять выдачу страниц с шагом 100 миллисекунд и обнаружили, что даже очень небольшие задержки приводят к существенному падению доходов. — Грег Линден, Amazon.com