Зачем это читать
У вас куча сотрудников с разными задачами и разным профилем работы, и каждому нужен компьютер.
Можно купить 500 ноутбуков и молиться, что никто не прольёт кофе на клавиатуру — вместе с важными данными. А можно задуматься о безопасности всего этого хозяйства и о том, где вообще должна жить информация.
В таком случае рабочие столы выносят в виртуальную среду — в свой или арендованный дата-центр — и передают пользователю только картинку, ввод и периферию.
Взрослые компании называют это VDI. Но сам по себе VDI не существует: без протокола доставки рабочего стола он просто не работает.
SPICE — один из таких протоколов. Open source, изначально заточен под Linux и без лицензионных отчислений. Если вы строите VDI на открытом стеке, рано или поздно вы с ним столкнётесь.
Дальше будет не обзор возможностей и не маркетинг. Мы вместе разберём, как SPICE устроен изнутри: какие архитектурные решения там приняты, зачем они такие и к каким практическим последствиям это приводит.
Немного истории (без занудства)
SPICE родился внутри Qumranet — израильского стартапа, который создал KVM. В 2008-м Red Hat купил Qumranet, а в декабре 2009-го открыл код SPICE.
Почему Red Hat вложился в собственный протокол, когда RDP и Citrix уже существовали? Однозначного ответа нет, но среди факторов наверняка были:
отсутствие открытого протокола для Linux VDI
желание контролировать весь стек (KVM + libvirt + SPICE)
независимость от лицензионной политики Microsoft и Citrix
Насколько каждый из этих факторов был решающим — сказать сложно. Но результат налицо: SPICE стал одним из основных протоколов доставки рабочего стола для oVirt, Proxmox, GNOME Boxes и остального open source VDI.
Архитектура: каналы и TCP
SPICE — клиент-серверный протокол. Серверная часть (libspice) живёт в QEMU, клиент (remote-viewer, spice-gtk) — на устройстве пользователя.
Первое архитектурное решение: только TCP
Это важно понять сразу, потому что отсюда растут многие ограничения.
SPICE работает исключительно поверх TCP. Никакого UDP. Точка. В spice-devel ещё в 2011 году обсуждали добавление UDP для аудио — воз и ныне там.
Что это означает на практике:
В LAN (потери <0.1%, латентность <5мс) — всё хорошо. TCP справляется, пользователи довольны.
В WAN с хорошим каналом (потери <0.5%, латентность <50мс) — терпимо. Есть нюансы, но жить можно.
В WAN с потерями (1%+ packet loss) — начинаются проблемы. TCP реагирует на потери ретрансмитами, латентность растёт, окно уменьшается. Там, где UDP-протокол просто потеряет кадр и пойдёт дальше, TCP будет героически доставлять каждый байт — и пользователь будет страдать.
Почему выбрали TCP? Простота. Не нужно возиться с NAT traversal, UDP hole punching, QoS для разных типов трафика. TCP просто работает через любой корпоративный файрвол. Для 2007-2009 года, когда проектировался протокол, это был разумный выбор. Сейчас, возможно, решили бы иначе.
Второе архитектурное решение: независимые каналы
Всё общение разбито на каналы — каждый со своим TCP-соединением:
Канал | Что делает | Почему важен для UX |
Display | Картинка | Пропускная способность |
Inputs | Клавиатура, мышь | Латентность — 100мс задержки и пользователь взбесится |
Cursor | Курсор отдельно | Курсор должен «прилипать» к движению мыши мгновенно |
Playback | Звук | Джиттер критичен |
USB | Проброс устройств | Зависит от устройства |
Отдельный канал для курсора — это не академическое решение, а практическая необходимость. Когда Display Channel загружен тяжёлым контентом, курсор всё равно должен двигаться плавно. Если бы курсор шёл в общем потоке с картинкой — каждый раз, когда на экране что-то сложное, мышь бы «залипала». Люди такое не прощают.
Разделение на каналы позволяет приоритизировать: input важнее, чем очередной кадр видео. Но — и это важно — приоритизация происходит на уровне приложения, а не протокола. SPICE не имеет встроенного QoS. Это ещё одно упрощение, за которое иногда приходится платить.

