【Dubbo3技术专题】「云原生微服务开发实战」 一同探索和分析研究RPC服务的底层原理和实现

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 【Dubbo3技术专题】「云原生微服务开发实战」 一同探索和分析研究RPC服务的底层原理和实现

Dubbo是一款高效而强大的RPC服务框架,它旨在解决微服务架构下的服务监控和通信问题。该框架提供了Java、Golang等多语言的SDK,使得使用者可以轻松构建和开发微服务。Dubbo具备远程地址发现和通信能力,可通过Dubbo独有的身临其境的服务治理特验为主导,以提高开发人员的功能性效率为目标,致力于为开发者提供最好的工具来优化开发流程。

RPC服务介绍

在当前互联网服务时代,服务拆分成为主流,服务之间的远程调用变得越来越复杂,使得像本地调用一样简单的远程调用成了一个大问题。在这个背景下,Dubbo是一个具有高度可扩展性的开源RPC框架。该框架提供了Java、Golang等多种语言的SDK和独特的服务治理体验,可以提高开发人员的效率。Dubbo还支持用户实现流量拦截、定制化逻辑、选址等各种定制逻辑。在微服务架构中,Dubbo具备极为重要的地位,被广泛应用于各大互联网公司的微服务场景中。总之,RPC作为一种进程间通信技术,在分布式系统中得到了广泛使用,并且作为解决微服务架构下服务治理问题的利器之一,Dubbo具有一定的优势。

RPC通信模式

当今大多数分布式系统都采用了远程过程调用(RPC)通信模式。RPC是一种通过网络调用远程服务的网络通信模式,在这种模式下,客户端和服务端之间的通信就好像是同一台机器上的程序之间进行的本地调用一样。RPC通常用于分布式应用程序的开发,它将应用程序的各个组成部分封装在独立的进程和服务中,并使用网络进行通信,旨在加速应用程序的开发和部署。 RPC通信模式通常涉及以下几个组成部分: 客户端:客户端是指发起RPC请求的应用程序或服务。在客户端发起RPC请求时,它将包含所有必要参数和方法名称的数据包发送到远程服务。 服务端:服务端是指接收RPC请求的应用程序或服务。服务端将使用接收到的数据包中的参数来执行服务并返回结果给客户端。 通信协议:通信协议是指在客户端和服务端之间传输数据所使用的协议。RPC通信模式可以使用多种协议,包括HTTP、TCP和UDP等。

序列化:序列化是指将对象转换为一组字节,以便可以在网络上传输。序列化也可以通过反序列化将对象还原到其原始状态。

RPC通信模式的优点包括:

  1. 简化了复杂的分布式应用程序的开发和部署。使用RPC通信模式,可以将各个组成部分分离为独立的进程和服务,并使用网络进行通信。这使得应用程序可以更加灵活地适应不同的场景和需求,同时简化了开发和部署过程。
  2. 提高了应用程序的性能和可扩展性。将应用程序分解为独立的组成部分并使用RPC通信模式进行通信,可以显著提高应用程序的性能和可扩展性,使其可以支持大量的同时访问和操作。
  3. 具有良好的可靠性和可用性。RPC通信模式通常使用多种协议,包括HTTP、TCP和UDP等,这些协议都具有良好的可靠性和可用性,并且可以实现远程监控和管理。

RPC架构组成

RPC技术要点

RPC通信技术选项分析

承接之前关于通信模式的内容,接下来要针对于通信模式进行分析网络通信的技术要点

RPC是一种通信协议,用于不同计算机上的进程之间进行通信。它允许一个计算机程序调用另一个计算机上的子程序,就像调用本地的子程序一样。

RPC通信的基本原理是,客户端程序通过发送请求给服务器端程序,请求执行特定的操作或获取特定的数据。服务器端程序接收请求并执行相应的操作,然后将结果返回给客户端。整个过程对于客户端来说是透明的,就像调用本地函数一样简单。

RPC通信技术的好处包括:

