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 може да е добър избор.