http://www.cnblogs.com/ityouknow/p/6854805.html
https://blog.csdn.net/azadalee/article/details/72123193

http://huhanlin.com/2018/07/09/springcloud%E8%BF%9B%E9%98%B6-eureka%E9%85%8D%E7%BD%AE/

Eureka是Netflix开源的一款提供服务注册和发现的产品,它提供了完整的Service Registry和Service Discovery实现。也是springcloud体系中最重要最核心的组件之一。

 

上图简要描述了Eureka的基本架构,由3个角色组成:

1、Eureka Server

  • 提供服务注册和发现

2、Service Provider

  • 服务提供方
  • 将自身服务注册到Eureka,从而使服务消费方能够找到

3、Service Consumer

  • 服务消费方
  • 从Eureka获取注册服务列表,从而能够消费服务

 

参数配置:

eureka.client.registry-fetch-interval-seconds
表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒

eureka.instance.lease-expiration-duration-in-seconds
leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该instance。

默认为90秒

如果该值太大,则很可能将流量转发过去的时候,该instance已经不存活了。

如果该值设置太小了,则instance则很可能因为临时的网络抖动而被摘除掉。

该值至少应该大于leaseRenewalIntervalInSeconds

eureka.instance.lease-renewal-interval-in-seconds
leaseRenewalIntervalInSeconds,表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。

默认30秒

eureka.instance.ipAddress

如果没有,就按照docker中的地址。否则按照ipAddress的ip作为注册的ip地址

在本地开发,对接主机上服务注册是有用

eureka.server.enable-self-preservation
是否开启自我保护模式,默认为true。

默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。

Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。

综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

eureka.server.eviction-interval-timer-in-ms
eureka server清理无效节点的时间间隔,默认60000毫秒,即60秒
 

案例实践

Eureka Server

spring cloud已经帮我实现了服务注册中心,我们只需要很简单的几个步骤就可以完成。

1、pom中添加依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2、添加启动代码中添加@EnableEurekaServer注解

@SpringBootApplication
@EnableEurekaServer
public class SpringCloudEurekaApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudEurekaApplication.class, args);
    }
}

3、配置文件

在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为,在application.properties添加以下配置:

spring.application.name=spring-cloud-eureka

server.port=8000
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/
  • eureka.client.register-with-eureka :表示是否将自己注册到Eureka Server,默认为true。
  • eureka.client.fetch-registry :表示是否从Eureka Server获取注册信息,默认为true。
  • eureka.client.serviceUrl.defaultZone :设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。默认是http://localhost:8761/eureka ;多个地址可使用 , 分隔。

启动工程后,访问:http://localhost:8000/,可以看到下面的页面,其中还没有发现任何服务

springcloud eureka 基础配置及集群、配置

 

集群

注册中心这么关键的服务,如果是单点话,遇到故障就是毁灭性的。在一个分布式系统中,服务注册中心是最重要的基础部分,理应随时处于可以提供服务的状态。为了维持其可用性,使用集群是很好的解决方案。Eureka通过互相注册的方式来实现高可用的部署,所以我们只需要将Eureke Server配置其他可用的serviceUrl就能实现高可用部署。

 

双节点注册中心

首次我们尝试一下双节点的注册中心的搭建。

1、创建application-peer1.properties,作为peer1服务中心的配置,并将serviceUrl指向peer2

spring.application.name=spring-cloud-eureka
server.port=8000
eureka.instance.hostname=peer1

eureka.client.serviceUrl.defaultZone=http://peer2:8001/eureka/

2、创建application-peer2.properties,作为peer2服务中心的配置,并将serviceUrl指向peer1

spring.application.name=spring-cloud-eureka
server.port=8001
eureka.instance.hostname=peer2

eureka.client.serviceUrl.defaultZone=http://peer1:8000/eureka/

3、host转换

在hosts文件中加入如下配置

127.0.0.1 peer1  
127.0.0.1 peer2  

4、打包启动

依次执行下面命令

#打包
mvn clean package
# 分别以peer1和peeer2 配置信息启动eureka
java -jar spring-cloud-eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1
java -jar spring-cloud-eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2

依次启动完成后,浏览器输入:http://localhost:8000/ 效果图如下:

springcloud eureka 基础配置及集群、配置

根据图可以看出peer1的注册中心DS Replicas已经有了peer2的相关配置信息,并且出现在available-replicas中。我们手动停止peer2来观察,发现peer2就会移动到unavailable-replicas一栏中,表示peer2不可用。

到此双节点的配置已经完成。

 