简化代码:通过RPC,远程调用可以被抽象为方法调用,使代码更清晰和简洁。 提高开发效率:RPC提供了一种方便的机制来调用远程服务,使分布式系统的开发更加高效。 增强系统扩展性:通过RPC,不同的组件和服务可以在不同的计算机上部署,可以方便地进行扩展和横向拓展。 促进系统集成:RPC可以作为不同系统之间进行通信的桥梁,促进系统之间的集成和协作。

RPC实战开发6大基础组件

“工欲成其事,必先利其器”,接下来,我们将会针对于RPC的实战开发基础组件进行分析和介绍,主要包括了对于所需要的基础工具和脚手架功能的插件等,有了它们我们可以打打提高我们的开发能力以及开发效率,具体6大基础如下图所示。

基础组件之Guava

Guava是由Google开发的Java工具库,它提供了丰富的实用工具类和方法,有助于开发人员编写高效、可靠的Java代码。Guava可以简化集合操作、处理字符串、并发编程和实现缓存机制等方面的工作。

使用Guava可以有效地减少开发工作量。它提供的集合类,如Immutable集合、Multiset和Multimap,可以用于RPC框架的注册中心的注册列表和元数据信息等方面。

Guava还提供了各种字符串处理工具类,包括切割、拼接、格式化和填充等功能,使得字符串操作更加便捷高效。在RPC服务框架中,可以方便地利用Guava的字符串处理能力来处理协议信息和解析传参格式。

此外,Guava还提供了强大而灵活的并发编程工具,如ListenableFuture、Futures和RateLimiter等。这些工具有助于更好地管理和控制并发任务,实现客户端调用和服务端执行时的多线程处理和异步操作能力。同时,Guava还提供了限流和服务保护等功能。

基础组件之Hutools

Hutools是一个强大而实用的Java开发工具包,可以帮助开发人员简化开发过程,提高开发效率。Hutools包含了各种功能模块,包括字符串处理、日期时间处理、文件操作、网络请求、加密解密、图片处理、Excel操作等等。

  • 网络请求:Hutools提供了丰富的网络请求工具方法,可以方便地发送HTTP请求、处理响应等。你可以使用Hutools发送RPC请求并接收响应,简化了网络请求的处理过程。
  • 序列化工具:RPC服务通常需要在网络中传输对象数据,而对象的序列化是一个常见的需求。Hutools提供了多种常用的序列化工具,如JSON、XML等,可以帮助你将对象转换成字符串或字节流,以便在网络中进行传输。
  • 编码解码工具:当进行网络传输时,数据的编码和解码是必不可少的。Hutools提供了多种常用的编码解码工具,如Base64、URL编码等,可以帮助你在RPC服务中进行数据的编码和解码处理。
  • 异常处理工具:RPC服务中可能会遇到各种异常情况,如网络异常、超时异常等。Hutools提供了一些异常处理工具,可以方便地捕获和处理异常,确保RPC服务的稳定性和可靠性。

基础组件之ReflectionASM

ReflectionASM是一个基于反射的优化库,它可以帮助开发人员在RPC服务开发中提高性能和效率。

使用ReflectionASM,你可以获得以下好处:

  • 提高反射操作的性能:反射是一种强大的机制,可以在运行时动态地获取和操作类的信息,但在性能方面存在一定的开销。ReflectionASM通过使用字节码生成技术,可以动态地生成目标类的字节码,避免了反射中的一些性能问题,提供了更快速的反射操作。
  • 减少调用开销:ReflectionASM可以生成直接调用目标方法的字节码,避免了通过反射机制间接调用的开销,从而提高了方法调用的性能。在RPC服务开发中,你可以利用ReflectionASM来优化服务接口的调用过程,提高服务的响应速度。
  • 简化代码:ReflectionASM可以帮助你生成具有相同接口的子类,这样你就能够通过正常的方法调用来操作目标类,而不需要显式地使用反射。这样可以使代码更加清晰和易于理解,并且减少了错误的可能性。

使用ReflectionASM可以在RPC服务开发中提高反射操作的性能、减少调用开销以及简化代码的编写。它是一个有效的工具,可以帮助你更高效地开发和运行RPC服务。

