听GPT 讲Istio源代码--pkg(13)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
日志服务 SLS,月写入数据量 50GB 1个月
全局流量管理 GTM,标准版 1个月
简介: 听GPT 讲Istio源代码--pkg(13)

File: istio/pkg/monitoring/counter.go

在Istio项目中,istio/pkg/monitoring/counter.go文件是用于实现计数器功能的。它提供了用于计算和记录各种类型的计数器的功能。

首先,下划线(_)是一个特殊标识符,被用作“空标识符”。在Go中,它可以用于表示一个不关心的变量或值,通常用于忽略某些返回结果或未使用的变量。

在counter.go文件中,_这些变量用于忽略一些返回值,以达到忽略不关心的效果。

接下来,counter.go中定义了几个结构体,用于表示不同类型的计数器:

  1. counter: 表示一个通用计数器的结构体。它包含了一个名称字段用于标识计数器,一个计数器的值,以及一个统计计数器增量的方法。
  2. integerCounter: 表示一个整数计数器的结构体。它继承了counter结构体,并增加了一个方法用于递增计数器的值。
  3. floatCounter: 表示一个浮点数计数器的结构体。它也继承了counter结构体,并增加了一个方法用于递增计数器的值。

这些结构体提供了不同类型的计数器对应的功能,并可以根据需要将其封装在不同的上下文中使用。

接下来是一些主要函数的介绍:

  1. newCounter: 是一个工厂函数,用于创建一个counter结构体的实例。它接受一个字符串作为计数器的名称,并返回一个新的计数器实例。该函数还会自动注册计数器,以便在监控过程中可以使用。
  2. Record: 是一个方法,用于记录和增加计数器的值。它接受一个参数,用于指定要增加的计数器值。
  3. With: 是一个装饰器函数,用于包装一个计数器,并返回一个新的counter结构体实例。它接受一个原始的counter实例和一个可变的参数列表,然后将计数器增量值传递给原始counter。

通过使用这些函数和结构体,可以方便地创建和管理各种类型的计数器,以用于监控和记录不同的系统指标。

File: istio/pkg/monitoring/distribution.go

在Istio项目中,istio/pkg/monitoring/distribution.go文件的作用是提供一组用于监视和记录分布式数据的工具方法和数据结构。

文件中的_变量用于忽略未使用的导入包,以防止编译器报错。

distribution结构体表示一个分布式数据的统计分布。它包含了以下字段:

  • Count用于记录样本的数量。
  • Sum用于存储样本的和。
  • SumOfSquares用于存储样本的平方和。

distributions结构体是一个分布式数据的集合,它由一个sync.RWMutex锁保护。它包含了多个distribution,每个distribution通过一个字符串键进行索引。

newDistribution函数用于创建一个新的distribution对象,该对象包含指定的名称和标签。

Record函数用于记录一个样本值到指定的distribution。它将样本值添加到distributionSumSumOfSquares中,并增加Count的计数。

With函数用于返回给定名称的distribution对象的引用。如果该名称的distribution不存在,则会创建一个新的distribution对象。

这些方法和数据结构提供了一种方便的方式来收集、统计和分析分布式数据,例如请求延迟、响应时间等。

File: istio/pkg/monitoring/base.go

在Istio项目中,istio/pkg/monitoring/base.go文件的作用是定义了基本的监控功能,提供了用于记录和报告度量指标的方法。

该文件中定义了一些重要的结构体和函数,包括:

  1. baseMetric结构体:用于表示一个基本的度量指标,包含了该指标的名称(Name字段)、默认值(defaultVal字段)、值类型(valueType字段)等属性。
  2. Name函数:用于获取度量指标的名称。
  3. Increment函数:用于增加度量指标的值。
  4. Decrement函数:用于减少度量指标的值。
  5. runRecordHook函数:用于运行记录钩子函数,将度量指标的当前值记录到监控系统中。
  6. Register函数:用于注册一个度量指标,将其添加到监控系统中进行跟踪。
  7. RecordInt函数:用于记录一个整数类型的度量指标。
  8. rebuildAttributes函数:用于重新构建度量指标的属性,如标签。

