- BrainTools - https://www.braintools.ru -
Представьте, что вам на собеседовании дали задачу: спроектировать систему доставки газа по трубам переменного давления, причём система должна загружаться почти на 100% в зоне высокого давления, а разгружаться (быстро и почти полностью) в зоне низкого. Вы бы, наверное, нарисовали линейную зависимость. Больше давления — больше загрузка. Просто, и главное, что будет легко тестировать.
Эволюция [1] посмотрела на этот вариант, подумала 500 миллионов лет и сделала всё наоборот.
Предлагаю чуть формализовать. У нас есть два «дата-центра»:
Лёгкие — давление кислорода [2] ~100 мм рт. ст. Тут надо загрузиться по максимуму.
Ткани — давление ~20–40 мм рт. ст. Тут надо отдать почти всё.
И есть молекула, которая мотается между ними по кровотоку. Задача: максимизировать разницу между «загрузился» и «разгрузился».
Если вы инженер (а вы, возможно, инженер), первая мысль — линейная зависимость, где загрузка пропорциональна давлению. То есть чем больше кислорода вокруг, тем больше связалось. Честный и весьма понятный даже школьникуy = kx.
Но проблема в том, что линейная кривая это палка о двух концах для этой задачи.
Вот посмотрите. При линейной зависимости разница насыщения между 100 мм рт. ст. и 40 мм рт. ст., ну, примерно 60% от максимума. Вроде нормально? К сожалению нет. Потому что в реальности ткани хотят получить кислород именно в узком диапазоне давлений, и линейная зависимость отдаёт его слишком равномерно (понемножку на каждом миллиметре давления). Как микросервис, который размазывает CPU по всем запросам одинаково, вместо того чтобы приоритизировать.
Гемоглобин — белок из четырёх субъединиц, каждая может связать одну молекулу O₂. Казалось бы, четыре независимых слота. Четыре boolean-а. Давайте загрузим по одному.
Но тут тоже нет.
Когда первая молекула кислорода садится на первую субъединицу, происходит конформационное изменение — белок меняет форму. И эта новая форма делает посадку второй молекулы легче. Вторая делает легче третью. Третья (соответственно) четвёртую.
binding_affinity[0] = LOW;
binding_affinity[1] = MEDIUM;
binding_affinity[2] = HIGH;
binding_affinity[3] = VERY_HIGH;
Это называется кооперативное связывание. И это даёт не прямую линию, а S-образную (сигмоидальную) кривую насыщения.
Внизу по давлению — кривая ползёт еле-еле., почти плоская. Гемоглобин упирается, не хочет брать кислород, а потом резкий взлёт (почти вертикальный). А уже наверху снова плато, насыщение под 98–99%.
А дальше…
При 100 мм рт. ст. (лёгкие) гемоглобин насыщен на ~98%. При 40 мм рт. ст. (ткани в покое) — на ~75%. При 20 мм рт. ст. (работающая мышца) — на ~30–35%. Разница между «загрузился» и «разгрузился» огромная, и именно в том диапазоне давлений, где это нужно.

Линейная зависимость дала бы при тех же параметрах разницу процентов в 60. Сигмоида даёт 65–70. Кажется, мелочь? Но это 65–70 на каждом цикле кровообращения, 70 раз в минуту, 24 часа в сутки. На масштабе — разница между «побежал за автобусом» и «упал в обморок, пытаясь встать с дивана».
Математически [3] это описывает уравнение Хилла:
Y = (pO₂)ⁿ / ((P₅₀)ⁿ + (pO₂)ⁿ)
Где Y — степень насыщения (0 до 1), pO₂ — парциальное давление кислорода, P₅₀ — давление, при котором насыщение = 50%, а n — коэффициент Хилла.
Вот этот n и есть вся суть.
При n = 1 — обычная гипербола. Так работает миоглобин (одна субъединица, без кооперативности). Загружается быстро, отдаёт неохотно. Хороший складской работник, паршивый курьер.
При n = 2.8 (реальный гемоглобин) — та самая сигмоида. Медленный старт, резкий переход и быстрое насыщение. Если б n было ровно 4 (по числу субъединиц), то это была бы идеальная кооперативность, все четыре сайта переключаются одновременно, как бистабильный триггер, но о природа не дотянула до 4. И, возможно, специально.
(Потому что если n = 4, система становится слишком «бинарной» — либо полностью загружен, либо полностью пуст. Никакой тонкой настройки. А n = 2.8 — это sweet spot между кооперативностью и гибкостью. Эволюция, проще говоря, нашла оптимум, который мы бы назвали «хорошим trade-off между throughput и latency».)
Ладно, S-кривая — это интересно, но гемоглобин пошёл дальше.