基础组件之FastJSON/FastJSON2

  • 序列化和反序列化:FastJSON/FastJSON2提供了强大的序列化和反序列化功能,可以将对象快速转换为JSON字符串,并将JSON字符串反序列化为对象。这在开发RPC框架服务中非常实用,可以将对象转换为字节流进行网络传输,并在远程服务端将字节流反序列化为对象进行处理。
  • 数据传输:FastJSON/FastJSON2可以将对象序列化为易于传输和解析的JSON字符串。在RPC框架中,可以使用FastJSON/FastJSON2将请求参数、响应结果等数据转换为JSON字符串,并通过网络进行传输。这种方式能够简化数据传输过程,并提高可读性。
  • 跨语言支持:FastJSON/FastJSON2是一种跨语言的JSON序列化和反序列化库,可以在不同编程语言之间进行数据交换。如果你的RPC框架需要与其他编程语言的服务进行交互,使用FastJSON/FastJSON2可以方便地进行JSON数据的序列astJSON2是一个高性能的JSON处理库,具有出色的序列化效率和低资源消耗。在RPC框架中,性能是非常重要的因素。使用FastJSON/FastJSON2可以提高数据的传输效率,减少网络延迟,从而提升RPC框架的整体性能。

总的来说,使用FastJSON/FastJSON2工具组件可以帮助简化开发RPC框架服务的过程,并提供高效的序列化和反序列化功能、跨语言支持以及高性能处理能力。这些功能有助于提升RPC框架的效率和可扩展性,提供更好的用户体验。

基础组件之FST

相比于FastJSON,FST 在某些方面具有更高的性能,FST 是一个专为高性能而设计的序列化库,它相对于 FastJSON 具有更快的序列化和反序列化速度。这主要是因为 FST 序列化库采用了一些优化策略,包括使用二进制格式、压缩编码和缓存等,从而提供更高效的数据处理性能。

相比FastJSON的优势

  • 更小的序列化结果: FST 序列化库生成的序列化结果通常更小,占用更少的存储空间。这可以减少网络传输的数据量,降低带宽占用。相比之下,FastJSON 生成的 JSON 字符串通常比二进制数据要大。
  • 更好的兼容性: FST 序列化库支持与不同编程语言和框架之间的交互。它的序列化和反序列化规则在不同环境下都是一致的,因此可以很方便地与其他系统进行数据交换,而不需要进行复杂的转换或兼容性处理。
  • 更低的资源消耗: FST 序列化库占用的系统资源较少,包括较低的 CPU 使用率和内存占用。这有助于提高系统的整体性能和资源利用率。
  1. 高性能:FST(Fast-Serialization)是一个高性能的二进制序列化库,相比于其他序列化方式,它能够更快地将对象序列化为字节流,并能够在远程服务端更快地反序列化字节流为对象。这在RPC服务中是非常有价值的,因为高性能的序列化和反序列化可以帮助提升整个RPC服务的性能和响应速度。
  2. 节省带宽:FST序列化库采用了紧凑的二进制格式,可以将对象序列化为较小的字节流。相比于使用文本格式的序列化方式(如JSON或XML),FST序列化可以有效地减少通过网络传输的数据量,从而节省带宽和降低网络延迟。
  3. 兼容性:FST序列化库具有良好的兼容性,能够与不同编程语言和框架进行交互。这意味着,如果你的RPC服务需要与其他编程语言的服务进行通信,使用FST序列化可以方便地进行数据交换,而无需过多的数据格式转换和兼容性处理。
  4. 简化开发:使用FST序列化库可以简化RPC服务的开发过程。它提供了简单易用的API接口,使得对象的序列化和反序列化变得简洁明了。同时,FST序列化还支持自定义序列化和反序列化的规则,使得开发者可以根据具体业务需求进行定制,进一步简化开发工作。

总而言之,RPC服务中使用FST序列化可以带来高性能、节省带宽、兼容性和简化开发等多重作用。这使得RPC服务更加高效、灵活和易于开发,从而提供更好的用户体验。

基础组件之Commons-Codec

