当前位置: 首页 > news >正文

Spring Cloud 所有组件全面总结

背景- 从单体架构到微服务

在传统的单体应用架构中,所有功能都部署在一个工程里:1. 结构简单, 2. 部署容易,3.早期开发快速 。 

但随着系统变大,出现了很多问题: 1.模块耦合严重,难以拆分协作, 2. 编译、测试时间越来越长, 3. 一处出错,全系统受影响, 4. 技术选型无法灵活切换(前后端、数据库、缓存等)

于是,微服务架构出现了。

Spring Cloud 的诞生,是为了应对微服务架构下复杂系统治理的挑战。它以模块化的方式提供了服务注册与发现、配置中心、服务调用、网关路由、熔断限流、安全认证等一整套基础能力,帮助开发者专注业务、屏蔽底层复杂性,成为构建云原生应用的核心利器。

Spring Cloud 各模块及作用一览表

功能模块代表组件主要用途
服务注册与发现Eureka / Consul / Zookeeper服务自动注册与动态发现,替代硬编码地址
客户端负载均衡Spring Cloud LoadBalancer / Ribbon(已弃用)多实例服务调用时自动选择一个合适实例(如轮询、权重等)
服务网关Spring Cloud Gateway统一入口,路由转发,鉴权,限流,熔断等
配置管理中心Spring Cloud Config集中管理配置,可动态刷新,支持 Git、Bus 等
熔断与容错Resilience4j / Hystrix(已弃用)降级、熔断、超时控制、重试等,提高系统稳定性
分布式链路追踪Sleuth + Zipkin / OpenTelemetry记录请求的全链路信息,方便定位问题与性能分析
消息总线Spring Cloud Bus配合 Config 实现配置自动刷新,也可用于服务间事件广播
声明式服务通信OpenFeign使用注解方式声明 REST 接口,封装调用逻辑,内置负载均衡
服务安全(认证授权)Spring Cloud Security / OAuth2微服务之间身份校验与权限控制,保护 API 接口安全
分布式任务调度(可选)Spring Cloud Data Flow / Task用于处理数据流、ETL、批处理任务等场景

1. 服务注册与发现 -Eureka / Consul / Zookeeper

什么是服务注册与发现?

在微服务架构中,服务实例通常是动态伸缩的(例如 Docker 容器或 Kubernetes Pod),IP 和端口也可能频繁变动。

因此,我们不能硬编码服务地址,而应该通过“注册中心”完成:

  • 服务注册(Register): 服务启动时,将自身信息注册到注册中心。

  • 服务发现(Discovery): 消费方从注册中心查询目标服务的实例列表,实现动态调用和负载均衡。

常见服务注册中心对比

特性EurekaConsulZookeeper
开源项目NetflixHashiCorpApache
协议自定义 HTTP 协议HTTP + gRPC + DNSZAB 协议
CAP 理论AP(可用性优先)CP(强一致性)CP
健康检查客户端上报支持 HTTP/TCP 检查不原生支持
易用性✅ 极简,易集成✅ 支持多协议,UI 强❌ 配置复杂,不推荐用于注册中心
Spring Cloud 支持✅ 原生集成✅ Spring Cloud Consul⚠️ 需额外适配
适用场景内部微服务系统,容忍短暂不一致金融、电商等一致性要求高场景分布式协调系统更适合(如 Kafka、HBase)

Eureka 注册与发现流程:文字版时序图

参与者:
[服务提供者] Service A (Eureka Client)
[服务注册中心] Eureka Server
[服务消费者] Service B (Eureka Client)

第一步:服务注册(Service A → Eureka Server)

Service A(服务提供方)启动↓
向 Eureka Server 发送注册请求(Register)↓
Eureka Server 将 Service A 注册信息保存到注册表中↓
Eureka Server 响应注册成功(200 OK)

第二步:服务续约(Service A → Eureka Server)

Service A 定时发送心跳(默认每 30 秒一次)↓
Eureka Server 更新 Service A 的 lastBeat 时间戳↓
保持 Service A 的注册状态为 “UP”

第三步:服务发现(Service B → Eureka Server)

Service B(服务调用方)启动↓
向 Eureka Server 请求拉取注册表副本(registry)↓
Eureka Server 返回所有注册服务实例信息↓
Service B 本地缓存注册表副本

 第四步:服务调用(Service B → Service A)

