Trong dự án hiện tại của tôi, tôi làm việc với protobuf không chỉ cho GRPC mà còn ở định dạng thông báo RabbitMQ . Mặc dù lợi thế của protobuf không giới hạn ở tốc độ của nó, nhưng tôi tự hỏi liệu nó có thực sự quá nhanh so với các thư viện JSON hay không, đặc biệt là trong thế giới ruby. Tôi quyết định thực hiện một số điểm chuẩn để kiểm tra, nhưng trước tiên tôi muốn thêm phần giới thiệu ngắn gọn về từng định dạng.
Đó là một hệ thống tin nhắn đa nền tảng nhanh, nhỏ gọn, được thiết kế có tính đến khả năng tương thích tiến và lùi. Nó bao gồm một ngôn ngữ định nghĩa và trình biên dịch ngôn ngữ cụ thể.
Nó hoạt động hoàn hảo đối với dữ liệu giống như đối tượng nhỏ, có khả năng tương thích ngược và xuôi tuyệt vời, nhanh (chúng tôi chưa chắc chắn) và nhỏ gọn hơn JSON chẳng hạn, nhưng có một số hạn chế như không hỗ trợ so sánh trực tiếp (bạn cần giải tuần tự hóa các đối tượng để so sánh).
Nó không được nén và một số định dạng cụ thể có thể hoạt động tốt hơn cho dữ liệu của chúng (ví dụ: JPEG). Nó không tự mô tả.
Xem Tài liệu chính thức để biết thêm chi tiết.
JSON là viết tắt của ký hiệu đối tượng JavaScript . Định dạng dữ liệu dựa trên văn bản, ban đầu được sử dụng trong JavaScript, nhưng sau đó đã được phổ biến rộng rãi dưới dạng định dạng giao tiếp không chỉ giữa các ứng dụng JS và chương trình phụ trợ mà thậm chí giữa các vi dịch vụ và có nhiều cách sử dụng khác.
Nó sử dụng các chuỗi làm khóa và có một chuỗi, số, boolean, đối tượng, mảng và nul làm các loại giá trị có sẵn. Ưu điểm chính của nó là con người có thể đọc được và khá dễ dàng để tuần tự hóa và phân tích cú pháp cho ngôn ngữ lập trình.
Xem trang web để biết thêm chi tiết.
Tôi đã chọn ba thư viện JSON ruby phổ biến. Chúng là thư viện Oj, Yajl và tiêu chuẩn JSON. Đối với protobuf, tôi sử dụng google protoc tiêu chuẩn với google ruby gem.
Tôi sẽ đo các loại tải trọng cụ thể khác nhau để xem loại dữ liệu nào chúng tôi sẽ hiển thị khác biệt nhất, miễn là tải trọng phức tạp với sự kết hợp của nhiều loại trường.
Bạn có thể xem tất cả mã ở đây https://github.com/alexstaro/proto-vs-json .
Về phần cứng, tôi sử dụng máy tính xách tay với AMD Ryzen 3 PRO 5450U và 16gb ram ddr4.
Là một hệ điều hành, tôi sử dụng động học Ubuntu 22.10.
Phiên bản Ruby 3.2.1 đã được cài đặt qua asdf.
Để đo điểm chuẩn, tôi sử dụng điểm chuẩn/ips gem ( https://github.com/evanphx/benchmark-ips )
Thiết lập trông như thế này:
Benchmark.ips do |x| x.config(time: 20, warmup: 5) x.report('Yajl encoding') do Yajl::Encoder.encode(data) end ... x.compare! end
Chúng tôi sẽ bắt đầu chỉ với số nguyên. Các con số khá khó đối với JSON, vì vậy chúng tôi hy vọng protobuf sẽ bỏ xa các đối thủ khác.
Các dữ liệu thử nghiệm:
data = { field1: 2312345434234, field2: 31415926, field3: 43161592, field4: 23141596, field5: 61415923, field6: 323423434343443, field7: 53141926, field8: 13145926, field9: 323423434343443, field10: 43161592 }
Kết quả điểm chuẩn:
protobuf encoding: 4146929.7 i/s Oj encoding: 1885092.0 i/s - 2.20x slower standard JSON encoding: 505697.5 i/s - 8.20x slower Yajl encoding: 496121.7 i/s - 8.36x slower
Không còn nghi ngờ gì nữa, protobuf là người chiến thắng tuyệt đối, nhưng điều gì sẽ xảy ra nếu chúng tôi thực hiện thử nghiệm gần hơn với kịch bản trong thế giới thực - hầu như chúng tôi luôn tạo các thông báo proto chỉ để đăng nhiều kỳ.
Đây là kết quả:
protobuf encoding: 4146929.7 i/s Oj encoding: 1885092.0 i/s - 2.20x slower standard JSON encoding: 505697.5 i/s - 8.20x slower Yajl encoding: 496121.7 i/s - 8.36x slower protobuf with model init: 489658.0 i/s - 8.47x slower
Kết quả không quá rõ ràng. Tôi dự kiến mã hóa với khởi tạo tin nhắn sẽ chậm hơn nhưng không phải là chậm nhất.
Hãy kiểm tra quá trình khử lưu huỳnh:
protobuf parsing: 737979.5 i/s Oj parsing: 448833.9 i/s - 1.64x slower standard JSON parsing: 297127.2 i/s - 2.48x slower Yajl parsing: 184361.1 i/s - 4.00x slower
Không có bất ngờ ở đây.
Về kích thước tải trọng, protobuf nhỏ gọn hơn gần 4 lần so với json:
JSON payload bytesize 201 Protobuf payload bytesize 58
Nhân đôi được cho là tải trọng khó khăn nhất đối với JSON, hãy kiểm tra điều này.
Tải trọng của chúng tôi:
data = { field1: 2312.345434234, field2: 31415.926, field3: 4316.1592, field4: 23141.596, field5: 614159.23, field6: 3234234.34343443, field7: 53141.926, field8: 13145.926, field9: 323423.434343443, field10: 43161.592 }
Kết quả:
protobuf encoding: 4814662.9 i/s protobuf with model init: 444424.1 i/s - 10.83x slower Oj encoding: 297152.0 i/s - 16.20x slower Yajl encoding: 160251.9 i/s - 30.04x slower standard JSON encoding: 158724.3 i/s - 30.33x slower
Protobuf nhanh hơn nhiều ngay cả khi khởi tạo mô hình. Hãy kiểm tra quá trình khử lưu huỳnh:
Comparison: protobuf parsing: 822226.6 i/s Oj parsing: 395411.3 i/s - 2.08x slower standard JSON parsing: 241438.7 i/s - 3.41x slower Yajl parsing: 157235.7 i/s - 5.23x slower
Vẫn không có bất ngờ ở đây.
và kích thước tải trọng:
JSON payload bytesize 211 Protobuf payload bytesize 90
Không phải bốn lần, nhưng vẫn đáng chú ý.
Các chuỗi dự kiến sẽ dễ dàng hơn đối với JSON, hãy kiểm tra điều này.
khối hàng:
data = { field1: "2312.345434234", field2: "31415.926", field3: "4316.1592", field4: "23141.596", field5: "614159.23", field6: "3234234.34343443", field7: "53141.926", field8: "13145.926", field9: "323423.434343443", field10: "43161.592" }
Kết quả băng ghế dự bị:
Comparison: protobuf encoding: 3990298.3 i/s oj encoder: 1848941.3 i/s - 2.16x slower yajl encoder: 455222.0 i/s - 8.77x slower standard JSON encoding: 444245.6 i/s - 8.98x slower protobuf with model init: 368818.3 i/s - 10.82x slower
khử lưu huỳnh:
Comparison: protobuf parser: 631262.5 i/s oj parser: 378697.6 i/s - 1.67x slower standard JSON parser: 322923.5 i/s - 1.95x slower yajl parser: 187593.4 i/s - 3.37x slower
Kích thước tải trọng:
JSON payload bytesize 231 Protobuf payload bytesize 129
Mặc dù chúng tôi đã phân tách băng ghế số nguyên, thật thú vị khi protobuf xử lý các bộ sưu tập.
Đây là dữ liệu:
data = { field1: [ 2312345434234, 31415926, 43161592, 23141596, 61415923, 323423434343443, 53141926, 13145926, 323423434343443, 43161592 ] }
Băng ghế sê-ri hóa:
Comparison: protobuf encoding: 4639726.6 i/s oj encoder: 2929662.1 i/s - 1.58x slower standard JSON encoding: 699299.2 i/s - 6.63x slower yajl encoder: 610215.5 i/s - 7.60x slower protobuf with model init: 463057.9 i/s - 10.02x slower
Bàn khử lưu huỳnh:
Comparison: oj parser: 1190763.1 i/s protobuf parser: 760307.3 i/s - 1.57x slower standard JSON parser: 619360.4 i/s - 1.92x slower yajl parser: 414352.4 i/s - 2.87x slower
Thành thật mà nói, kết quả khử lưu huỳnh ở đây khá bất ngờ.
Hãy kiểm tra kích thước tải trọng:
JSON payload bytesize 121 Protobuf payload bytesize 50
Tôi quyết định kiểm tra xem một mảng nhân đôi có cùng hành vi không.
dữ liệu:
data = { field1: [ 2312.345434234, 31415.926, 4316.1592, 23141.596, 614159.23, 3234234.34343443, 53141.926, 13145.926, 323423.434343443, 43161.592 ] }
Tuần tự hóa:
Comparison: protobuf encoding: 7667558.9 i/s protobuf with model init: 572563.4 i/s - 13.39x slower Oj encoding: 323818.1 i/s - 23.68x slower Yajl encoding: 183763.3 i/s - 41.73x slower standard JSON encoding: 182332.3 i/s - 42.05x slower
khử lưu huỳnh:
Comparison: Oj parsing: 953384.6 i/s protobuf parsing: 883899.0 i/s - 1.08x slower standard JSON parsing: 452799.0 i/s - 2.11x slower Yajl parsing: 356091.2 i/s - 2.68x slower
Chúng tôi đã nhận được kết quả tương tự ở đây. Có vẻ như protobuf có một số vấn đề với mảng.
Kích thước tải trọng:
JSON payload bytesize 131 Protobuf payload bytesize 82
Là một trọng tải "phức tạp", tôi đã chế nhạo một số dữ liệu người dùng bằng các bài đăng và nhận xét cho những bài đăng đó để làm cho nó giống với ứng dụng ngoài đời thực hơn.
data = { user_id: 12345, username: 'johndoe', email: '[email protected]', date_joined: '2023-04-01T12:30:00Z', is_active: true, profile: { full_name: 'John Doe', age: 30, address: '123 Main St, Anytown, USA', phone_number: '+1-555-123-4567' }, posts: [ { post_id: 1, title: 'My first blog post', content: 'This is the content of my first blog post.', date_created: '2023-04-01T14:00:00Z', likes: 10, tags: ['blog', 'first_post', 'welcome'], comments: [ { comment_id: 101, author: 'Jane', content: 'Great first post!', date_created: '2023-04-01T15:00:00Z', likes: 3 }, ... ] }, ... ] }
Kết quả:
Comparison: protobuf encoding: 1038246.0 i/s Oj encoding: 296018.6 i/s - 3.51x slower Yajl encoding: 125909.6 i/s - 8.25x slower protobuf with model init: 119673.2 i/s - 8.68x slower standard JSON encoding: 115773.4 i/s - 8.97x slower Comparison: protobuf parsing: 291605.9 i/s Oj parsing: 76994.7 i/s - 3.79x slower standard JSON parsing: 64823.6 i/s - 4.50x slower Yajl parsing: 34936.4 i/s - 8.35x slower
Và kích thước tải trọng:
JSON payload bytesize 1700 Protobuf payload bytesize 876
Ở đây, chúng tôi thấy hành vi được mong đợi với mã hóa protobuf thuần túy ngay từ đầu, tuy nhiên, nếu chúng tôi xem xét ví dụ “thế giới thực” của mình, chúng tôi sẽ thấy mã hóa JSON tiêu chuẩn không nhanh hơn.
Nếu bạn đang chuyển từ JSON sang Protobuf chỉ vì tốc độ, thì điều đó có thể không đáng.
Lý do để sử dụng Protobuf phải là định nghĩa lược đồ đa ngôn ngữ tuyệt vời để trao đổi dữ liệu — không phải là tăng hiệu suất.
Hình ảnh chính cho bài viết này được tạo bởiTrình tạo hình ảnh AI của HackerNoon thông qua dấu nhắc "ngôn ngữ lập trình".