Image-based: осознанный выбор, а не ограничение
Здесь нужно кое-что объяснить, потому что эту тему часто понимают неправильно.
Протоколы удалённого рабочего стола делятся на два типа:
Command-based: передаём графические команды («нарисуй прямоугольник», «залей область»). Клиент рендерит сам. Так работает X11, так частично работает RDP.
Image-based: передаём готовые изображения изменившихся областей. Клиент просто показывает картинки.
SPICE — image-based протокол. И это не потому, что разработчики не осилили command-based. Это сознательный архитектурный выбор.
Почему image-based?
Универсальность. Image-based работает с чем угодно — браузер, CAD, игра, терминал. Протоколу без разницы, что рисует приложение. Всё превращается в пиксели.
Независимость от гостя. Command-based требует глубокой интеграции с графической подсистемой гостевой ОС. Image-based нужен только framebuffer — а его даёт любая система.
Предсказуемость. С command-based можно нарваться на приложение, которое генерирует «плохие» команды — и всё встанет колом. Image-based деградирует предсказуемо и пропорционально объёму изменений: больше изменений на экране — больше трафика. Никаких сюрпризов.
Цена решения
Трафик. Image-based в среднем требует больше bandwidth, чем хороший command-based. Для типичного офисного десктопа — порядка 1-5 Мбит/с (очень грубо, зависит от миллиона факторов). Для активной работы с видео — значительно больше.
В LAN это не проблема. В WAN с ограниченной полосой — фактор, который нужно учитывать.
QXL и реальность современных десктопов
Теперь — о том, что происходит на стороне гостевой ОС.
SPICE может работать с обычным VGA — тогда QEMU просто читает framebuffer и отправляет изменения. Но для приемлемой производительности нужен QXL — паравиртуальное графическое устройство.
Как задумывалось
Драйвер QXL в гостевой ОС перехватывает графические команды и транслирует их в QXL-команды. Эти команды попадают в command ring — область shared memory между гостем и хостом. libspice вытягивает их и решает: простые операции (заливка, копирование области) можно отправить клиенту как команды, сложные — растеризовать и отправить как изображения.
В теории это даёт лучшее из обоих миров: command-based для простых операций, image-based для сложных.
Как получилось
На практике 2D-команды QXL почти не используются. Почему?
Современные десктопы работают через композитные оконные менеджеры — Mutter, KWin, DWM. Им нужен OpenGL. В виртуалке без GPU passthrough аппаратного GPU нет, есть только QXL. Поэтому композитор работает через llvmpipe — программный растеризатор Mesa, который эмулирует OpenGL на CPU.
Результат: композитор рендерит всё в offscreen buffer и отдаёт QXL готовый framebuffer. 2D-команды не задействуются. QXL становится просто framebuffer'ом с дополнительными фичами.
Что это значит
Это не баг и не провал архитектуры. SPICE изначально проектировался как image-based протокол. 2D-команды QXL — оптимизация для специфических случаев (скроллинг, X11 без композитинга, классический Windows GDI), а не основной путь.
Когда SPICE создавался в 2007-2009, композитинг ещё не был повсеместным. Сейчас мир изменился, и основной режим работы — передача изображений. Но протокол к этому готов, потому что так и задумывался.
(Впрочем, можно отключить композитинг в гостевой ОС — и тогда 2D-команды заработают. Но кто будет это делать в 2025 году?)
Display Channel: как сжимаем картинку
Display Channel — сердце протокола. Здесь происходит самое интересное.
Pipeline
Детекция изменений — отслеживание dirty regions в framebuffer
Оптимизация — отбрасывание областей, которые уже перекрыты новыми
Классификация — эвристика решает, какой кодек применить
Сжатие — применяется выбранный кодек
Передача — данные уходят клиенту
Декодирование — клиент восстанавливает картинку
Всё это происходит много раз в секунду. Скорость критична.