这些函数和结构体的作用如下:

  • baseMetric结构体定义了一个度量指标的基本属性,并提供了对该指标的增减操作。
  • Name函数返回度量指标的名称,用于标识该指标。
  • Increment函数用于增加度量指标的值,可针对某个指标进行累加操作。
  • Decrement函数用于减少度量指标的值,可针对某个指标进行递减操作。
  • runRecordHook函数用于运行记录钩子函数,将度量指标的当前值记录到监控系统中,以便进行监控和报告。
  • Register函数用于注册一个度量指标,将其添加到监控系统中进行跟踪。
  • RecordInt函数用于记录一个整数类型的度量指标,将其值保存到监控系统中。
  • rebuildAttributes函数用于重新构建度量指标的属性,如标签,以便在度量指标发生变化时进行更新。

这些函数和结构体的综合作用是提供一个方便且可扩展的接口,用于记录和报告度量指标,从而实现对Istio项目的监控和性能优化。

File: istio/pkg/monitoring/gauge.go

在Istio项目中,istio/pkg/monitoring/gauge.go文件的作用是定义和实现了度量计(Gauge)的功能。Gauge是一种度量类型,用于跟踪某个值的瞬时状态。它可以用于记录和监控关键指标,比如连接数、请求处理时间等。

在该文件中,有几个重要的变量和结构体:

  1. _:这些变量用于导入包时进行空白识别,表示忽略导入的包,因为在Istio中,该文件只导入了prometheus包,而不使用其中的变量。
  2. gauge:这个结构体表示度量计对象,它包含了一个Prometheus Gauge对象,并提供了一些方法来操作和记录该度量计的值。
  3. gaugeValues:这个结构体表示记录度量计值的对象,包含了具体的度量计和值的信息。

newGauge函数用于创建一个新的度量计对象,它接受一个描述度量计的名称和标签(labels),并返回一个度量计对象的指针。这个函数会在度量计注册表中注册该度量计。

Record函数用于记录度量计的值,它接受一个度量计对象和一个浮点数作为值,并将值记录到度量计对象中。

With函数用于为度量计对象增加标签,它接受一个度量计对象和一个包含标签的映射(map),并返回一个带有新增标签的新的度量计对象。

通过这些函数和结构体,可以方便地创建、记录和操作度量计对象,在Istio项目中用于对系统的各项指标进行度量和监控。

File: istio/pkg/monitoring/disabled.go

在Istio项目中,istio/pkg/monitoring/disabled.go文件的作用是为禁用的度量提供一个简单的实现。这个文件中定义了一些变量、结构体和函数,用于处理禁用的度量的操作。

首先,下划线 "_" 是一个空标识符,用于声明变量但不使用它们。在这个文件中,它被用于忽略一些不需要的变量。

disabledMetric结构体是对禁用度量的定义。它包含了度量的名称(Name)和标签(Labels),以及与度量相关的方法。

  • Decrement方法用于将度量递减指定的值。
  • Increment方法用于将度量递增指定的值。
  • Name方法返回度量的名称。
  • Record方法用于记录度量的值。
  • RecordInt方法用于记录整数类型的度量的值。
  • Register方法用于注册度量。
  • With方法用于创建一个带有指定标签的度量。

禁用的度量通常是在Istio中配置禁用的一种度量类型。如果度量是禁用的,那么将使用这个文件中定义的禁用度量进行处理,而不是真正的度量。

这个文件的目的是提供禁用的度量的一个默认实现,以便在度量禁用时不会导致错误。它对度量的操作实际上是不执行任何操作,它只是提供了一个占位符实现。

总而言之,disabled.go文件为禁用的度量提供了一个默认的占位符实现,用于处理禁用度量的操作。

File: istio/pkg/monitoring/units.go

在Istio项目中,istio/pkg/monitoring/units.go文件定义了用于度量标准单位转换的功能。该文件中包含了一些用于单位转换的结构体类型。

