Low-latency оптимизации на всех уровнях торговой системы

В предыдущей статье я говорил об оптимизации вообще, а теперь приведу несколько советов по low-latency оптимизациях в Java-приложениях на всех уровнях торговой системы:

  • аппаратный уровень: процессор, сетевой интерфейс, коммутация
  • операционная система
  • настройка JVM
  • оптимизации на уровне приложения

На аппаратном уровне

BIOS: Отключить в BIOS энергосберегающий режим. Все ядра процессора должны работать в идеале в Turbo режиме. Изнашивается от такой работы процессор быстрее, но ради прибыли ничего не жалко.

Процессор: чем новее, тем лучше. Чем производительнее, тем лучше. Выбирайте вариант процессора выдающий более высокую частоту и допускающий разгон процессора и каналов памяти до еще более высоких частот. Есть конечно риск перестараться и спалить процессор, но кто не рискует — тот не пьет шампанского. Совеременные процессоры допускают разгон и работают вполне стабильно, если не выжимать из них последнее.

Чаще всего выбирают процессоры Intel семейства Xeon, так как они стандартно ставятся в серверные решения от ведущих поставщиков производительных решений: большое количество ядер, поддержка памяти с коррекцией ошибок, поддержка сопряжения большого количества процессоров, высокие тактовые частоты, минимум лишнего, что на сервере и не нужно. Недавно AMD-процессоры тоже стали предлагать — получается дешевле, но как-то Intel пока еще держит планку.

Начинайте свой выбор минимум с Sandy Bridge и выше. Существует поверие, что каждое новое поколение процессоров Intel прибавляет 15%-17% производительности. Мои измерения с помощью JMH одного и того же кода на разных машинах вроде бы подтверждают это утверждение. Здесь трудно что-то советовать, так как все зависит от бюджета вашего проекта.  Уверяю вас даже из Sandy Bridge 7-летней давности можно выжать рекордные latency, если хорошо постараться. Помните 3 ГГц — это (очень приблизительно) 3 миллиарда инструкций в секунду! На каждом ядре многоядерного процессора! Это очень много, даже в 2019 году. Какие такие сложные вычисления в вашем приложении могут потребовать 3 миллиардов инструкций, чтобы оно выполняло его 1 секунду?

Какую бы архитектуру процессора вы не выбрали, очень советую основательно разузнать по документации все её характеристики, размеры кэша всех уровней, особенности реализации. Это пригодится при написании кода по принципу mechanical sympathy: часто оказывается что код, который работает быстро на, скажем, стареньком Sandy Bridge, начинает тормозить на более свежем Haswell.

Сетевой интерфейс: В современных серверах PIC-слоты, куда ставятся сетевые карты, распределены так, что часть из них находятся «ближе» к CPU0, а другие — к CPU1. Сетевая карта должна располагаться в слоте, который ближе к процессору, на котором будет крутиться приложение.

PCI-слоты могут поддерживать разное количество lane. При установке сетевой карты надо убедиться не только в том, что вы ставите карту в слот, который ближе к нужному вам процессору, но и в слот, количество lane, которого совпадает с lane вашей сетевой карты.

Выбирайте самую быструю сетевую карту. Самым популярным выбором являются сетевые карты Solarflare, которые специально заточены под low-latency. Кроме того, они снабжаются высокоэффективными драйверами, позволяющими ускорять передачу данных между сетью и приложением.

Некоторые Solarflare имеют также FPGA модули, которые позволяют на аппаратном уровне фильтровать пакеты. Но это уже высший пилотаж программирования на уровне VHDL. Главный конкурент Solarflare — компания Mellanox, которая, увы, пока не дотягивает.

На уровне операционной системы

Выбор ОС: Наиболее популярной операционной системой является Linux. Из всех дистрибутивов Linux наиболее популярным являются Red Hat Enterprise Linux (RHEL) и его открытый вариант CentOS. Версия CentOS тоже играет роль, но нет пока никаких доказательств, что свежая версия всегда лучше предыдущей. Скорее бывает даже наоборот, новая версия дистрибутива приносит с собой какие-то новые настройки, которые могут снижать производительность системы, и если вы не догадываетесь о существовании этих настроек, после обновления ОС ваша торговая система будет работать медленнее.

Выбор версии: Версия ядра Linux — пожалуй, первое, на что нужно обращать внимание. В некоторых версиях Linux присутствуют критические ошибки, снижающие производительность системы.

Используйте самые свежие драйвера для сетевой карты.

Выбор драйверов: Если используется Solareflare сетевая карта, воспользуйтесь драйверами и функцией Open Onload, которая позволяет обходить TCP/IP стек операционной системы и ее системные вызовы при передаче данных, и позволяет сетевой карте писать данные прямо в user-space вашего приложения, а вашему приложению — напрямую общаться с стевой картой, минуя ядро операционной системы. Этот механизм называется TCP-offload или kernel bypass. Очень эффективно снижает зажержки на копирование данных из буфера в буфер между user-space и kernel-space, переключение контекста и системные вызовы.

Отключите у операционной системы все некритические и ненужные сервисы.

Отключите у операционной системы заплатки от Spectre и Meltdown. Заплатки предназначены для защиты систем, где работают несколько пользователей. Вы своей торговой системой владеете безраздельно. Защищите ее от доступа извне другими способами, а в самой системе снимите все барьеры. Заплатки от Spectre и Meltdown легко могут сьесть 20-30% производительности вашего приложения так как препятствуют процессору использовать многие техники, ускорявшие исполнение кода.

Изоляция процессов: Современные сервера имеют несколько многоядерных процессоров — чаще два. Идеально — запускать приложение только на одном процессоре, отдавая второй CPU под задачи и сервисы операционной системы. Изоляция процесса осуществляется с помощью утилит cgroups и taskset.

Оптимальный доступ к памяти: Двухпроцессорная архитектура наверняка будет организована как NUMA: вся память поделена на два банка, и у каждого процессора есть свой банк памяти, который ближе к нему. Очень важно запретить приложению аллоцировать память, которая расположена ближе ко второму процессору. Доступ к такой памяти будет медленнее и требует доступа к шине между процессорами. Делается это несколькими способами:

  • с помощью cgroups
  • с помощью утилиты numactl
  • с помощью параметра JVM -XX:UseNUMA, сообщающего JVM, что процесс работает на NUMA-машине

На уровне JVM

Настройки JVM с помощью стартовых опций я описываю в отдельной статье.

  • настройки heap
  • настройки сборщика мусора
  • настройки JIT-компилятора
  • прочие настройки

На уровне самого Java-приложения

Текст этого раздела оказался настолько большим, что был вынесен в отдельную статью Принципы написания торговых low-latency приложений на Java. В ней затрагиваются темы:

  • оптимизация работы сборщика мусора
  • логгирование
  • многопоточность
  • lock-free алгоритмы и структуры данных и проч.

 

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s