Зачем это читать
У вас куча сотрудников с разными задачами и разным профилем работы, и каждому нужен компьютер.
Можно купить 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.
Комментарии (9)

kulaginds
31.12.2025 13:34Интересно, чем VNC их не устроил, как в qemu?

lapinsa42 Автор
31.12.2025 13:34Ну дело в том, что VNC — это remote framebuffer из 1998 года, созданный для совсем других задач.

kulaginds
31.12.2025 13:34Почему Red Hat вложился в собственный протокол, когда RDP и Citrix уже существовали? Однозначного ответа нет, но среди факторов наверняка были:
отсутствие открытого протокола для Linux VDI
желание контролировать весь стек (KVM + libvirt + SPICE)
независимость от лицензионной политики Microsoft и Citrix
Тут вроде все плюсы за VNC.
Результат: композитор рендерит всё в offscreen buffer и отдаёт QXL готовый framebuffer. 2D-команды не задействуются. QXL становится просто framebuffer'ом с дополнительными фичами.
Тут прям четко про то, что хорошо умеет VNC.
Претензий нет, просто размышления.

lapinsa42 Автор
31.12.2025 13:34VNC образца 2007 был значительно беднее (без аудио, USB, нормального clipboard). К слову, и сегодня open-source VNC так и не получил аудио — PR в TigerVNC висит с 2023 года, а clipboard в noVNC работает через костыли с тем же spice-vdagent.
Но вы правы насчёт framebuffer'а — разница в том, как он передаётся: SPICE использует адаптивное сжатие и эвристики для детекта видеопотоков, VNC — фиксированные encoding'и (Tight, ZRLE) на весь кадр.
В целом, вы попали в точку: именно поэтому Red Hat сегодня рекомендует VNC для серверов. Когда разница нивелирована — зачем тянуть отдельный протокол? Но это не для VDI а для админов.
Mingun
Что, неужели абстракции в протоколе настолько протекают, что TCP не заменяется более-менее прозрачно на что-то другое?
lapinsa42 Автор
Хороший вопрос, без шуток. В SPICE TCP — это не просто «подложка», а часть мышления протокола. Там много решений, которые молча опираются на поведение TCP: порядок, блокировки, backpressure, отдельные соединения на каналы. Поэтому «прозрачно заменить транспорт» не получается — это уже будет другой протокол, с другими допущениями и болью.
Связь SPICE и TCP на самом деле глубже, чем влезает в комментарий. Я, пожалуй, отдельно про это напишу: почему так вышло исторически и к чему это привело сейчас.
Mingun
Да, это было бы интересно. Особенно, что так мешает для разных каналов использовать разный транспорт, чтобы там, где свойства TCP больше мешают, чем помогают, использовать UDP