TL;DR — кодирането и декодирането на данни с интензивно използване на низове в JavaScript е по-бързо с JSON, отколкото с protobuf.

Когато имате структурирани данни в JavaScript, които трябва да бъдат изпратени по мрежата (за друга микроуслуга например) или запазени в система за съхранение, те първо трябва да бъдат сериализирани. Процесът на сериализация преобразува обекта с данни, който имате в програмната памет на JavaScript, в буфер от байтове, който след това може да бъде десериализиран обратно в JavaScript обект.

Два популярни метода за сериализация са JSON и Google Protocol Buffers (protobuf)

JSON

Сериализиране на данни в JSON е толкова лесно, колкото:

protobuf.js

Google Protocol Buffers е метод за сериализиране на структурни данни, който се основава на схема (написана в .proto файл). Пример за това как да сериализирате предишния полезен товар в Protobuf с пакета protobufjs:

Можете да видите, че генерираният изход е дълъг само 7 байта, много по-малко от 23-те байта, които получихме при JSON сериализация. Protobuf е в състояние да сериализира данни толкова компактно, главно защото не е необходимо да вгражда имената на полетата като текст в данните, вероятно много пъти („име“ и „възраст“ в примера са заменени с кратки дескриптори от 2 байта).

Избор на правилния формат

Изборът на правилния формат за сериализация, който работи най-добре за вас, е задача, която включва множество фактори.

JSON обикновено е по-лесен за отстраняване на грешки (сериализираният формат е четим от хора) и по-лесен за работа (няма нужда да дефинирате типове съобщения, да ги компилирате, да инсталирате допълнителни библиотеки и т.н.).

Protobuf от друга страна обикновено компресира данните по-добре и има вградена документация на протокола чрез схемата.

Друг важен фактор е производителността на процесора - времето, необходимо на библиотеката да сериализира и десериализира съобщение. В тази статия искаме да сравним само производителността в JavaScript. В крайна сметка може да изберете формат, който е по-малко ефективен, но осигурява стойност в други фактори, или производителността може да е голям проблем за вас, в който случай - продължете да четете.

Encode Performance

В Aspecto написахме SDK, който събира събития за проследяване и ги експортира в колектор с отворена телеметрия. Данните се форматират като JSON и се изпращат по http. Износителят и колекторът могат също да комуникират в protobuf, използвайки библиотеката protobufjs.

Тъй като форматът protobuf е толкова компресиран, може да се изкушим да мислим, че кодирането в protobuf изисква по-малко CPU, което се измерва като брой операции (кодиране/декодиране) в секунда. Бързо търсене в Google по темата затвърждава тази теза и Секцията за производителност в документацията на protobufjs ни накара да заменим нашия SDK експортер от JSON към protobuf полезен товар, вярвайки, че ще получим по-добра производителност.

Действителна производителност

След като сменихме от сериализация на JSON към сериализация на protobuf, изпълнихме нашия тест за SDK и изненадващо установихме, че производителността намаля. Това наблюдение, за което първоначално вярвахме, че е грешка, ни изпрати да проучим допълнително проблема.

Бенчмаркинг — базова линия

На първо място, ние изпълняваме оригиналния бенчмарк на библиотеката protobufjs, за да получим солидна основа, от която да започнем. Наистина получихме резултати, подобни на библиотеката README:

Тези резултати показват, че производителността на protobuf.js е по-добра от JSON, което беше в контраст с предишното ни наблюдение.

Бенчмарк — телеметрични данни

След това променихме бенчмарка, за да кодираме нашите примерни данни, които са „данни за проследяване на отворена телеметрия“. Копирахме прото файловете и данните в бенчмарка и получихме следните резултати:

Това бяха резултатите, които очаквахме - за тези данни protobuf всъщност е по-бавен от JSON.

Бенчмарк — низове

Получихме два резултата за две различни схеми на данни. В един - protobufjs е по-бърз, а във втория - JSON е по-бърз. Разглеждайки схемите, непосредственият заподозрян беше броят на низовете. Нашите схеми са съставени почти изцяло от низове. Затова създадохме трети тест, попълвайки проста схема с много много много низове:

Изпълняваме бенчмарка с този полезен товар (10 000 низа, с дължина 10 всеки)

И резултатите доказаха нашето подозрение:

Когато вашите данни са съставени от много низове, производителността на protobuf в JavaScript пада под тази на JSON. Може да е свързано с функцията JSON.stringify, която е внедрена в C++ в двигателя V8 и е силно оптимизирана в сравнение с JS реализацията на protobufjs.

Декодиране

Сравнителните показатели по-горе са за кодиране (сериализиране). Резултатите от бенчмарковете за декодиране (десериализиране) са подобни.

Заключение

Ако имате време, нашата препоръка е да профилирате вашите общи данни, да разберете очакваната производителност на всяка опция и да изберете формата, който работи най-добре за вашите нужди.

Важно е да сте наясно, че protobuf не е непременно най-бързият вариант. Ако вашите данни са предимно низови, тогава форматът JSON може да е добър избор.