最后一个基础组件是Commons Codec,它是一个开源的 Java 库,提供了各种常见编码和解码的功能。作为一个 RPC 框架的开发者,你可以利用 Commons Codec 来实现以下几个方面的功能:

  • 字符串编码和解码:在 RPC 框架中,你可能需要对字符串数据进行编码和解码,以确保数据传输的安全性和可靠性。Commons Codec 提供了许多常见的编码算法,如 Base64、URL 编码、HTML 编码等,可以方便地对字符串进行编码和解码操作。
  • 摘要算法:在 RPC 框架中,为了验证数据的完整性和一致性,常常需要使用哈希算法生成数据的摘要。Commons Codec 提供了一系列的消息摘要算法,如 MD5、SHA-1、SHA-256 等,可以方便地计算数据的摘要值。
  • 加密和解密:为了保护敏感数据在网络传输过程中的安全性,RPC 框架通常需要使用加密算法对数据进行加密和解密。Commons Codec 提供了一些常见的加密算法,如 AES、DES、RSA 等,可以方便地实现数据的加密和解密功能。
  • 编码规范:在 RPC 框架的开发过程中,为了保持代码的高质量和可读性,使用一些编码规范是很有帮助的。Commons Codec 提供了一些编码规范和实用工具,可以帮助你编写更加规范和易于维护的代码。

开发一个 RPC框架,Commons Codec 可以提供编码、摘要、加密等功能的支持,帮助你更轻松地实现数据处理和安全性保护的需求。

RPC框架层面选项分析

上一节已经介绍了开发一个RPC框架所需要的基础工具组件。接下来,我们将进行技术设计分析,着重考虑RPC框架能够支持的技术框架生态,尤其是在Java领域,基本的开发模式如下图所示。

首先,Java领域的主流框架生态之一是Spring框架。考虑到广泛的应用和丰富的功能,RPC框架应该支持与Spring框架的集成,以便于与现有的Spring项目进行无缝对接和使用。

除了Spring框架,还有一些服务可能并未使用Spring框架。对于此类服务,我们需要提供兼容处理,建立Frameworkless模式的原生Java开发模式。这样,即使没有依赖于特定框架的服务也能够无缝接入RPC框架。

另外,还有其他一些第三方框架,如JFinal等,也有可能被广泛使用。作为一个全面的RPC框架,我们应该考虑与这些第三方框架的集成,为开发者提供更多选择和便利。

注意:对于Java领域的RPC框架,我们应该首先支持与Spring框架的集成,其次提供Frameworkless模式的原生Java开发支持,最后考虑与其他第三方框架的集成,如JFinal等。这样可以确保RPC框架能够在不同的技术框架生态中灵活应用和扩展。

RPC组件化的扩展机制

RPC组件化的扩展机制主要面向于两个方面,分别是采用JVMTI技术进行实现热刷新机制。

RPC(远程过程调用)组件化的扩展机制是指通过使用Java的Agent探针技术来实现对RPC服务的动态化处理和扩展能力。这种机制可以在运行时对RPC组件进行增强、修改或替换,以满足不同的业务需求。

Java的Agent机制允许在Java应用程序运行时通过动态生成字节码来修改或增强已加载的类,同时也可以控制类的加载和转换过程。对于RPC组件,Agent探针技术可以在服务启动时动态地对相关类进行处理,以实现扩展功能。具体来说,Agent可以在加载RPC组件的类时,使用字节码操作来修改其中的方法实现、增加拦截器、添加性能监控等。这样一来,就能够方便地定制和扩展RPC组件的功能,而无需修改原始的源代码。

通过采用Agent的探针技术进行动态化处理织入扩展能力可以带来许多好处。首先,它具有灵活性和可扩展性,使得开发人员能够根据实际需求动态地对RPC组件进行增强和修改,而不必依赖于静态的源代码。其次,它使得扩展功能可以独立于应用程序的开发周期和发布过程,因此可以实现运行时的动态更新和部署。最后,Agent机制也提供了一种非侵入式的扩展方式,既不影响原有的业务逻辑,又能够灵活地添加额外的功能。

总结而言,RPC组件化的扩展机制通过使用Java的Agent探针技术,为RPC服务提供了动态化处理织入扩展能力,使得开发人员可以在运行时对RPC组件进行定制和扩展。这种机制能够提高开发效率、灵活应对需求变化,同时也方便了系统的维护和更新。

