• NFX — Ультраэффективная Бинарная Сериализация в CLR

      Требования


      В данной статье мы рассмотрим задачи переноса сложных объектов между процессами и машинами. В наших системах было много мест, где требовалось перемещать большое кол-во бизнес объектов различной структуры, например:

      • самозацикленные графы объектов (деревья с back-references)
      • массивы структур (value types)
      • классы/структуры с readonly полями
      • инстансы существующих .Net коллекций (Dictionary, List), которые внутренне используют custom-сериализацию
      • большое кол-во инстансов типов, специализированных для конкретной задачи


      Речь пойдёт о трёх аспектах, которые очень важны в распределённых кластерных системах:

      • скорость сериализации/десериализации
      • объём объектов в сериализированном виде
      • возможность использовать существующие объекты без надобности “украшения” этих объектов и их полей вспомогательными атрибутами для сериализации

      Читать дальше →
    • Храним 300 миллионов объектов в CLR процессе

        Камень преткновения — GC


        Все managed языки такие как Java или C# имеют один существенный недостаток — безусловное автоматическое управление паматью. Казалось бы, именно это и является преимуществом managed языков. Помните, как мы барахтались с dandling-указателями, не понимая, куда утекают драгоценные 10KB в час, заставляя рестартать наш любимый сервер раз в сутки? Конечно, Java и C# (и иже с ними) на первый взгляд разруливают ситуацию в 99% случаев.

        Так-то оно так, только вот есть одна проблемка: как быть с большим кол-вом объектов, ведь в том же .Net никакой магии нет. CLR должен сканировать огромный set объектов и их взаимных ссылок. Это проблема частично решается путём введения поколений. Исходя из того, что большинство объектов живёт недолго, мы высвобождаем их быстрее и поэтому не надо каждый раз ходить по всем объектам хипа.

        Но проблема всё равно есть в тех случаях, когда объекты должны жить долго. Например, кэш. В нём должны находиться миллионы объектов. Особенно, учитывая возрастание объемов оперативки на типичном современном серваке. Получается, что в кэше потенциально можно хранить сотни миллионов бизнес-объектов (например, Person с дюжиной полей) на машине с 64GB памяти.

        Однако на практике это сделать не удаётся. Как только мы добавляем первые 10 миллионов объектов и они “устаревают” из первого поколения во второе, то очередной полный GC-scan “завешивает” процесс на 8-12 секунд, причём эта пауза неизбежна, т.е. мы уже находимся в режиме background server GC и это только время “stop-the-world”. Это приводит к тому, что серверная апликуха просто “умирает” на 10 секунд. Более того, предсказать момент “клинической смерти” практически невозможно.
        Что же делать? Не хранить много объектов долго?

        Зачем


        Но мне НУЖНО хранить очень много объектов долго в конкретной задаче. Вот например, я храню network из 200 миллионов улиц и их взаимосвязей. После загрузки из flat файла моё приложение должно просчитать коэффициенты вероятностей. Это занимает время. Поэтому я это делаю сразу по мере загрузки данных с диска в память. После этого мне нужно иметь object-graph, который уже прекалькулирован и готов “к труду и обороне”. Короче, мне нужно хранить резидентно около 48GB данных в течении нескольких недель при этом отвечаю на сотни запросов в секунду.

        Вот другая задача. Кэширование социальных данных, которых скапливаются сотни миллионов за 2-3 недели, а обслуживать необходимо десятки тысяч read-запросов в секунду.
        Читать дальше →