Работающие ткани производят CO₂ и молочную кислоту. pH падает, температура растёт ,и гемоглобин это чувствует. При снижении pH кривая сдвигается вправо и белок начинает отдавать кислород ещё активнее при том же давлении.
Это как если бы ваш балансировщик нагрузки не просто раскидывал запросы по round-robin, а мониторил температуру CPU на каждом сервере и автоматически перенаправлял трафик на холодные ноды. Только это не какой-нибудь навороченный service mesh — это одна молекула, четыре субъединицы, пара протонов.
Христиан Бор (отец того самого Нильса Бора, квантовая механика, судя по всему, передаётся генетически) описал этот эффект в 1904 году. (за 40 лет до того, как люди поняли структуру ДНК, между прочим).
# Эффект Бора в псевдокоде
if ph < 7.4 or pco2 > 40 or temperature > 37:
p50 += delta # сдвиг кривой вправо
# отдаём O2 активнее
Элегантно? Как по мне — очень. Один и тот же белок одновременно транспортирует O₂, сенсит pH, реагирует на температуру и всё это без единого if-а в привычном нам смысле. Чистая биохимия, чистые аллостерические взаимодействия.
А теперь баг, который прошёл code review эволюции и остался в продакшене.
Серповидноклеточная анемия [4] — одна точечная мутация в гене β-глобина, лдна аминокислота: глутаминовая кислота → валин. В позиции 6. Шестой символ в строке длиной 146. Один char.
- ...Val-His-Leu-Thr-Pro-Glu-Glu-Lys...
+ ...Val-His-Leu-Thr-Pro-Val-Glu-Lys...
Этот один символ меняет всё. Мутантный гемоглобин (HbS) при низком давлении кислорода начинает полимеризоваться — молекулы слипаются в длинные жёсткие нити. Эритроцит из мягкого пончика превращается в серп. Серпы застревают в капиллярах, рвут сосуды, вызывают адскую боль [5], инсульты, отказ органов.
Очень тяжёлая болезнь. До современной медицины это часто была смерть в детстве.
И вот вопрос: почему естественный отбор не выкосил эту мутацию за тысячи лет?
Потому что гетерозиготы (одна нормальная копия, одна мутантная) получают устойчивость к малярии. Плазмодий — паразит, который живёт внутри эритроцитов, — не может нормально размножаться в клетках с частичным содержанием HbS. Эритроцит деформируется, селезёнка его утилизирует вместе с паразитом. Грубо говоря, организм выкидывает заражённые контейнеры до того, как инфекция расползётся по кластеру.
Если посмотреть на карты, то это видно буквально: частота гена серповидноклеточности совпадает с ареалом малярийного плазмодия. Африка, Ближний Восток, Индия, Средиземноморье. Там, где малярия убивает, мутация спасает. Там, где малярии нет, — мутация просто вредит и вымывается отбором.
Это же классический полиморфизм, поддерживаемый балансирующим отбором. Или, если по-нашему, — это feature flag, который в одном окружении критичный баг, а в другом — конкурентное преимущество. И вы не можете его просто выключить, потому что для части пользователей он в проде держит SLA выше нуля.
Мне кажется, что если бы кто-то принёс гемоглобин на архитектурное ревью, его бы разнесли.
— Подождите, у вас четыре субъединицы, и они все влияют друг на друга?!
— Один белок отвечает за транспорт, сенсинг pH, буферизацию CO₂ и регуляцию сосудистого тонуса? Single Responsibility Principle — не, не слышал?
— А мутация одного символа может положить всю систему? У вас что, нет валидации входных данных?
И ведь они были бы формально правы. По всем метрикам «хорошей архитектуры» гемоглобин — монолит с god object, тесной связанностью и нулевой отказоустойчивостью на уровне отдельной молекулы.
Но на уровне популяции — это антихрупкость в чистом виде. Та самая мутация, которая ломает отдельные эритроциты, в тоже время спасает людей от малярии. Кооперативное связывание даёт S-кривую, без которой ваш мозг [6] бы не получал кислород каждый раз, когда вы поднимаетесь на третий этаж. Нарушение SRP позволяет одной молекуле заменить то, что в инженерной системе потребовало бы отдельных сенсоров, контроллеров и актуаторов.
500 миллионов лет, без рефакторинга, на одной кодовой базе, и с обратной совместимостью от рыб до людей.
Я не знаю, какой из этого следует вывод для нашей работы. Но мне кажется, что гемоглобин — это ещё одно доказательство, что идеальной архитектуры не существует. Зато рабочей — вполне.
Автор: inkedsymon
Источник [7]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/28035
URLs in this post:
[1] Эволюция: http://www.braintools.ru/article/7702
[2] кислорода: http://www.braintools.ru/article/5138
[3] Математически: http://www.braintools.ru/article/7620
[4] анемия: http://www.braintools.ru/article/3432
[5] боль: http://www.braintools.ru/article/9901
[6] мозг: http://www.braintools.ru/parts-of-the-brain
[7] Источник: https://habr.com/ru/articles/1016514/?utm_campaign=1016514&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.