RPC容器化部署发布机制

RPC设计模式

RPC(Remote Procedure Call)是一种用于实现远程过程调用的技术,它允许不同的计算机之间通过网络进行函数调用和数据交互。在设计RPC服务时,可以使用以下几种设计模式来提高系统的可扩展性、可靠性和可维护性:

  • 代理模式(Proxy Pattern):在RPC中,客户端需要调用远程服务,而不需要关心实际的实现细节。使用代理模式可以隐藏底层通信细节,提供一个简单的API供客户端调用。
  • 工厂模式(Factory Pattern):在RPC中,可能存在多种类型的服务需要被调用。使用工厂模式可以根据不同的服务类型来创建具体的服务实例,提供灵活的服务创建和管理机制。
  • 观察者模式(Observer Pattern):在RPC中,服务的状态可能会发生变化,例如服务的可用性、延迟等。使用观察者模式可以让客户端或其他组件订阅服务状态的变化,并及时处理相应的变动,提高系统的可靠性。
  • 重试模式(Retry Pattern):在RPC中,由于网络不可靠性或服务不可用等原因,调用可能会失败。使用重试模式可以在调用失败时进行重试,提高调用的成功率和可靠性。
  • 断路器模式(Circuit Breaker Pattern):在RPC中,服务的不可用性或延迟可能会导致系统性能下降甚至崩溃。使用断路器模式可以在服务不可用时进行熔断处理,防止系统负载过大,提高系统的可用性和稳定性。
  • 限流模式(Rate Limiting Pattern):在RPC中,服务可能会被频繁调用,导致系统资源消耗过多或负载过高。使用限流模式可以限制调用频率,保护系统免受过多请求的影响,提高系统的性能和稳定性。

RPC难点分析

如何保障对后面扩展功能的支持

多数采用工厂模式

工厂模式是一种创建对象的设计模式,它通过一个工厂类来创建对象,隐藏了实例化对象的细节。在实际开发中,工厂模式大量应用于对象的创建和管理。通过使用工厂模式,可以将对象的创建集中管理,提高代码的封装性和可维护性。

面向接口的动态代理:

面向接口的动态代理是一种通过代理类来处理方法调用的机制,它可以在运行时创建动态代理对象,并在代理对象的方法中添加额外的逻辑,如方法调用前后的处理。面向接口的动态代理可以用于实现横切关注点的模块化和复用,例如日志记录、性能监控等。

拦截器和AOP的支持

拦截器和面向切面编程(AOP)是一种编程范式,用于实现在应用程序中多个模块之间的解耦和横切功能。拦截器机制允许在方法调用前后执行额外的逻辑,如日志记录、权限检查等。AOP通过将横切关注点(如事务管理、异常处理)从业务逻辑中分离出来,使代码更加模块化、可维护和可测试。

SPI的可配置化替换实现

SPI(Service Provider Interface)是一种可插拔机制,它允许开发人员定义一组接口和服务提供者实现,然后通过配置文件等方式将特定的实现进行替换。SPI机制允许应用程序在不修改源代码的情况下切换不同的实现,提供了可插拔性和可扩展性。

数据模型的可塑性

服务接口的数据隔离设计

数据隔离是一种在服务接口中保护数据安全性和隐私的设计方法。它通过限制对数据的访问和操作,确保数据仅对授权的用户可见和可操作。在设计服务接口的数据隔离时,可以采用以下方法:

  1. 身份验证和授权:确保只有经过身份验证和授权的用户可以访问特定的数据。可以使用令牌、角色或权限控制来实现身份验证和授权机制。
  2. 数据过滤:根据用户的权限和访问级别,对数据进行过滤和筛选,确保用户只能看到他们有权限访问的数据。
  3. 数据掩码和加密:对敏感数据进行掩码或加密处理,确保数据保持匿名化和加密状态,以控制对数据的访问。
  4. 数据分区:根据业务需求,将数据进行逻辑上的分区,确保不同用户只能访问和操作属于他们的数据。

服务接口版本控制设计