以下是units.go文件中定义的结构体及其作用:

  1. Unit结构体:表示一种度量单位,包含单位的名称和符号。例如,Unit{name: "seconds", symbol: "s"}表示时间的单位为秒。
  2. UnitGroup结构体:表示一组相关的单位,包括一个基准单位和一组衍生单位。该结构体包含以下字段:
  • baseUnit:基准单位,用于进行单位转换的基准。例如,对于时间而言,基准单位可以是秒。
  • units:衍生单位的列表,表示可以转换为基准单位的其他单位。每个衍生单位包含一个乘法因子和一个单位对象。
  1. UnitConvert结构体:表示一个单位转换器,用于执行单位转换的操作。该结构体包含以下方法:
  • ToBase:将给定的值从一种单位转换为基准单位。
  • FromBase:将给定的基准单位值转换为指定单位。
  • Convert:将给定值从一种单位转换为另一种单位。

这些结构体和方法的作用是为了提供更易于使用和理解的方式来执行单位转换。在Istio中,这些结构体和方法主要用于处理与度量标准单位相关的操作,如在监控和度量中进行单位转换和格式化显示等。

File: istio/pkg/monitoring/derived_gauge.go

在Istio项目中,istio/pkg/monitoring/derived_gauge.go文件的作用是定义了DerivedGauge接口及其默认实现DerivedGaugeImpl,用于创建和管理衍生指标(Derived Gauge)。衍生指标是从其他基础指标计算得出的指标,可用于监控或度量特定的系统或应用程序性能。

在这个文件中,_是一个空标识符,用于忽略不需要的返回值或赋值操作。

而derivedGauge结构体定义了一个衍生指标的实例,用于存储指标的名称、标签和值。

  • newDerivedGauge函数是DerivedGaugeImpl的构造函数,用于创建DerivedGaugeImpl的实例,并将衍生指标的名称和标签传递给构造函数。
  • Name函数是DerivedGaugeImpl结构体的方法,用于返回衍生指标的名称。
  • Register函数是DerivedGaugeImpl结构体的方法,用于注册衍生指标到监控指标的注册表中。
  • ValueFrom函数是DerivedGaugeImpl结构体的方法,用于计算和返回衍生指标的值。

DerivedGauge接口和DerivedGaugeImpl默认实现提供了一种在Istio项目中衡量和监控系统性能的方式。通过实例化并注册DerivedGauge,可以方便地衍生新的指标,并在程序运行时更新这些指标的值。这些衍生指标可以用于监控和度量Istio项目的各个方面,从而提供了对系统的深入了解和性能优化的基础。

File: istio/pkg/webhooks/webhookpatch.go

webhookpatch.go文件是Istio项目中的一个组件,用于在运行时动态地修改Kubernetes中的mutatingwebhookconfigurations对象,以修补证书。这个组件称为Webhook Cert Patcher。

以下是文件中的几个变量的作用:

  1. errWrongRevision:表示在webhook配置中找不到正确的修订版本错误。
  2. errNotFound:表示找不到指定名称的webhook配置错误。
  3. errNoWebhookWithName:表示没有找到指定名称的webhook错误。

以下是文件中的几个结构体的作用:

  1. WebhookCertPatcher:表示用于动态修补证书的主要结构体。它包含了用于从Kubernetes API服务器获取webhook配置并修复证书的方法。
  2. CertPatcherConfig:表示用于配置Webhook Cert Patcher的结构体。其中包括Kubernetes API服务器的相关配置以及Webhook配置的修复策略。

以下是文件中的几个函数的作用:

  1. NewWebhookCertPatcher:根据给定的配置创建一个新的Webhook Cert Patcher对象。
  2. newWebhookPatcherQueue:创建一个新的Webhook Patcher队列对象,用于管理修复任务。
  3. Run:运行Webhook Cert Patcher,该函数会循环监听并处理修复任务。
  4. HasSynced:检查是否已同步指定的webhook名称。
  5. webhookPatchTask:表示一个Webhook修复任务的结构体,包含要修复的webhook名称和修复操作。
  6. patchMutatingWebhookConfig:执行对指定webhook配置的修复操作。
  7. startCaBundleWatcher:启动一个goroutine来监听并更新CA证书的变化。

总体而言,webhookpatch.go文件中的代码实现了一个支持动态修复证书的Webhook Cert Patcher组件,用于在Istio项目中对Kubernetes中的mutatingwebhookconfigurations对象进行修改和修补操作。