Service B 查询本地缓存,查找 Service A 实例↓
负载均衡(Ribbon)选出一个 Service A 实例↓
Service B 发起 HTTP 请求调用 Service A

第五步:服务下线(Service A → Eureka Server)

Service A 正常关闭(或异常终止)↓
向 Eureka Server 发送注销请求(Cancel)↓
Eureka Server 将其从注册表中移除

若 Service A 崩溃未发送下线通知:

  • Eureka Server 等待续约超时(默认 90 秒)

  • 自动剔除该实例(Eviction)


第六步(可选):Eureka Server 集群同步

Eureka Server A 发生注册表变更↓
向其他 Eureka Server 节点发送同步请求(Peer Replication)↓
各节点保持注册表一致性

服务注册与发现是微服务架构的基础设施,它屏蔽了服务地址变化的复杂性。Eureka 更适合 Spring Cloud 生态,Consul 提供了更强的功能和一致性保障,而 Zookeeper 更适合做协调工具。选择哪一个注册中心,应结合项目需求的一致性、可用性和技术生态综合考虑。

2. 客户端负载均衡 -Spring Cloud LoadBalancer / Ribbon(已弃用)

在微服务架构中,一个服务往往有多个实例。服务消费者(如 OrderService)调用服务提供者(如 ProductService)时,需要从多个实例中选择一个进行调用。

客户端负载均衡(Client-Side Load Balancing) 的特点是:

  • 实例选择逻辑在客户端完成

  • 客户端维护服务实例列表(通常从注册中心获取)

  • 可以自定义负载均衡策略(如轮询、随机等)