服务接口版本控制是一种管理和演化服务接口的方法,旨在确保在接口变更时能够向后兼容并支持不同版本的客户端。在设计服务接口的版本控制时,可以采用以下方法:

  1. URI版本控制:通过在URI路径中添加版本号来区分不同的接口版本。例如,/v1/api/或/api/v1/。
  2. 请求头版本控制:客户端可以通过请求头传递版本号信息,服务器根据版本号选择相应的处理逻辑。
  3. Query参数版本控制:通过在查询参数中添加版本号来区分不同的接口版本。例如,/api?version=1。
  4. 媒体类型版本控制:客户端可以通过Accept头字段指定所需的媒体类型和版本号。

数据包传输的类型设计

在设计数据包传输的类型时,可以考虑以下设计选项:

  1. 同步传输:数据包同步传输是一种阻塞式的传输方式,发送方等待接收方确认后再传输下一个数据包。
  2. 异步传输:数据包异步传输是一种非阻塞式的传输方式,发送方无需等待接收方的确认即可继续传输下一个数据包。
  3. 批量传输:将多个数据包打包成一个批次进行传输,可以提高传输效率。
  4. 压缩传输:对数据包进行压缩处理,减小数据包的大小,从而提高传输速度和带宽利用率。
  5. 加密传输:对数据包进行加密处理,确保数据包在传输过程中的安全性。

在选择数据包传输的类型时,需要根据应用的需求、网络环境和性能要求综合考虑,并选择最适合的传输方式。

复制代码


相关文章
|
11天前
|
边缘计算 运维 Cloud Native
浙江省科技进步奖一等奖!阿里云云原生技术实现新突破
科技成果鉴定委员会高度评价该技术,“项目研发难度大,成果创新性强,对促进关键技术进步及自主可控具有重大意义,成果在国内外开源社区产生了广泛影响,并成功应用于互联网、交通、金融、物流、医疗等多个行业。”
|
11天前
|
监控 Cloud Native 持续交付
云原生技术在现代企业中的应用与实践
本文将深入探讨云原生技术如何改变现代企业的运作模式,提升业务灵活性和创新能力。通过实际案例分析,我们将揭示云原生架构的关键要素、实施步骤以及面临的挑战,为读者提供一套清晰的云原生转型指南。
|
11天前
|
边缘计算 运维 Cloud Native
阿里云基于云原生的大规模云边协同关键技术及应用荣获浙江省科学技术进步一等奖
11月22日, 2023年度浙江省科学技术奖获奖成果公布,阿里云与浙江大学、支付宝、谐云科技联合完成的基于云原生的大规模云边协同关键技术及应用获得浙江省科学技术进步一等奖。
|
15天前
|
边缘计算 Cloud Native 安全
云原生技术的未来发展趋势
云原生技术的未来发展趋势
34 1
|
20天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
78 6
|
20天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
31 1
|
3月前
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
3月前
|
负载均衡 Java 应用服务中间件
微服务分布式系统架构之zookeeper与dubbor-1
微服务分布式系统架构之zookeeper与dubbor-1
|
4月前
|
Kubernetes Cloud Native Docker
云原生之旅:从容器到微服务的架构演变
【8月更文挑战第29天】在数字化时代的浪潮下,云原生技术以其灵活性、可扩展性和弹性管理成为企业数字化转型的关键。本文将通过浅显易懂的语言和生动的比喻,带领读者了解云原生的基本概念,探索容器化技术的奥秘,并深入微服务架构的世界。我们将一起见证代码如何转化为现实中的服务,实现快速迭代和高效部署。无论你是初学者还是有经验的开发者,这篇文章都会为你打开一扇通往云原生世界的大门。
|
4月前
|
负载均衡 应用服务中间件 持续交付
微服务架构下的Web服务器部署
【8月更文第28天】随着互联网应用的不断发展,传统的单体应用架构逐渐显露出其局限性,特别是在可扩展性和维护性方面。为了解决这些问题,微服务架构应运而生。微服务架构通过将应用程序分解成一系列小型、独立的服务来提高系统的灵活性和可维护性。本文将探讨如何在微服务架构中有效部署和管理Web服务器实例,并提供一些实际的代码示例。
125 0