File: istio/pkg/dns/proto/nds.pb.go

文件istio/pkg/dns/proto/nds.pb.go 的作用是定义了 DNS NDS(Name Data Service)的协议缓冲区。它是由Protocol Buffers (Protobuf)生成的Go语言代码。

  • File_dns_proto_nds_proto: 包含了文件名的字符串 "dns/proto/nds.proto"。
  • file_dns_proto_nds_proto_rawDesc: 存储了原始的文件描述符,以字节的形式表示。
  • file_dns_proto_nds_proto_rawDescOnce: 只加锁一次变量,用于确保只初始化一次原始文件描述符。
  • file_dns_proto_nds_proto_rawDescData: 存储了原始文件描述符的解包数据。
  • file_dns_proto_nds_proto_msgTypes: 存储了消息类型的切片。
  • file_dns_proto_nds_proto_goTypes: 存储了Go语言类型的切片。
  • file_dns_proto_nds_proto_depIdxs:存储了依赖索引的切片。
  • NameTable: 是一个消息结构体,用于存储名称表相关的信息。
  • NameTable_NameInfo: 是一个消息结构体,表示名称信息。
  • Reset: 是一个函数,用于重置消息结构体的字段值。
  • String: 是一个方法,用于将消息结构体转换为字符串形式。
  • ProtoMessage: 是一个接口,定义了协议缓冲区的消息类型。
  • ProtoReflect: 是一个接口,提供了协议缓冲区的反射方法。
  • Descriptor: 是一个接口,提供了协议缓冲区的描述符方法。
  • GetTable: 是一个方法,返回协议缓冲区的描述符。
  • GetIps: 是一个方法,返回名称表的 IP 地址列表。
  • GetRegistry: 是一个方法,返回名称表的注册表。
  • GetShortname: 是一个方法,返回名称表的短名称。
  • GetNamespace: 是一个方法,返回名称表的命名空间。
  • GetAltHosts: 是一个方法,返回名称表的备用主机列表。
  • file_dns_proto_nds_proto_rawDescGZIP: 是一个变量,存储了原始文件描述符的压缩数据。
  • init: 是一个函数,在初始化时注册协议缓冲区的描述符。
  • file_dns_proto_nds_proto_init: 是一个函数,实现了文件描述符的初始化操作。

总结来说,该文件定义了 DNS NDS 协议的消息结构体和相关的方法,并提供了与协议缓冲区的交互接口。这些结构体和方法的作用是在 DNS NDS 协议中进行数据的序列化、反序列化和操作。

File: istio/pkg/envoy/proxy.go

在Istio项目中,"istio/pkg/envoy/proxy.go"文件是一个关键的文件,其主要目的是管理与Envoy代理相关的操作和配置。

  • istioBootstrapOverrideVar:这个变量用于允许强制覆盖Istio生成的Envoy引导配置。
  • enableEnvoyCoreDump:此变量用于启用Envoy代理的核心转储功能,可以在代理发生崩溃或出现其他问题时方便地进行调试。

以下是其他重要结构体和函数的作用:

  1. envoy:此结构体表示Envoy代理实例。它包含了一些代理的基本信息,如代理节点名称、SDS(Secret Discovery Service)等。
  2. ProxyConfig:这个结构体用于保存代理的配置和运行时的上下文信息。它存储了Envoy的配置文件路径,以及其他一些配置参数,例如Tracing、Metrics等。
  3. NewProxy:此函数用于创建一个新的Envoy代理实例。它运行代理的主循环,并负责启动和管理Envoy实例。
  4. splitComponentLog:此函数用于根据指定的组件和日志级别拆分日志。它可以使Istio的日志输出更加灵活和可定制。
  5. Drain:这个函数启动了代理的排空(Drain)模式,用于控制正在更新的代理实例的所有连接不会丢失,同时不再接受新的请求。
  6. UpdateConfig:这个函数负责更新Envoy代理的配置。它会监视配置变化,并重新加载代理的配置文件以实现平滑的配置更新。
  7. args:这个函数解析并返回命令行参数。
  8. Run:此函数是整个代理的入口点。它负责处理代理的启动、初始化和关闭等过程。
  9. Cleanup:这个函数用于代理的清理和关闭。它会关闭所有与代理相关的资源,释放内存,停止代理实例的运行。