服务调用方 → 使用服务名发起请求(如 http://product-service/products)↓
Spring Cloud LoadBalancer 拦截请求,向注册中心获取可用实例列表↓
应用内选择一个实例(轮询、随机、权重等)↓
构造真实的 URL(如 http://192.168.1.2:8081/products)并发起请求

3. 服务网关 -Spring Cloud Gateway

spring-cloud-gateway vs spring-cloud-gateway-mvc

spring-cloud-gateway 基于 WebFlux 和 Netty,适合构建高并发、轻量级网关服务。而 spring-cloud-gateway-mvc 提供了面向传统 Servlet 模型的网关方案,便于在已有 Spring MVC 应用中集成网关能力。根据项目技术栈和部署需求灵活选择,可以实现最优的网关架构设计。

技术架构对比

项目Spring Cloud GatewaySpring Cloud Gateway MVC
底层技术Reactor + Netty + WebFluxServlet + Spring MVC
编程模型响应式,非阻塞传统阻塞式
默认容器NettyTomcat / Jetty
性能特点高并发、高吞吐(适合网关)兼容性强、适合传统项目
启动依赖spring-boot-starter-webfluxspring-boot-starter-web

架构原理

Spring Cloud Gateway 的核心架构基于三个关键组件:

  1. Route(路由规则)

    • 定义请求匹配条件(路径、Host、Header、Query 等)

    • 绑定目标服务地址(如 lb://user-service

  2. Predicate(断言)

    • 用于匹配请求的条件(如 Path、Method、Header 等)

    • 类似 Spring MVC 的请求匹配器

  3. Filter(过滤器)

    • 可在路由前/后执行逻辑(如限流、认证、修改请求等)

    • 内置 + 自定义,功能强大

工作流程(简化)

客户端请求 → Gateway 网关↓
匹配 Route 规则 → 判断 Predicate 条件是否满足↓
执行 Filter(全局或局部)→ 请求转发到后端服务↓
接收响应 → 执行后置 Filter → 返回结果给客户端

4. 配置管理中心 - Spring Cloud Config

Spring Cloud Config 是 Spring Cloud 提供的 集中式配置管理解决方案,支持为分布式系统中的所有服务提供统一的配置服务

它解决了:

  • 多环境多服务配置难以维护

  • 各服务配置冗余、易出错

  • 动态刷新配置需求

工作流程(基于  Kafka Bus + Database 场景)

描述的是:Spring Cloud Config + Spring Cloud Bus(Kafka)+ 配置数据存储在数据库 的整合使用场景。

1️⃣ 启动加载流程

  1. 各服务作为 Config Client 启动时,通过 bootstrap or application.yml 配置连接到 Config Server;

  2. Config Server 从配置源(此处为数据库)加载指定应用、环境的配置;

  3. Config Client 加载配置并注入 Spring 容器;

  4. 所有服务完成启动,使用统一配置。

2️⃣ 配置修改流程(运维或开发手动修改 DB 中配置):

  1. 配置管理员在数据库中修改某个服务的配置信息;

  2. 通过管理后台或命令调用 POST /actuator/bus-refresh

  3. Spring Cloud Config Server 发送 Kafka 消息到指定 topic;

  4. 所有监听该 topic 的 Config Client 收到刷新指令;

  5. 各服务使用 @RefreshScope 注解的 Bean 会重新加载最新配置。

✅ 特别说明:

  • 数据库做配置源:需扩展 Config Server 的 EnvironmentRepository 接口,自定义从数据库读取配置。

  • Spring Cloud Bus:用 Kafka 或 RabbitMQ 广播刷新事件,支持集群场景动态刷新。

  • 无需重启服务即可生效,依赖 Spring 的 @RefreshScope 和 Actuator。

5. 熔断与容错 - Resilience4j / Hystrix

什么是熔断与容错?

熔断和容错是微服务架构中的服务稳定性保障机制,用于防止服务雪崩。

名称说明
容错(Fallback)当下游服务出错或超时时,返回默认值或执行备用逻辑
熔断(Circuit Breaker)当连续失败率超过阈值时,短路下游调用,保护系统
限流(Rate Limiter)控制请求频率,防止资源过载
重试(Retry)出错时,自动重试调用(可设置次数/间隔)
舱壁(Bulkhead)隔离不同服务或线程池,防止级联故障

关键工作流程图(文字时序图)

以下以 Circuit Breaker + Retry + Fallback 组合为例,描述其工作时序:

[Client Service]|| -- 发起请求 --> [Protected Service(带熔断)]|                         ||                  ① CircuitBreaker 检查当前状态|                         ||            ┌────────────┴────────────┐|            ↓                         ↓|        Closed(默认)           Open(熔断中)|            |                         ||        ② 执行请求           ⑤ 拦截请求并快速失败|            |                         ||      ┌─────┴─────┐              ⑥ 走 fallback 方法|      ↓           ↓|   成功         异常/超时|      |           ||      |      ③ Retry 判断是否重试|      |           ↓|      |      重试成功 or 失败|      |           ↓|      └────→ ④ 更新失败统计|                        ||              连续失败超阈值|                        ↓|               熔断器切换为 Open 状态||<----- 最终返回结果(成功 / fallback / 异常)

熔断器状态流转简要说明

[Closed] ——(连续失败)——> [Open]
[Open] ——(过渡时间后尝试一次请求)——> [Half-Open]
[Half-Open] ——(成功)——> [Closed]
[Half-Open] ——(失败)——> [Open]

在微服务架构中,系统稳定性至关重要。Resilience4j 提供了包括熔断、重试、限流、超时、隔离在内的一整套容错机制,帮助开发者优雅地应对下游故障和异常场景。相较于 Hystrix,Resilience4j 更加轻量、模块化、易于集成,是构建高可用系统的首选工具。

6. 分布式链路追踪 - Sleuth + Zipkin / OpenTelemetry

为什么需要分布式链路追踪?

在微服务架构中,一个请求通常会经过多个服务模块:

  • 请求链路变长、依赖关系变复杂

  • 出现性能瓶颈或异常时,难以定位是哪一层的问题

  • 日志分散,各服务无法自动关联上下文

分布式链路追踪 就是为了解决这个问题,让你清楚看到一次请求跨越多个服务的完整调用路径、耗时和异常点。

核心术语

术语说明
Trace(跟踪)一次完整请求的全路径(跨服务)
Span(跨度)一个服务中的一次操作或调用
Trace ID整个调用链的唯一标识
Span ID当前服务中操作的唯一标识
Parent ID当前 Span 的上级 Span
采样率(Sampling)控制是否记录 Trace,用于控制系统开销

核心组件

☁️ 1. Spring Cloud Sleuth

  • 是 Spring Cloud 的链路追踪框架,自动为请求打上 TraceId / SpanId

  • 支持同步/异步线程、消息队列、WebClient 等场景

  • 默认集成 Zipkin,也支持 OpenTelemetry

🧭 2. Zipkin(可选)

  • 可视化链路追踪工具,用于收集、存储和展示 Trace 数据

  • 支持 HTTP、Kafka、RabbitMQ 作为传输方式

  • 可通过浏览器查看请求链路图、耗时分析等

📡 3. OpenTelemetry(现代推荐)

  • CNCF 推出的统一观测标准,融合了 OpenTracing + OpenCensus

  • 提供 Trace、Metrics、Logs 一体化支持

  • 更加灵活、跨语言、跨平台,适合云原生体系

请求链路追踪流程(文字时序图)

用户请求 --> [Gateway 服务]|① Sleuth 生成 TraceId、SpanId|↓[Service A - 用户服务]|② 创建子 Span,记录处理时间|↓[Service B - 订单服务]|③ 继续传播 TraceId / SpanId|↓[Service C - 支付服务]|④ 创建子 Span,记录执行耗时|↓返回响应 ←──── ⑤ 所有日志带有相同 TraceId

每个服务中的日志都包含如下信息:

[TraceId=abc123] [SpanId=xyz456] 用户请求 /order/create 成功

这些 Trace 数据最终发送到:

  • Zipkin Server:进行集中展示分析

  • OpenTelemetry Collector → 导入 Grafana、Jaeger 等可观测平台

分布式链路追踪是微服务体系的眼睛,能够清晰洞察请求在系统中的全生命周期。Sleuth + Zipkin 提供了简单、开箱即用的解决方案,而 OpenTelemetry 则是面向未来的通用观测标准。根据团队技术栈选择适合的工具,是构建高可观测性系统的关键一步。

7. 消息总线.- Spring Cloud Bus

Spring Cloud Bus 是 Spring Cloud 提供的一个轻量级消息通信总线,通过集成消息中间件(如 Kafka、RabbitMQ),让分布式系统中的多个微服务可以广播事件、共享状态变化、自动刷新配置

它的设计目标是:
“用消息中间件连接微服务,实现事件驱动的系统间通信与协调。”

场景描述
配置中心刷新配合 Spring Cloud Config 使用,实现配置变更自动推送到所有服务
广播消息事件通过自定义事件,在多个服务之间同步状态
服务间通讯某些场景下替代 HTTP,使用事件通信解耦服务

流程(文字时序图):

[配置管理员]|① 修改 Git / 数据库配置|② 调用 POST /actuator/bus-refresh↓
[Config Server]|③ 发布刷新事件(RefreshRemoteApplicationEvent)↓
[Kafka / RabbitMQ]|④ 广播消息到所有订阅服务↓
[Client Service A / B / C...]|⑤ 接收到事件,触发 ContextRefresher,重新加载配置

特点:

  • 使用 Spring ApplicationEvent 作为消息载体

  • 自动监听 RefreshRemoteApplicationEvent

  • 不依赖服务发现,使用消息系统作为通信媒介

  • 可通过 destination 定向刷新指定服务实例

定向刷新 vs 全量刷新

  • 默认 /actuator/bus-refresh 会广播到所有实例

  • 若只刷新某个服务,可使用:

POST /actuator/bus-refresh/{destination}
# destination 格式:applicationName:serverId

例如

POST /actuator/bus-refresh/order-service:8081

Spring Cloud Bus 是微服务架构中连接各个模块的“神经网络”。它通过整合 Kafka/RabbitMQ 等消息中间件,实现了配置热刷新、状态同步、事件广播等关键功能,是提升系统动态化与自动化治理的重要工具。结合 Spring Cloud Config 等组件,构建出真正灵活、高效、解耦的微服务体系。

8. 声明式服务通信 - OpenFeign

OpenFeign 是一个基于 Netflix Feign 开发的 HTTP 客户端,它在 Spring Cloud 中进行了深度集成,实现了声明式调用远程服务的能力。

它让你调用远程 HTTP 服务就像调用本地接口一样简单,无需写 RestTemplate 或 WebClient 的实现逻辑。

OpenFeign 的核心优势

优势描述
声明式调用使用 Java 接口 + 注解方式,开发简洁优雅
Ribbon / LoadBalancer 集成内置客户端负载均衡
支持熔断/重试/日志与 Resilience4j、Hystrix 无缝整合
支持请求压缩/拦截器可配置 GZIP、添加 Token、Header 等
与 Spring Cloud 紧密结合可直接读取配置中心、注册中心信息

OpenFeign 的工作原理(文字时序图)

[User Service]|
① 注入 FeignClient 接口|
② 调用接口方法(如 orderClient.getOrder(1))|
③ OpenFeign 生成动态代理对象|
④ 代理内部通过 HTTP 请求调用远程服务|
⑤ 集成 LoadBalancer,获取目标实例(如 order-service)|
⑥ 发送 HTTP 请求(RestTemplate/WebClient)|
⑦ 获取响应,转换为方法返回值|
[返回结果给调用方]

与 RestTemplate 的对比

特性RestTemplateOpenFeign
编码风格命令式,手动构造 URL、参数声明式,接口 + 注解
可读性
可维护性改动影响大修改方便
负载均衡需手动配置 LoadBalancerClient内置负载均衡
熔断、重试支持需额外配置原生支持(可与 Resilience4j 配合)

OpenFeign 提供了一种更优雅的方式来进行服务间通信,使得开发者能够以声明式的方式编写远程调用逻辑,从而减少样板代码,提高可读性和可维护性。作为 Spring Cloud 微服务体系中不可或缺的一环,OpenFeign 与服务注册中心、配置中心、熔断机制无缝协作,是构建健壮、高效服务调用的首选利器。

9. 服务安全(认证授权)- Oauth2

OAuth2 是一种开放的授权协议,允许第三方应用代表用户访问受保护资源,而不暴露用户密码。

它的本质是“授权 + 令牌访问资源”。

OAuth2 四种授权模式(授权方式)

模式适用场景是否推荐特点
授权码模式(Authorization Code)后端 + 前端分离系统✅ 推荐安全性最高(支持 refresh_token)
客户端模式(Client Credentials)后台服务对服务通信✅ 推荐无用户参与,仅代表服务身份
密码模式(Resource Owner Password)自家 App❌ 不推荐用户将密码交给客户端,已废弃
简化模式(Implicit)前端单页应用(SPA)❌ 不推荐不返回 refresh_token,易被截获,已废弃

Spring Cloud OAuth2 模块划分

在 Spring Security 5+ 中,OAuth2 分为三大核心模块:

模块用途
spring-security-oauth2-client客户端发起授权客户端 Web 应用
spring-security-oauth2-resource-server验证 token,保护资源资源服务器
spring-authorization-server(独立)授权服务器自建 OAuth2 Server

access_token 与 refresh_token 区别

类型用途有效期存放位置
access_token调用资源接口的凭证短期每个请求 Header 中
refresh_token用于重新获取 access_token长期仅客户端持有,不能泄露

OIDC 与 OAuth2 的区别

特性OAuth2OpenID Connect (OIDC)
类型授权框架身份认证层(基于 OAuth2)
是否识别用户身份❌ 否✅ 是(包含 id_token)
是否返回用户信息❌ 否✅ 是(UserInfo Endpoint)
id_token❌ 无✅ 有(JWT 格式,内含用户信息)

Authorization Code 授权码模式(推荐,最常用)

[User] → 访问客户端资源,触发授权流程
↓
[Client] → 重定向用户到 [Authorization Server] 的授权页面
↓
[User] → 登录并授权
↓
[Authorization Server] → 带 code 重定向回客户端的 redirect_uri
↓
[Client] → 使用 code + client_secret 向授权服务器换取 access_token
↓
[Authorization Server] → 返回 access_token(+ optionally refresh_token)
↓
[Client] → 使用 token 访问 [Resource Server]

Client Credentials 客户端模式(服务对服务通信)

[Client] → 使用 client_id + client_secret 请求 [Authorization Server]
↓
[Authorization Server] → 返回 access_token
↓
[Client] → 使用 token 访问 [Resource Server]

分布式任务调度(可选)-Spring Cloud Data Flow / Task

在微服务架构中,除了处理持续运行的服务,还经常需要处理:

  • 批量数据处理(如订单结算、日志归档)

  • 定时任务(每天、每小时触发)

  • 数据管道(数据流转、ETL)

  • 工作流编排(任务间存在依赖关系)

这些任务对资源调度、状态管理、失败恢复、监控运维提出了更高要求。
Spring Cloud 提供了两种应对方案:

  • Spring Cloud Task:轻量级、短生命周期任务的开发框架

  • Spring Cloud Data Flow (SCDF):面向任务和流的完整分布式调度平台

Spring Cloud Task:适用于一次性/批处理任务

适用场景:

  • 一次性执行的批处理任务(导入数据、备份)

  • 简单的数据处理工作流程

  • 与 Spring Batch 无缝集成

核心特性:

特性描述
生命周期管理自动记录任务启动、结束、失败状态
与 Spring Boot 一致开箱即用,兼容 Spring Batch
元数据管理支持持久化任务执行记录到数据库
与 SCDF 集成可作为 SCDF 任务运行时组件

工作流程(文字流程图):

开发者启动任务↓
Spring Cloud Task 初始化任务上下文↓
任务执行(如数据导入)↓
自动记录状态(成功/失败)↓
任务终止(非持续运行)

Spring Cloud Data Flow:任务调度 + 数据流管道

✅ 适用场景:

  • 数据流管道(如 Kafka → 处理 → 存储)

  • 复杂工作流编排(多个任务依赖关系)

  • 多租户、可视化监控调度平台

  • 动态启动、取消任务(REST / UI)

架构组件:

组件作用
SCDF Server中央控制器,负责任务部署、监控
Skipper管理任务版本、回滚(可选)
Task Launcher启动任务的运行时平台(K8s、Cloud Foundry、local)
Metrics/Monitoring对接 Prometheus、Grafana

SCDF 工作流程(文字时序图)

[用户提交任务定义(DSL / UI / REST)]↓
[SCDF Server]|├── 解析任务定义├── 选择 Task Launcher 平台(如 Kubernetes)↓
[启动 Task 实例]↓
[任务执行:运行 Spring Boot Jar]↓
[上报执行状态、日志、指标]↓
[SCDF Dashboard 展示状态 / 成功 / 失败]

Task vs Data Flow 对比

特性Spring Cloud TaskSpring Cloud Data Flow
使用复杂度简单中等,需平台支持
是否支持持久任务记录✅(通过 Task)
可视化支持✅ Dashboard 管理界面
动态部署/调度✅(REST / Shell / UI)
多任务编排✅ 支持流任务依赖
运行平台支持本地、容器Kubernetes、Cloud Foundry、Local 等

注意事项

问题建议
任务运行失败配置持久化数据源,方便追踪失败信息
容器环境调度使用 Kubernetes 作为 Task Launcher
任务并发冲突配合数据库乐观锁或调度中心处理
SCDF 部署复杂建议使用官方 Docker Compose 或 Helm Chart

总结

Spring Cloud Task 提供了快速开发、运行、追踪一次性任务的能力,而 Spring Cloud Data Flow 则是面向企业级任务调度和数据管道编排的全平台解决方案。二者互补,为微服务体系中的数据处理、定时作业和任务流提供了完整的生命周期支持。根据任务复杂度选择合适方案,可以极大提升系统的可维护性与自动化程度。

相关文章:

  • 传统数据仓库正在被 Agentic AI 吞噬
  • 快速取模指数算法:密码学的核心引擎
  • 正整数的正向分解
  • Git里面Stash Changes和UnStash Changes使用
  • ​​WSL2 (Ubuntu)​​ 中安装 ​​CUDA 12.9​​ 的详细教程
  • Spring Boot Web开发
  • ansible变量
  • springboot项目启动报错:spring boot application in default package
  • ansible模块使用实践
  • 如何在现有的分科、分纲、分目、分类的知识体系下构建根茎式心智
  • 关于springMVC 项目 println 输出中文乱码问题,解决方法
  • java 设计模式_行为型_18解释器模式
  • Spring AI 对话记忆持久化实战-MySQL方案
  • vscode-monitor-pro | 提升开发效率的利器
  • leetcode23-合并K个升序链表
  • Day01_刷题niuke20250615
  • 【Flutter】解决小米澎湃系统迷你窗口、缩小窗口后界面空白问题
  • linux 常用工具的静态编译之二
  • 算法导论第七章:快速排序的艺术与科学
  • 【git】如何在team里使用公共账号进行ssh clone
  • 漳州网站建设公司首选公司/广东疫情最新消息今天又封了
  • 南京怎样做网站/网站排名监控工具
  • 东莞网页制作报价/重庆网站关键词排名优化
  • 2345网址导航手机版下载/windows7优化大师
  • 做网站就/app拉新推广赚佣金
  • 用博客网站做淘宝客/北京seo顾问