eureka集群使用

在生产中我们可能需要三台或者大于三台的注册中心来保证服务的稳定性,配置的原理其实都一样,将注册中心分别指向其它的注册中心。这里只介绍三台集群的配置情况,其实和双节点的注册中心类似,每台注册中心分别又指向其它两个节点即可,使用application.yml来配置。

application.yml配置详情如下:

---
spring:
  application:
    name: spring-cloud-eureka
  profiles: peer1
server:
  port: 8000
eureka:
  instance:
    hostname: peer1
  client:
    serviceUrl:
      defaultZone: http://peer2:8001/eureka/,http://peer3:8002/eureka/
---
spring:
  application:
    name: spring-cloud-eureka
  profiles: peer2
server:
  port: 8001
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: http://peer1:8000/eureka/,http://peer3:8002/eureka/
---
spring:
  application:
    name: spring-cloud-eureka
  profiles: peer3
server:
  port: 8002
eureka:
  instance:
    hostname: peer3
  client:
    serviceUrl:
      defaultZone: http://peer1:8000/eureka/,http://peer2:8001/eureka/

分别以peer1、peer2、peer3的配置参数启动eureka注册中心。

java -jar spring-cloud-eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1
java -jar spring-cloud-eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2
java -jar spring-cloud-eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer3

依次启动完成后,浏览器输入:http://localhost:8000/ 效果图如下:

springcloud eureka 基础配置及集群、配置

可以在peer1中看到了peer2、peer3的相关信息。至此eureka集群也已经完成了

 

SpringCloud进阶–Eureka配置

文章内索引

[显示]

服务端参数设置

spring读取org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean类中的参数,作为EurekaServer的配置,服务端的前缀为eureka.server。

30

参数名 描述 默认值
aWSAccessId AWS Access Id,这主要用于弹性IP绑定, 提供适当的AWS权限来绑定EIP。 null
aWSSecretKey AWS的秘***。这主要用于弹性IP的选择。访问id应该提供适当的AWS权限来绑定EIP。 null
eIPBindRebindRetries 获取服务器应该尝试绑定到候选EIP的次数。这些更改在运行时是有效的。 3
getEIPBindingRetryIntervalMsWhenUnbound 获取服务器应该检查EIP是否被绑定的时间间隔 1 * 60 * 1000
getEIPBindingRetryIntervalMs 稳定状态检查下,获取服务器应该检查EIP是否被绑定的时间间隔。 5 * 60 * 1000
enableSelfPreservation eurekaserver的健康检测,当出现出现网络分区、eureka在短时间内丢失过多客户端时,会进入自我保护模式,即一个服务长时间没有发送心跳,eureka也不会将其删除。 true
renewalPercentThreshold 阈值因子,如果阈值比最小值大,则自我保护模式开启。#关于配置解释可以参考https://stackoverflow.com/questions/33921557/understanding-spring-cloud-eureka-server-self-preservation-and-renew-threshold

 

 