总之,"istio/pkg/envoy/proxy.go"文件中的代码负责管理Envoy代理的配置、运行和监控。它提供了一系列的函数和结构体,用于创建、更新和关闭Envoy实例,并提供了一些额外的功能,如配置覆盖和日志分割。

File: istio/pkg/test/echo/server/forwarder/dns.go

istio/pkg/test/echo/server/forwarder/dns.go是Istio项目中用于模拟DNS请求的文件。

该文件中定义了一些变量和函数,用于处理DNS请求。

下面是相关变量的作用解释:

  • :在Go语言中,下划线“”用作空白标识符,表示忽略该变量。这里的下划线变量没有具体的作用。
  • dnsProtocol:表示DNS协议类型,是一个字符串常量。
  • dnsRequest:表示DNS请求的结构体,包含请求的域名和类型等信息。

下面是相关函数的作用解释:

  • newDNSProtocol:创建一个新的DNS协议请求,默认为UDP协议。
  • ForwardEcho:转发Echo请求到远程地址,并返回响应结果。
  • checkIn:检查是否有可用的服务器地址。
  • parseRequest:解析DNS请求的数据包。
  • makeRequest:向DNS服务器发送请求,并返回响应结果。
  • Close:关闭DNS协议连接。

以上是对于文件中变量和函数的大致解释,但具体实现细节还需要参考代码来理解。

File: istio/pkg/adsc/adsc.go

在istio/pkg/adsc/adsc.go文件中,定义了用于与Pilot或MCP (Mesh Configuration Protocol)服务器进行通信的ADSC(Aggregated Discovery Service Client)结构体和相关函数。

ADSC结构体是一个用于管理与Pilot或MCP服务器通信的客户端。它维护了与服务器的连接,处理从服务器接收到的发现服务流(Discovery Service Stream),并提供了一组方法用于向服务器发送请求。

接下来,我们来了解一下文件中提到的各个变量和结构体的作用:

  1. adscLog:用于记录日志的logger对象。

下面是一些关键的方法和结构体的解释:

  • Config:包含与ADSC通信相关的配置信息。
  • ADSC:用于构建ADSC客户端的结构体。它管理连接、发送请求和处理响应等功能。
  • ResponseHandler:处理从ADSC服务器返回的响应的回调函数。
  • jsonMarshalProtoWithName:将protobuf消息序列化为JSON格式的辅助函数。

还有一些常用的方法的解释:

  • DefaultGrpcDialOptions:返回gRPC客户端的默认选项。
  • MarshalJSON:将protobuf消息序列化为JSON格式。
  • NewWithBackoffPolicy:使用指定的指数回退策略创建一个ADSC客户端。
  • New:创建一个新的ADSC客户端。
  • Dial:与Pilot或MCP服务器建立连接。
  • getPrivateIPIfAvailable:返回可用的私有IP地址。
  • tlsConfig:创建用于与Pilot或MCP服务器进行安全通信的TLS配置。
  • Close:关闭与Pilot或MCP服务器的连接。
  • Run:开启与Pilot或MCP服务器的通信循环。
  • HasSynced:检查ADSC客户端是否已经同步完成。
  • reconnect:重新连接到Pilot或MCP服务器。
  • handleRecv:处理从服务器收到的发现服务流。
  • mcpToPilot:处理MCP协议中的与Pilot服务器通信的部分。
  • handleLDS:处理从服务器返回的Listener Discovery Service (LDS)响应。
  • Save:将响应的资源存储到内部缓存。
  • handleCDS:处理从服务器返回的Cluster Discovery Service (CDS)响应。
  • node:获取当前节点的信息。
  • Send:向Pilot或MCP服务器发送请求。
  • handleEDS:处理从服务器返回的Endpoint Discovery Service (EDS)响应。
  • handleRDS:处理从服务器返回的Route Discovery Service (RDS)响应。
  • WaitClear:等待缓存清空。
  • WaitSingle:等待指定资源的响应。
  • Wait:等待所有资源的响应。
  • EndpointsJSON:返回指定服务的所有Endpoints的JSON格式。
  • Watch:监听指定的资源。
  • ConfigInitialRequests:配置初始请求。
  • sendRsc:向服务器发送资源数据。
  • ack:向服务器发送应答。
  • GetHTTPListeners:获取所有HTTP的Listeners。
  • GetTCPListeners:获取所有TCP的Listeners。
  • GetEdsClusters:获取所有EDS的Clusters。
  • GetClusters:获取所有Clusters。
  • GetRoutes:获取所有Routes。
  • GetEndpoints:获取所有Endpoints。
  • handleMCP:处理MCP请求和响应。

