JSON非常慢:这里有更快的替代方案!

2023年 11月 21日 75.4k 0

是的,你没听错!JSON,这种在网络开发中普遍用于数据交换的格式,可能正在拖慢我们的应用程序。在速度和响应性至关重要的世界里,检查 JSON 的性能影响至关重要。在这篇博客中,深入探讨 JSON 可能成为应用程序瓶颈的原因,并探索更快的替代方法和优化技术,使您的应用程序保持最佳运行状态。

JSON 是什么,为什么要关心?

图片图片

JSON 是 JavaScript Object Notation 的缩写,一种轻量级数据交换格式,已成为应用程序中传输和存储数据的首选。它的简单性和可读格式使开发者和机器都能轻松使用。但是,为什么要在项目中关注 JSON 呢?

JSON 是应用程序中数据的粘合剂。它是服务器和客户端之间进行数据通信的语言,也是数据库和配置文件中存储数据的格式。从本质上讲,JSON 在现代网络开发中起着举足轻重的作用。

JSON 的流行以及人们使用它的原因...

主要有就下几点:

  • 人类可读格式:JSON 采用简单明了、基于文本的结构,便于开发人员和非开发人员阅读和理解。这种人类可读格式增强了协作,简化了调试。
  • 语言无关:JSON 与任何特定编程语言无关。它是一种通用的数据格式,几乎所有现代编程语言都能对其进行解析和生成,因此具有很强的通用性。
  • 数据结构一致性:JSON 使用键值对、数组和嵌套对象来实现数据结构的一致性。这种一致性使其具有可预测性,便于在各种编程场景中使用。
  • 浏览器支持:浏览器原生支持 JSON,允许应用程序与服务器进行无缝通信。这种本地支持极大地促进了 JSON 在开发中的应用。
  • JSON API:许多服务和应用程序接口默认以 JSON 格式提供数据。这进一步巩固了 JSON 在网络开发中作为数据交换首选的地位。
  • JSON 模式:开发人员可以使用 JSON 模式定义和验证 JSON 数据的结构,从而为其应用程序增加一层额外的清晰度和可靠性。
  • 鉴于这些优势,难怪全球的开发人员都依赖 JSON 来满足他们的数据交换需求。不过,随着我们深入探讨,会发现与 JSON 相关的潜在性能问题以及如何有效解决这些挑战。

    对速度的需求

    应用速度和响应速度的重要性

    在当今快节奏的数字环境中,应用程序的速度和响应能力是不容忽视的。用户希望在网络和移动应用中即时获取信息、快速交互和无缝体验。对速度的这种要求是由多种因素驱动的:

  • 用户期望:用户已习惯于从数字互动中获得闪电般快速的响应。他们不想等待网页加载或应用程序响应。哪怕是几秒钟的延迟,都会导致用户产生挫败感并放弃使用。
  • 竞争优势:速度可以成为重要的竞争优势。与反应慢的应用程序相比,反应迅速的应用程序往往能更有效地吸引和留住用户。
  • 搜索引擎排名:谷歌等搜索引擎将页面速度视为排名因素。加载速度更快的网站往往在搜索结果中排名靠前,从而提高知名度和流量。
  • 转换率:电子商务网站尤其清楚速度对转换率的影响。网站速度越快,转换率越高,收入也就越高。
  • 移动性能:随着移动设备的普及,对速度的需求变得更加重要。移动用户的带宽和处理能力往往有限,因此,快速的应用程序性能必不可少。
  • JSON 会拖慢我们的应用程序吗?

    在某些情况下,JSON 可能是导致应用程序运行速度减慢的罪魁祸首。解析 JSON 数据的过程,尤其是在处理大型或复杂结构时,可能会耗费宝贵的毫秒时间。此外,低效的序列化和反序列化也会影响应用程序的整体性能。

    JSON 为什么会变慢

    1.解析开销

    JSON 数据到达应用程序后,必须经过解析过程才能转换成可用的数据结构。解析过程可能相对较慢,尤其是在处理大量或深度嵌套的 JSON 数据时。

    2.序列化和反序列化

    JSON 要求在从客户端向服务器发送数据时进行序列化(将对象编码为字符串),并在接收数据时进行反序列化(将字符串转换回可用对象)。这些步骤会带来开销并影响应用程序的整体速度。

    在微服务架构的世界里,JSON 通常用于在服务之间传递消息。但是,JSON 消息需要序列化和反序列化,这两个过程会带来巨大的开销。

    在众多微服务不断通信的情况下,这种开销可能会累积起来,有可能会使应用程序减慢到影响用户体验的程度。

    图片图片

    3.字符串操作

    JSON 以文本为基础,主要依靠字符串操作来进行连接和解析等操作。与处理二进制数据相比,字符串处理速度较慢。

    4.缺乏数据类型

    JSON 的数据类型(如字符串、数字、布尔值)有限。复杂的数据结构可能需要效率较低的表示方法,从而导致内存使用量增加和处理速度减慢。

    图片图片

    5.冗长性

    JSON 的人机可读设计可能导致冗长。冗余键和重复结构会增加有效载荷的大小,导致数据传输时间延长。

    6.不支持二进制

    JSON 缺乏对二进制数据的本地支持。在处理二进制数据时,开发人员通常需要将其编码和解码为文本,这可能会降低效率。

    7.深嵌套

    在某些情况下,JSON 数据可能嵌套很深,需要进行递归解析和遍历。这种计算复杂性会降低应用程序的运行速度,尤其是在没有优化的情况下。

    JSON 的替代品

    虽然 JSON 是一种通用的数据交换格式,但由于其在某些情况下的性能限制,开发者开始探索更快的替代格式。我们来看呓2其中的一些替代方案。

    1.协议缓冲区(protobuf)

    协议缓冲区(通常称为 protobuf)是谷歌开发的一种二进制序列化格式。其设计宗旨是高效、紧凑和快速。Protobuf 的二进制特性使其在序列化和反序列化时比 JSON 快得多。

    何时使用:当你需要高性能数据交换时,尤其是在微服务架构、物联网应用或网络带宽有限的情况下,请考虑使用 protobuf。

    2. MessagePack 信息包

    MessagePack 是另一种二进制序列化格式,以速度快、结构紧凑而著称。其设计目的是在保持与各种编程语言兼容的同时,提高比 JSON 更高的效率。

    何时使用:当你需要在速度和跨语言兼容性之间取得平衡时,MessagePack 是一个不错的选择。它适用于实时应用程序和对减少数据量有重要要求的情况。

    3. BSON(二进制 JSON)

    BSON 或二进制 JSON 是一种从 JSON 衍生出来的二进制编码格式。它保留了 JSON 的灵活性,同时通过二进制编码提高了性能。BSON 常用于 MongoDB 等数据库。

    何时使用:如果你正在使用 MongoDB,或者需要一种能在 JSON 和二进制效率之间架起桥梁的格式,那么 BSON 就是一个很有价值的选择。

    4. Apache Avro(阿帕奇 Avro)

    Apache Avro 是一个数据序列化框架,专注于提供一种紧凑的二进制格式。它基于模式,可实现高效的数据编码和解码。

    何时使用:Avro 适用于模式演进非常重要的情况,如数据存储,以及需要在速度和数据结构灵活性之间取得平衡的情况。

    与 JSON 相比,这些替代方案在性能上有不同程度的提升,具体选择取决于您的具体使用情况。通过考虑这些替代方案,您可以优化应用程序的数据交换流程,确保将速度和效率放在开发工作的首位。

    每个字节的重要性:优化数据格式

    JSON 数据

    下面是我们的 JSON 数据示例片段:

    {
      "id": 1,                                 // 14 bytes
      "name": "John Doe",                      // 20 bytes
      "email": "johndoe@example.com",          // 31 bytes
      "age": 30,                               // 9 bytes
      "isSubscribed": true,                    // 13 bytes
      "orders": [                              // 11 bytes
        {                                      // 2 bytes
          "orderId": "A123",                   // 18 bytes
          "totalAmount": 100.50                // 20 bytes
        },                                     // 1 byte
        {                                      // 2 bytes
          "orderId": "B456",                   // 18 bytes
          "totalAmount": 75.25                 // 19 bytes
        }                                      // 1 byte
      ]                                        // 1 byte
    }

    JSON 总大小: ~139 字节

    JSON 功能多样,易于使用,但也有缺点,那就是它的文本性质。每个字符、每个空格和每个引号都很重要。在数据大小和传输速度至关重要的情况下,这些看似微不足道的字符可能会产生重大影响。

    效率挑战:使用二进制格式减少数据大小

    现在,我们提供其他格式的数据表示并比较它们的大小:

    **协议缓冲区 (protobuf)**:

    syntax = "proto3";
    
    message User {
      int32 id = 1;
      string name = 2;
      string email = 3;
      int32 age = 4;
      bool is_subscribed = 5;
      repeated Order orders = 6;
    
      message Order {
        string order_id = 1;
        float total_amount = 2;
      }
    }
    0A 0E 4A 6F 68 6E 20 44 6F 65 0C 4A 6F 68 6E 20 44 6F 65 65 78 61 6D 70 6C 65 2E 63 6F 6D 04 21 00 00 00 05 01 12 41 31 32 33 03 42 DC CC CC 3F 05 30 31 31 32 34 34 35 36 25 02 9A 99 99 3F 0D 31 02 42 34 35 36 25 02 9A 99 99 3F

    协议缓冲区总大小: ~38 字节

    MessagePack

    二进制表示法(十六进制):

    a36a6964000000000a4a6f686e20446f650c6a6f686e646f65406578616d706c652e636f6d042100000005011241313302bdcccc3f0530112434353625029a99993f

    信息包总大小: ~34 字节

    Binary Representation (Hexadecimal):

    3e0000001069640031000a4a6f686e20446f6502656d61696c006a6f686e646f65406578616d706c652e636f6d1000000022616765001f04370e4940

    BSON 总大小: ~43 字节

    Avro

    二进制表示法(十六进制):

    0e120a4a6f686e20446f650c6a6f686e646f65406578616d706c652e636f6d049a999940040a020b4108312e3525312e323538323539

    Avro 总大小: ~32 字节

    图片图片

    现在,你可能想知道,为什么这些格式中的某些会输出二进制数据,但它们的大小却各不相同。Avro、MessagePack 和 BSON 等二进制格式具有不同的内部结构和编码机制,这可能导致二进制表示法的差异,即使它们最终表示的是相同的数据。下面简要介绍一下这些差异是如何产生的:

    1. Avro

    • Avro 使用模式对数据进行编码,这种模式通常包含在二进制表示法中。
    • Avro 基于模式的编码通过提前指定数据结构,实现了高效的数据序列化和反序列化。
    • Avro 的二进制格式设计为自描述格式,这意味着模式信息包含在编码数据中。这种自描述性使 Avro 能够保持不同版本数据模式之间的兼容性。

    2. MessagePack

    • MessagePack 是一种二进制序列化格式,直接对数据进行编码,不包含模式信息。
    • 它使用长度可变的整数和长度可变的字符串的紧凑二进制表示法,以尽量减少空间使用。
    • MessagePack 不包含模式信息,因此更适用于模式已提前知晓并在发送方和接收方之间共享的情况。

    3. BSON

    • BSON 是 JSON 数据的二进制编码,包括每个值的类型信息。
    • BSON 的设计与 JSON 紧密相连,但它增加了二进制数据类型,如 JSON 缺乏的日期和二进制数据。
    • 与 MessagePack 一样,BSON 不包括模式信息。

    这些设计和编码上的差异导致了二进制表示法的不同:

    • Avro 包含模式信息并具有自描述性,因此二进制文件稍大,但与模式兼容。
    • MessagePack 的编码长度可变,因此非常紧凑,但缺乏模式信息,因此适用于已知模式的情况。
    • BSON 与 JSON 关系密切,并包含类型信息,与 MessagePack 等纯二进制格式相比,BSON 的大小会有所增加。

    总之,这些差异源于每种格式的设计目标和特点。Avro 优先考虑模式兼容性,MessagePack 侧重于紧凑性,而 BSON 在保持类似 JSON 结构的同时增加了二进制类型。格式的选择取决于您的具体使用情况和要求,如模式兼容性、数据大小和易用性。

    优化 JSON 性能

    下面是一些优化 JSON 性能的实用技巧以及代码示例和最佳实践:

    1.最小化数据大小

    • 使用简短的描述性键名:选择简洁但有意义的键名,以减少 JSON 对象的大小
    // Inefficient
    {
      "customer_name_with_spaces": "John Doe"
    }
    
    // Efficient
    {
      "customerName": "John Doe"
    }
    • 尽可能缩写:在不影响清晰度的情况下,考虑对键或值使用缩写。
    // 效率低
    {
      "transaction_type": "purchase"
    }
     
    // 效率高
    {
      "txnType": "purchase"
    }

    2.明智使用数组

    • 尽量减少嵌套:避免深度嵌套数组,因为它们会增加解析和遍历 JSON 的复杂性。
    // 效率低
    {
      "order": {
        "items": {
          "item1": "Product A",
          "item2": "Product B"
        }
      }
    }
    
    // 效率高
    {
      "orderItems": ["Product A", "Product B"]
    }

    3.优化数字表示法

    尽可能使用整数:如果数值可以用整数表示,就用整数代替浮点数。

    // 效率低
    {
      "quantity": 1.0
    }
    
    // 效率高
    {
      "quantity": 1
    }

    4.删除冗余

    避免重复数据:通过引用共享值来消除冗余数据。

    // 效率低
    {
      "product1": {
        "name": "Product A",
        "price": 10
      },
      "product2": {
        "name": "Product A",
        "price": 10
      }
    }
    
    // 效率高
    {
      "products": [
        {
          "name": "Product A",
          "price": 10
        },
        {
          "name": "Product B",
          "price": 15
        }
      ]
    }

    5.使用压缩

    应用压缩算法:如果适用,在传输过程中使用 Gzipor Brotlito 等压缩算法来减小 JSON 有效负载的大小。

    // 使用 zlib 进行 Gzip 压缩的 Node.js 示例
    const zlib = require('zlib');
    
    const jsonData = {
      // 在这里填入你的 JSON 数据
    };
    
    zlib.gzip(JSON.stringify(jsonData), (err, compressedData) => {
      if (!err) {
        // 通过网络发送 compressedData
      }
    });

    6.采用服务器端缓存:

    缓存 JSON 响应:实施服务器端缓存,高效地存储和提供 JSON 响应,减少重复数据处理的需要。

    7.配置文件和优化

    剖析性能:使用剖析工具找出 JSON 处理代码中的瓶颈,然后优化这些部分。

    实际优化:在实践中加快 JSON 的处理速度

    在本节中,我们将探讨实际案例,这些案例在使用 JSON 时遇到性能瓶颈并成功克服。我们会看到诸如 LinkedIn、Auth0、Uber 等知名技术公司如何解决 JSON 的限制并改善他们应用的性能。这些案例为如何提升应用处理速度和响应性提供了实用的策略。

    1.LinkedIn 的协议缓冲区集成:

    • 挑战:LinkedIn 面临的挑战是 JSON 的冗长以及由此导致的网络带宽使用量增加,从而导致延迟增加。
    • 解决方案:他们采用了 Protocol Buffers,这是一种二进制序列化格式,用以替换微服务通信中的 JSON。
    • 影响:这一优化将延迟降低了 60%,提高了 LinkedIn 服务的速度和响应能力。

    2.Uber 的 H3 地理索引:

    挑战:Uber 使用 JSON 来表示各种地理空间数据,但解析大型数据集的 JSON 会降低其算法速度。

    解决方案:他们引入了 H3 Geo-Index,这是一种用于地理空间数据的高效六边形网格系统,可减少 JSON 解析开销。

    影响:这一优化大大加快了地理空间业务的发展,增强了 Uber 的叫车和地图服务。

    3.Slack 的信息格式优化:

    挑战:Slack 需要在实时聊天中传输和呈现大量 JSON 格式的消息,这导致了性能瓶颈。

    解决方案:他们优化了 JSON 结构,减少了不必要的数据,只在每条信息中包含必要的信息。

    影响:这项优化使得消息展现更快,从而提高了 Slack 用户的整体聊天性能。

    4.Auth0 的协议缓冲区实现:

    挑战:Auth0 是一个流行的身份和访问管理平台,在处理身份验证和授权数据时面临着 JSON 的性能挑战。

    解决方案:他们采用协议缓冲区(Protocol Buffers)来取代 JSON,以编码和解码与身份验证相关的数据。

    影响:这一优化大大提高了数据序列化和反序列化的速度,从而加快了身份验证流程,并增强了 Auth0 服务的整体性能。

    这些现实世界中的例子展示了通过优化策略解决 JSON 的性能挑战如何对应用程序的速度、响应速度和用户体验产生实质性的积极影响。它们强调了考虑替代数据格式和高效数据结构的重要性,以克服各种情况下与 JSON 相关的速度减慢问题。

    结论

    在不断变化的网络开发环境中,优化 JSON 性能是一项宝贵的技能,它能让你的项目与众不同,并确保你的应用程序在即时数字体验时代茁壮成长。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论