Кодеки: инженерные компромиссы
SPICE использует несколько алгоритмов сжатия. Это не «у нас много кодеков, мы крутые» — это необходимость. Разный контент требует разных подходов.
QUIC
Собственная разработка Qumranet/Red Hat на базе алгоритма SFALIC (Starosolski, 2007). Использует предсказание соседних пикселей + кодирование Голомба-Райса.
Где хорош: фотографии, видеокадры, градиенты — всё с плавными переходами цветов. Степень сжатия порядка 3-5x для такого контента (оценка, не точное измерение).
Где плох: текст, UI с резкими границами. Предсказание не работает на резких переходах, кодек тратит биты впустую.
Название сбивает с толку — этот QUIC не имеет отношения к QUIC-протоколу от Google.
LZ / GLZ
LZ — классический словарный алгоритм. Ищет повторяющиеся последовательности, заменяет ссылками.
GLZ — расширение с глобальным словарём между кадрами. Идея простая: пользователь переключается между окнами, каждое окно уже отрисовывалось. GLZ находит совпадения в ранее переданных данных и отправляет короткие ссылки вместо полных изображений.
Где хорош: текст, UI, офисная работа с переключением между приложениями. По субъективным оценкам, GLZ экономит 20-50% трафика по сравнению с обычным LZ для типичной офисной нагрузки.
Ограничение: размер словаря конечен. При интенсивной работе старые данные вытесняются, и экономия падает.
LZ4
Появился позже в SPICE-стеке как альтернатива классическим LZ-алгоритмам, в том числе для сценариев со слабыми клиентами (ARM, thin clients).
Особенность: сжимает хуже (порядка 1.5-2x), но декодирует в разы быстрее. Компромисс: больше трафика, но клиент не греется.
Когда использовать: Raspberry Pi, Android-устройства, тонкие клиенты со слабым CPU. Если сеть быстрая, а процессор медленный — лучше передать больше данных, но не грузить CPU декомпрессией.
Как SPICE выбирает кодек
По умолчанию — режим auto_glz. Эвристика смотрит на цветовое распределение: много уникальных цветов → QUIC, мало цветов с повторами → GLZ.
Эвристика не идеальна. Код с подсветкой синтаксиса может быть принят за «фотографию» и сжат QUIC, что неоптимально. Но в большинстве случаев работает.
Можно форсировать кодек:
remote-viewer --spice-preferred-compression=auto_glz spice://host:5900
Оптимизации: кэш и скроллинг
Image Cache
Идея: передать картинку один раз — хорошо. Не передавать повторно — ещё лучше.
Сервер вычисляет хеш каждого изображения. Если картинка уже в кэше клиента — отправляется только ID. Клиент достаёт её из кэша.
Где работает: переключение окон, повторяющиеся иконки, возврат к ранее показанному контенту.
Где не работает: видео (каждый кадр уникален), интенсивная работа с переполнением кэша.
COPY_BITS
При скроллинге содержимое окна сдвигается. Наивный подход — передать весь видимый контент заново. Умный подход:
Сервер определяет, что это скролл
Отправляет команду «скопируй область из (x1,y1) в (x2,y2)»
Передаёт только новый контент в освободившейся полосе
Результат: вместо мегабайта — килобайты.
Ограничение: работает с QXL, композитные менеджеры могут ломать детекцию. При быстром скролле не успевает — переходит к полным перерисовкам.
Итоги: для кого этот протокол
Давайте честно.
SPICE хорош, когда:
Linux VDI в контролируемой сети (датацентр, корпоративный LAN)
Бюджет ограничен, лицензии — существенная статья расходов
Нужна предсказуемость open source без vendor lock-in
Нагрузка типовая: офис, разработка, терминалы
SPICE — компромисс, когда:
WAN с нестабильным каналом (TCP-only даёт о себе знать)
Много видео и мультимедиа (M-JPEG — это 90-е)
Нужны продвинутые фичи типа 3D-ускорения
SPICE не подходит, когда:
Пользователи через океан с 2% packet loss
Критичны GPU-ускоренные workloads
Нужна enterprise поддержка с SLA
Это не «плохой протокол». Это протокол с понятной нишей и честными ограничениями. В своей нише — Linux VDI в LAN — он работает хорошо и стоит ноль рублей. За пределами ниши — есть варианты лучше, но они стоят денег.
В следующих статьях разберём остальные каналы: почему курсор всё-таки отдельно, как работает agent mouse mode, что происходит с USB.