0.85
renewalThresholdUpdateIntervalMs 阈值更新的时间间隔,单位为毫秒 15 * 60 * 1000
peerEurekaNodesUpdateIntervalMs  集群里eureka节点的变化信息更新的时间间隔,单位为毫秒。用户可以使用Archaius提供的DNS机制或动态配置来动态更改信息。 10 * 60 * 1000
enableReplicatedRequestCompression 复制的数据在发送请求时是否被压缩。 false
NumberOfReplicationRetries 获取集群里服务器尝试复制数据的次数 6
peerEurekaStatusRefreshTimeIntervalMs  服务器节点的状态信息被更新的时间间隔 30 * 1000
waitTimeInMsWhenSyncEmpty  在Eureka服务器获取不到集群里对等服务器上的实例时,需要等待的时间,单位为毫秒. 5 * 60 * 1000
peerNodeConnectTimeoutMs 集群内对等节点连接超时时间 200
peerNodeReadTimeoutMs 集群内对等节点读取超时时间 200
peerNodeTotalConnections 读取对等节点服务器复制的超时的时间 1000
peerNodeTotalConnectionsPerHost 获取对等节点上http连接的总数 500
peerNodeConnectionIdleTimeoutSeconds http连接被清理之后服务器的空闲时间 30
retentionTimeInMSInDeltaQueue 客户端保持增量信息缓存的时间,从而保证不会丢失这些信息,单位为毫秒 3 * 60 * 1000
evictionIntervalTimerInMs 过期实例应该启动并运行的时间间隔 300
aSGQueryTimeoutMs ASG查询超时时间  
aSGUpdateIntervalMs ASG更新时间间隔 5min
aSGCacheExpiryTimeoutMs ASG缓存到期超时时间,默认大于asg update interval 10min
responseCacheAutoExpirationInSeconds 当注册表信息被改变时,则其被保存在缓存中不失效的时间. 180 s
responseCacheUpdateIntervalMs  客户端的有效负载缓存应该更新的时间间隔 30
useReadOnlyResponseCache 目前采用的是二级缓存策略,一个是读写高速缓存过期策略,另一个没有过期只有只读缓存,默认为true,表示只读缓存 true
disableDelta 增量信息是否可以提供给客户端看,默认为false false
MaxIdleThreadInMinutesAgeForStatusReplication 状态复制线程可以保持存活的空闲时间,默认为10分钟 10min
minThreadsForStatusReplication  被用于状态复制的线程的最小数目 1
maxThreadsForStatusReplication  被用于状态复制的线程的最大数目 1
maxElementsInStatusReplicationPool 可允许的状态复制池备份复制事件的最大数量 10000
syncWhenTimestampDiffers 当时间变化实例是否跟着同步 true
registrySyncRetries 当eureka服务器启动时尝试去获取集群里其他服务器上的注册信息的次数 0
registrySyncRetryWaitMs 当eureka服务器启动时获取其他服务器的注册信息失败时,会再次尝试获取,期间需要等待的时间 30*1000
maxElementsInPeerReplicationPool 复制池备份复制事件的最大数量 10000
maxIdleThreadAgeInMinutesForPeerReplication 复制线程可以保持存活的空闲时间 15
minThreadsForPeerReplication 获取将被用于复制线程的最小数目 5
maxThreadsForPeerReplication 获取将被用于复制线程的最大数目 20
maxTimeForReplication 尝试在丢弃复制事件之前进行复制的时间 30000
primeAwsReplicaConnections 对集群中服务器节点的连接是否应该准备 True
disableDeltaForRemoteRegions 增量信息是否可以提供给客户端或一些远程地区 False
remoteRegionConnectTimeoutMs 连接到对等远程地eureka节点的超时时间 1000
remoteRegionReadTimeoutMs 获取从远程地区eureka节点读取信息的超时时间 1000
remoteRegionTotalConnections 获取远程地区对等节点上http连接的总数 1000
remoteRegionTotalConnectionsPerHost 获取远程地区特定的对等节点上http连接的总数 500
remoteRegionConnectionIdleTimeoutSeconds  http连接被清理之后远程地区服务器的空闲时间 30
gZipContentFromRemoteRegion eureka服务器中获取的内容是否在远程地区被压缩 True
remoteRegionUrlsWithName 针对远程地区发现的网址域名的map New HashMap<>()
remoteRegionUrls 远程地区的URL列表 Null
remoteRegionAppWhitelist 必须通过远程区域中检索的应用程序的列表 Null
remoteRegionRegistryFetchInterval 从远程区域取出该注册表的信息的时间间隔 30
remoteRegionFetchThreadPoolSize  用于执行远程区域注册表请求的线程池的大小 20
remoteRegionTrustStore 用来合格请求远程区域注册表的信任存储文件 “”
remoteRegionTrustStorePassword 获取偏远地区信任存储文件的密码 Changeit
disableTransparentFallbackToOtherRegion 如果在远程区域本地没有实例运行,对于应用程序回退的旧行为是否被禁用 False
batchReplication 表示集群节点之间的复制是否为了网络效率而进行批处理 False
rateLimiterEnabled 限流是否应启用或禁用 False
rateLimiterThrottleStandardClients 认证的客户端列表,这里是除了标准的eureka Java客户端。 False
rateLimiterPrivilegedClients 认证的客户端列表,这里是除了标准的eureka Java客户端。 Collections.emptySet();
rateLimiterBurstSize 速率限制的burst size ,这里用的是令牌桶算法 10
rateLimiterRegistryFetchAverageRate 速率限制器用的是令牌桶算法,此配置指定平均执行注册请求速率 500
rateLimiterFullFetchAverageRate  速率限制器用的是令牌桶算法,此配置指定平均执行请求速率 100
logIdentityHeaders Eureka服务器是否应该登录clientAuthHeaders True
listAutoScalingGroupsRoleName 用来描述从AWS第三账户的自动缩放组中的角色名称 ListAutoScalingGroups
enableReplicatedRequestCompression   False
jsonCodecName 如果没有设置默认的编解码器将使用全JSON编解码器,获取的是编码器的类名称 Null
xmlCodecName 如果没有设置默认的编解码器将使用xml编解码器,获取的是编码器的类名称 Null
route53BindRebindRetries 服务器尝试绑定到候选Route53域的次数 3
route53BindingRetryIntervalMs 服务器应该检查是否和Route53域绑定的时间间隔 5min
route53DomainTTL 用于建立route53域的ttl
bindingStrategy 获取配置绑定EIP或Route53的策略。 EIP
minAvailableInstancesForPeerReplication 当尝试新功能迁移过程时,为了避免配置API污染,相应的配置即可投入实验配置部分 -1