这些方法和结构体一起构成了一个完整的ADSC客户端,用于与Pilot或MCP服务器通信和进行服务发现。

File: istio/pkg/channels/unbounded.go

在Istio项目中,unbounded.go文件位于pkg/channels目录下,主要定义了用于无限制缓冲通道的Unbounded结构体及相关函数。

Unbounded结构体用于创建和管理一个无限制的缓冲通道,可以在生产者和消费者之间传递数据。它包括以下几个字段:

  1. buffer: 一个[]interface{}切片,用于存储通道中的元素。
  2. closed: 一个bool值,表示通道是否已关闭。
  3. listeners: 一个通道监听器的切片,用于在数据可用时通知等待中的消费者。

NewUnbounded函数用于创建一个新的Unbounded实例,它接受一个可选的参数bufferSize来指定缓冲区大小。如果不指定bufferSize或者bufferSize为0,那么将创建一个没有限制的缓冲通道。

Put函数用于将元素放入通道中,它接受一个参数item表示要放入的元素。如果缓冲区已满,则Put函数会等待直到有空间可用。

Load函数用于从通道中加载一个元素,它返回一个bool值和一个interface{}类型的元素,表示是否成功加载和加载的元素。如果通道已关闭,Load函数会立即返回false,否则它会等待直到有元素可用。

Get函数用于从通道中获取一个元素,它返回一个interface{}类型的元素。如果通道已关闭且没有可用的元素,则Get函数会立即返回nil

总结起来,unbounded.go文件中的Unbounded结构体及相关函数提供了一个无限制的缓冲通道,允许生产者放入元素并通知等待中的消费者获取元素。


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
存储 Kubernetes 测试技术
听GPT 讲Istio源代码--pkg(12)
听GPT 讲Istio源代码--pkg(12)
55 0
|
存储 Kubernetes 安全
听GPT 讲Istio源代码--security(2)
听GPT 讲Istio源代码--security(2)
62 0
|
存储 缓存 Kubernetes
听GPT 讲Istio源代码--security(1)
听GPT 讲Istio源代码--security(1)
56 0
|
4月前
|
存储 SQL 数据库
Python 金融编程第二版(GPT 重译)(四)(4)
Python 金融编程第二版(GPT 重译)(四)
49 3
|
4月前
|
存储 NoSQL 索引
Python 金融编程第二版(GPT 重译)(一)(4)
Python 金融编程第二版(GPT 重译)(一)
61 2
|
4月前
|
索引 Python
Python 金融编程第二版(GPT 重译)(二)(4)
Python 金融编程第二版(GPT 重译)(二)
31 0
|
4月前
|
存储 机器学习/深度学习 关系型数据库
Python 金融编程第二版(GPT 重译)(四)(5)
Python 金融编程第二版(GPT 重译)(四)
35 2
|
4月前
|
存储 SQL 数据可视化
Python 金融编程第二版(GPT 重译)(四)(1)
Python 金融编程第二版(GPT 重译)(四)
46 2
|
4月前
|
数据可视化 Python
Python 金融编程第二版(GPT 重译)(三)(4)
Python 金融编程第二版(GPT 重译)(三)
27 2
|
4月前
|
存储 算法 数据可视化
Python 金融编程第二版(GPT 重译)(一)(1)
Python 金融编程第二版(GPT 重译)(一)
88 1

热门文章

最新文章