客户端参数配置

spring读取org.springframework.cloud.netflix.eureka.EurekaClientConfigBean类中的参数,作为EurekaClient的配置,服务端的前缀为eureka.client。

参数名 描述 默认值
registryFetchIntervalSeconds  从eureka服务器注册表中获取注册信息的时间间隔(s) 30
instanceInfoReplicationIntervalSeconds 复制实例变化信息到eureka服务器所需要的时间间隔 30
initialInstanceInfoReplicationIntervalSeconds  最初复制实例信息到eureka服务器所需的时间 40
eurekaServiceUrlPollIntervalSeconds 询问Eureka服务url信息变化的时间间隔 5min
proxyPort  获取eureka服务的代理主机 “”
proxyHost 获取eureka服务的代理端口 “”
proxyUserName 获取eureka服务的代理用户名 “”
proxyPassword 获取eureka服务的代理密码 “”
eurekaServerReadTimeoutSeconds  eureka需要超时读取之前需要等待的时间 8
eurekaServerConnectTimeoutSeconds  eureka需要超时连接之前需要等待的时间 5
backupRegistryImpl 获取实现了eureka客户端在第一次启动时读取注册表的信息作为回退选项的实现名称 “”
eurekaServerTotalConnections  eureka客户端允许所有eureka服务器连接的总数目 200
eurekaServerTotalConnectionsPerHost eureka客户端允许eureka服务器主机连接的总数目 50
eurekaServerURLContext 表示eureka注册中心的路径,如果配置为eureka,则为http://x.x.x.x:x/eureka/,在eureka的配置文件中加入此配置表示eureka作为客户端向注册中心注册,从而构成eureka集群。此配置只有在eureka服务器ip地址列表是在DNS中才会用到 “”
eurekaServerPort  获取eureka服务器的端口,此配置只有在eureka服务器ip地址列表是在DNS中才会用到 “”
eurekaServerDNSName 获取要查询的DNS名称来获得eureka服务器,此配置只有在eureka服务器ip地址列表是在DNS中才会用到。 “”
region 获取实例所在的地区。 us-east-1
eurekaConnectionIdleTimeoutSeconds Eureka服务的http请求关闭之前其响应的时间 30
registryRefreshSingleVipAddress 此客户端只对一个单一的VIP注册表的信息感兴趣 “”
heartbeatExecutorThreadPoolSize 心跳执行程序线程池的大小 2
heartbeatExecutorExponentialBackOffBound 心跳执行程序回退相关的属性,是重试延迟的最大倍数值 10
cacheRefreshExecutorThreadPoolSize  执行程序缓存刷新线程池的大小 2
cacheRefreshExecutorExponentialBackOffBound 执行程序指数回退刷新的相关属性,是重试延迟的最大倍数值 10
serviceUrl Eureka服务器的连接,默认为http://XXXX:X/eureka/,但是如果采用DNS方式获取服务地址,则不需要配置此设置。 New HashMap<>()
gZipContent eureka注册表的内容是否被压缩,默认为true,并且是在最好的网络流量下被压缩 true
useDnsForFetchingServiceUrls eureka客户端是否应该使用DNS机制来获取eureka服务器的地址列表 false
registerWithEureka 实例是否在eureka服务器上注册自己的信息以供其他服务发现 true
preferSameZoneEureka  实例是否使用同一zone里的eureka服务器,默认为true,理想状态下,eureka客户端与服务端是在同一zone下 true
logDeltaDiff 是否记录eureka服务器和客户端之间在注册表的信息方面的差异 False
disableDelta 指示“发现”客户端是否应该禁用delta的取回,而应该求助于获得完整的注册表信息。请注意,delta取回可以极大地减少流量,因为与“发现”服务器的更改速率通常比取回的速率要低得多。这些变化在运行时在下一次注册表获取周期中是有效的,这是由注册中心的terfetchinterval秒指定的 false
fetchRemoteRegionsRegistry  eureka服务注册表信息里的以逗号隔开的地区名单,如果不这样返回这些地区名单,则客户端启动将会出错。 “”
availabilityZones  获取实例所在的地区下可用性的区域列表,用逗号隔开。 New HashMap<>()
filterOnlyUpInstances  是否获得处于开启状态的实例的应用程序过滤之后的应用程序 true
fetchRegistry 此客户端是否获取eureka服务器注册表上的注册信息 true
dollarReplacement  eureka服务器序列化/反序列化的信息中获取“$”符号的的替换字符串。 “_-“
escapeCharReplacement  eureka服务器序列化/反序列化的信息中获取“_”符号的的替换字符串 “__”
allowRedirects  服务器是否能够重定向客户端请求到备份服务器。 如果设置为false,服务器将直接处理请求,如果设置为true,它可能发送HTTP重定向到客户端。 true
onDemandUpdateStatusChange 如果设置为true,客户端的状态更新将会点播更新到远程服务器上 true
encoderName 这是一个短暂的编码器的配置,如果最新的编码器是稳定的,则可以去除 “”
decoderName 这是一个短暂的解码器的配置,如果最新的解码器是稳定的,则可以去除, “”
clientDataAccept 客户端数据接受的EurekaAccept名称 EurekaAccept.full.name()

EurekaInstance配置

spring读取org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean类中的参数,作为Eureka实例的配置,服务端的前缀为eureka.instance。

参数名 描述 默认值
hostInfo org.springframework.cloud.commons.util.InetUtils.HostInfo,host的封装  
InetUtils org.springframework.cloud.commons.util.InetUtils  
appname  获得在eureka服务上注册的应用程序的名字 unknown
appGroupName 获得在eureka服务上注册的应用程序组的名字 “”
instanceEnabledOnit  实例注册到eureka服务器时,是否开启通讯 false
nonSecurePort 获取该实例应该接收通信的非安全端口 80
securePort 获取该实例应该接收通信的安全端口 443
nonSecurePortEnabled 该实例应该接收通信的非安全端口是否启用 true
securePortEnabled 该实例应该接收通信的安全端口是否启用 false
leaseRenewalIntervalInSeconds 服务刷新时间配置,每隔这个时间会主动心跳一次,通知服务自己还存在。 30
leaseExpirationDurationInSeconds 服务过期时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除 90
virtualHostName  此实例定义的虚拟主机名,其他实例将通过使用虚拟主机名找到该实例。 unknown
instanceId 应用在注册中心中的唯一标识 “”
secureVirtualHostName 此实例定义的安全虚拟主机名 Unknown
aSGName 与此实例相关联 AWS自动缩放组名称。此项配置是在AWS环境专门使用的实例启动,它已被用于流量停用后自动把一个实例退出服务。 “”
metadataMap 获取与此实例相关联的元数据(key,value)。这个信息被发送到eureka服务器,其他实例可以使用。 new HashMap<>()
dataCenterInfo 返回数据中心这个实例被部署。这些信息被用来获取

 

如果实例被部署在AWS中,一些AWS特定的实例信息。

 

DataCenterInfo.Name.MyOwn
ipAddress 实例的ip地址, “”
statusPageUrlPath 获取此实例状态页的URL路径,然后构造出主机名,安全端口等 /info
statusPageUrl 获取此实例绝对状态页的URL路径,为其他服务提供信息时来找到这个实例的状态的路径 Null
homePageUrlPath 获取此实例的相关主页URL路径,然后构造出主机名,安全端口等 /
homePageUrl 获取此实例的绝对主页URL路径,为其他服务提供信息时使用的路径 “”
healthCheckUrlPath 获取此实例的相对健康检查URL路径 /health
healthCheckUrl 获取此实例的绝对健康检查URL路径 “”
secureHealthCheckUrl  获取此实例的绝对安全健康检查网页的URL路径 “”
namespace  获取用于查找属性的命名空间,默认为eureka Erureka
hostname 与此实例相关联的主机名,是其他实例可以用来进行请求的准确名称 “”
preferIpAddress Spring就会自动为我们获取第一个非回环IP地址,注册至服务。 false
initialStatus 注册至eureka的初始状态 up
defaultAddressResolutionOrder 获取实例的网络地址,默认为[] []
environment Eureka运行环境
org.springframework.core.env.Environment
null

 

相关文章:

  • 2021-08-09
  • 2021-07-30
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-05-03
猜你喜欢
  • 2021-11-04
  • 2021-09-11
  • 2021-07-22
  • 2021-10-11
相关资源
相似解决方案