SpringCloud基础

1. 微服务的基础知识

1.1 单体应用架构

Web应用程序发展的早期,大部分web工程(包含前端页面,web层代码,service层代码,dao层代码)是将所有的功能模块,打包到一起并放在一个web容器中运行。
在这里插入图片描述

  • 优点:
    所有的功能集成在一个项目工程中
    项目架构简单,前期开发成本低,周期短,小型项目的首选。
  • 缺点:
    全部功能集成在一个工程中,对于大型项目不易开发、扩展及维护。
    系统性能扩展只能通过扩展集群结点,成本高、有瓶颈。
    技术栈受限。

1.2 垂直应用架构

当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率
在这里插入图片描述

  • 优点:
    项目架构简单,前期开发成本低,周期短,小型项目的首选。
    通过垂直拆分,原来的单体项目不至于无限扩大
    不同的项目可采用不同的技术。
  • 缺点:
    全部功能集成在一个工程中,对于大型项目不易开发、扩展及维护。
    系统性能扩展只能通过扩展集群结点,成本高、有瓶颈。

1.3 分布式SOA架构

SOA 全称为 Service-Oriented Architecture,即面向服务的架构。它可以根据需求通过网络对松散耦合的粗粒度应用组件(服务)进行分布式部署、组合和使用。一个服务通常以独立的形式存在于操作系统进程中。
站在功能的角度,把业务逻辑抽象成可复用、可组装的服务,通过服务的编排实现业务的快速再生,目的:把原先固有的业务功能转变为通用的业务服务,实现业务逻辑的快速复用。
通过上面的描述可以发现 SOA 有如下几个特点:分布式、可重用、扩展灵活、松耦合
在这里插入图片描述

  • 优点:
    抽取公共的功能为服务,提高开发效率
    对不同的服务进行集群化部署解决系统压力
    基于ESB/DUBBO减少系统耦合
  • 缺点:
    抽取服务的粒度较大
    服务提供方与调用方接口耦合度较高

1.4 微服务架构

在这里插入图片描述

  • 优点:
    通过服务的原子化拆分,以及微服务的独立打包、部署和升级,小团队的交付周期将缩短,运维成本也将大幅度下降
    微服务遵循单一原则。微服务之间采用Restful等轻量协议传输。
  • 缺点:
    微服务过多,服务治理成本高,不利于系统维护。
    分布式系统开发的技术成本高(容错、分布式事务等)。

1.5 SOA与微服务的关系

  • SOA( Service Oriented Architecture )“面向服务的架构”:他是一种设计方法,其中包含多个服务, 服务之间通过相互依赖最终提供一系列的功能。一个服务 通常以独立的形式存在与操作系统进程中。各个服务之间 通过网络调用
  • 微服务架构:其实和 SOA 架构类似,微服务是在 SOA 上做的升华,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”,原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。这些小应用之间通过服务完成交互和集成。

在这里插入图片描述

1.6 分布式核心知识

1.6.1 分布式中的远程调用

在微服务架构中,通常存在多个服务之间的远程调用的需求。远程调用通常包含两个部分:序列化和通信协议。常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等,目前主流的远程调用技术有基于HTTP的RESTful接口以及基于TCP的RPC协议。

  • RESTful接口
    REST,即Representational State Transfer的缩写,如果一个架构符合REST原则,就称它为RESTful架构。
    资源(Resources)
    所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。REST的名称"表现层状态转化"中,省略了主语。“表现层"其实指的是"资源”(Resources)的"表现层"。
    表现层(Representation)
    “资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的”.html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。
    状态转化(State Transfer)
    访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源

总结restful服务

  1. 每一个URI代表一种资源;
  2. 客户端和服务器之间,传递这种资源的某种表现层;
  3. 客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

1.6.2 RPC协议

RPC(Remote Procedure Call ) 一种进程间通信方式。允许像调用本地服务一样调用远程服务。RPC框架的主要目标就是让远程服务调用更简单、透明。RPC框架负责屏蔽底层的传输方式(TCP或者UDP)、序列化方式(XML/JSON/二进制)和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程
在这里插入图片描述
区别和联系
在这里插入图片描述

1.6.3 分布式中的CAP原理

Consistency(一致性):数据一致更新,所有数据的变化都是同步的
Availability(可用性):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求
Partition tolerance(分区容忍性):某个节点的故障,并不影响整个系统的运行
我们得知任何分布式系统只可同时满足二点

在这里插入图片描述
需要明确一点的是,在一个分布式系统当中,分区容忍性和可用性是最基本的需求,所以在分布是系统中,我们的系统最当关注的就是A(可用性)P(容忍性),通过补偿的机制寻求数据的一致性

1.7 常见的微服务框架

SpringCloud、 ServiceComb ZeroC ICE

1.8 SpringBoot和SpringCloud的区别

  • SpringCloud,基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。
  • SpringCloud利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发,SpringCloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等,它们都可以用SpringBoot的开发风格做到一键启动和部署。
  • SpringBoot并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包
    =======================================================================================
  1. SpringBoot专注于快速方便的开发单个个体微服务。
  2. SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
  3. SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于依赖的关系.
  4. SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。

1.9 SpringCloud和Dubbo的区别

在这里插入图片描述

  • 最大区别:SpringCloud抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式。
    严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,

  • 品牌机与组装机的区别
    很明显,Spring Cloud的功能比DUBBO更加强大,涵盖面更广,而且作为Spring的拳头项目,它也能够与Spring Framework、Spring Boot、Spring Data、Spring Batch等其他Spring项目完美融合,这些对于微服务而言是至关重要的。使用Dubbo构建的微服务架构就像组装电脑,各环节我们的选择自由度很高,但是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心,但是如果你是一名高手,那这些都不是问题;而Spring Cloud就像品牌机,在Spring Source的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性,但是如果要在使用非原装组件外的东西,就需要对其基础有足够的了解。

  • 社区支持与更新力度
    最为重要的是,DUBBO停止了5年左右的更新,虽然2017.7重启了。对于技术发展的新需求,需要由开发者自行拓展升级(比如当当网弄出了DubboX),这对于很多想要采用微服务架构的中小软件组织,显然是不太合适的,中小公司没有这么强大的技术能力去修改Dubbo源码+周边的一整套解决方案,并不是每一个公司都有阿里的大牛+真实的线上生产环境测试过。
    在这里插入图片描述

2 微服务

什么是微服务?
微服务之间是如何独立通讯的?
springCloud和Dubbo有那些区别?
SpringBoot和SpringCloud,谈谈你的理解?
什么是服务熔断?什么是服务降级?
微服务的优缺点分别是?
你所知道的微服务技术栈有那些?
eureka和zookeeper都可以提供服务注册与发现的功能,请说说两个的区别?

  • 微服务架构是⼀种架构模式,它提倡将单⼀应⽤程序划分成⼀组⼩的服务,服务之间互相协调、互相配合,为⽤户提供最终价值。每个服务运⾏在其独⽴的进程中,服务与服务间采⽤轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进⾏构建,并且能够被独⽴的部署到⽣产环境、类⽣产环境等。另外,应当尽量避免统⼀的、集中式的服务管理机制,对具体的⼀个服务⽽⾔,应根据业务上下⽂,选择合适的语⾔、⼯具对其进⾏构建。
  • 简而言之,微服务架构风格是一种将单个应用程序作为一套小型服务开发的方法,每种应用程序都运行在自己的进程中,并与轻量级机制(通常是HTTP资源API)进行通信。这些服务是围绕业务功能构建的,可以通过全自动部署机制独立部署。这些服务的集中管理最少,可以用不同的编程语言编写,并使用不同的数据存储技术。
  • 微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地去耦合,每一个微服务提供单个业务功能的服务,一个服务做―件事,从技术角度看就是一种小而独立的处理过程,类似进程概念,能够自行单独启动或销毁,拥有自己独立的数据库。
  1. 每个服务足够内聚,足够小,代码容易理解这样能聚焦一个指定的业务功能或业务需求
  2. 开发简单、开发效率提高,一个服务可能就是专一的只干一件事。
  3. 微服务能够被小团队单独开发,这个小团队是2到5人的开发人员组成。
  4. 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。
  5. 微服务能使用不同的语言开发。
  6. 易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins, Hudson, bamboo 。
  7. 微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。
  8. 微服务允许你利用融合最新技术。
  9. 微服务只是业务逻辑的代码,不会和HTML,CSS或其他界面组件混合
  10. 每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库

2.1 微服务的概念

2.1.1 服务注册与发现

服务注册:服务实例将自身服务信息注册到注册中心。这部分服务信息包括服务所在主机IP和提供服务的Port,以及暴露服务自身状态以及访问协议等信息。
服务发现:服务实例请求注册中心获取所依赖服务信息。服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去请求它们提供的服务。
在这里插入图片描述

2.1.2 负载均衡

负载均衡是高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性。
在这里插入图片描述

2.1.3 熔断

熔断:在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断
在这里插入图片描述

2.1.4 链路追踪

随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要对一次请求涉及的多个服务链路进行日志记录,性能监控即链路追踪
在这里插入图片描述

2.1.5 API网关

随着微服务的不断增多,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信可能出现:

  • 客户端需要调用不同的url地址,增加难度
  • 再一定的场景下,存在跨域请求的问题
  • 每个微服务都需要进行单独的身份认证

针对这些问题,API网关顺势而生。
API网关直面意思是将所有API调用统一接入到API网关层,由网关层统一接入和输出。一个网关的基本功能有:统一接入、安全防护、协议适配、流量管控、长短链接支持、容错能力。有了网关之后,各个API服务提供团队可以专注于自己的的业务逻辑处理,而API网关更专注于安全、流量、路由等问题。
在这里插入图片描述

2.2 SpringCloud的介绍

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

2.2.1 SpringCloud中的核心组件

微服务条目落地技术备注
服务开发Springboot、Spring、SpringMVC
服务配置与管理Netflix公司的Archaius、阿里的Diamond等
服务注册与发现Eureka、Consul、Zookeeper等
服务调用Rest、RPC、gRPC
服务熔断器Hystrix、Envoy等
负载均衡Ribbon、Nginx等
服务接口调用(客户端调用服务的简化工具)Feign等
消息队列Kafka、RabbitMQ、ActiveMQ等
服务配置中心管理SpringCloudConfig、Chef等
服务路由(API网关)Zuul等
服务监控Zabbix、Nagios、Metrics、Spectator等
全链路追踪Zipkin,Brave、Dapper等
服务部署Docker、OpenStack、Kubernetes等
数据流操作开发包SpringCloud Stream(封装与Redis,Rabbit、Kafka等发送接收消息)
事件消息总线Spring Cloud Bus

2.2.2 SpringCloud的体系结构

在这里插入图片描述
从上图可以看出Spring Cloud各个组件相互配合,合作支持了一套完整的微服务架构。

  • 注册中心负责服务的注册与发现,很好将各服务连接起来
    断路器负责监控服务之间的调用情况,连续多次失败进行熔断保护。
  • API网关负责转发所有对外的请求和服务
  • 配置中心提供了统一的配置信息管理服务,可以实时的通知各个服务获取最新的配置信息
  • 链路追踪技术可以将所有的请求数据记录下来,方便我们进行后续分析
  • 各个组件又提供了功能完善的dashboard监控平台,可以方便的监控各组件的运行状况

2.3 服务调用

2.3.1 RestTemplate介绍

Spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式。
在Spring应用程序中访问第三方REST服务与使用Spring RestTemplate类有关。RestTemplate类的设计原则与许多其他Spring 模板类(例如JdbcTemplate、JmsTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法。RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如 Apache HttpComponents、Netty或OkHttp等其它HTTP library。
考虑到RestTemplate类是为调用REST服务而设计的,因此它的主要方法与REST的基础紧密相连就不足为奇了,后者是HTTP协议的方法:HEAD、GET、POST、PUT、DELETE和OPTIONS。例如,RestTemplate类具有headForHeaders()、getForObject()、postForObject()、put()和delete()等方法。

2.3.2 RestTemplate方法介绍

在这里插入图片描述

2.3.3 通过RestTemplate调用微服务

(1) 在 shop_service_order工程中ProductApplication启动类 中配置RestTemplate

 //配置RestTemplate交给spring管理
 @Bean
 public RestTemplate getRestTemplate() {
 return new RestTemplate();
 }

(2) 编写下订单方法

 @PostMapping("/{id}")
 public String order(Integer num) {
 //通过restTemplate调用商品微服务
 Product object =
restTemplate.getForObject("http://127.0.0.1:9002/product/1", Product.class);
 System.out.println(object);
 return "操作成功";
 }

2.3.4 硬编码存在的问题

至此已经可以通过RestTemplate调用商品微服务的RESTFul API接口。但是我们把提供者的网络地址
(ip,端口)等硬编码到了代码中,这种做法存在许多问题:

  • 应用场景有局限
  • 无法动态调整

2.4 Eureka服务

Eureka

2.5 Ribbon 客户端 负载均衡

Ribbon

2.6 Feign组件

feign

2.7 总结

2.7.1 注册中心

(1)Eureka

  • 搭建注册中心
    引入依赖spring-cloud-starter-netflix-eureka-server
    配置EurekaServer
    通过@EnableEurekaserver激活Eureka Server端配置
  • 服务注册
    服务提供者引入spring-cloud-starter-netf1ix-eureka-client依赖。
    通过eureka.client.serviceur1.defau1tzone配置注册中心地址

(2) consul

  • 搭建注册中心
    下载安装consul
    启动consul consu1 agent -dev服务注册
  • 服务注册
    服务提供者引入spring-cloud-starter-consul-discovery依赖
    通过spring.cloud.consu1.host和spring.cloud.consul.port 指定Consul Server的请求地址

2.7.2 服务调用

(1)Ribbon

  • 通过Ribbon结合RestTemplate方式进行服务调用只需要在声明RestTemplate的方法上添加注解@LoadBalanced即可
  • 可以通过{服务名称}.ribbon . NFLoadBalancerRuleclassName

(2)Feign

  • 服务消费者引入 spring-cloud-starter-openfeign依赖
  • 通过@Feignc1ient声明一个调用远程微服务接口
  • 启动类上通过@EnableFeignclients激活Feign

3. 微服务中高并发问题

3.1 请求解压问题

在这里插入图片描述
tomcat会以线程池的形式对所有的请求进行统一的管理,对于某个方法可能存在的耗时问题的时候,随着外面挤压的请求越来越多,势必会造成系统的崩溃。
为了不影响其他接口的正常访问,对多个服务之间进行隔离

解决的方法

  1. 线程池隔离
  2. 信号隔离: 即类似于一个计数器 当访问的数量到达计数器的值,其他访问者直接不能进行访问。

3.1.1 线程池隔离

(1) 配置坐标
为了方便实现线以线程池的形式完成资源隔离,需要引入如下依赖

   <!--hystrix-->
       <dependency>
           <groupId>com.netflix.hystrix</groupId>
           <artifactId>hystrix-metrics-event-stream</artifactId>
           <version>1.5.12</version>
       </dependency>
       <dependency>
           <groupId>com.netflix.hystrix</groupId>
           <artifactId>hystrix-javanica</artifactId>
           <version>1.5.12</version>
       </dependency>

(2) 配置线程池
配置HystrixCommand接口的实现类,再实现类中可以对线程池进行配置


import cn.itcast.order.entity.Product;
import com.netflix.hystrix.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;

public class OrderCommand extends HystrixCommand<Product> {

	private RestTemplate restTemplate;
	
	private Long id;

	public OrderCommand(RestTemplate restTemplate, Long id) {
		super(setter());
		this.restTemplate = restTemplate;
		this.id = id;
	}

	private static Setter setter() {

		// 服务分组
		HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("order_product");
		// 服务标识
		HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("product");
		// 线程池名称
		HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("order_product_pool");
		/**
		 * 线程池配置
		 *     withCoreSize :  线程池大小为10
		 *     withKeepAliveTimeMinutes:  线程存活时间15秒
		 *     withQueueSizeRejectionThreshold  :队列等待的阈值为100,超过100执行拒绝策略
		 */
		HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter().withCoreSize(50)
				.withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100);

		// 命令属性配置Hystrix 开启超时
		HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
				// 采用线程池方式实现服务隔离
				.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
				// 禁止
				.withExecutionTimeoutEnabled(false);
		return Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey)
				.andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties);

	}

	@Override
	protected Product run() throws Exception {
		System.out.println(Thread.currentThread().getName());
		return restTemplate.getForObject("http://127.0.0.1/product/"+id, Product.class);
	}

	/**
	 * 降级方法
	 */
	@Override
	protected Product getFallback(){
		Product product = new Product();
		product.setProductName("不好意思,出错了");
		return product;
	}
}

(3) 配置调用
修改 OrderController ,使用自定义的OrderCommand完成调用

	@Autowired
	private RestTemplate restTemplate;


	/**
	 * 使用OrderCommand调用远程服务
	 */
	@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable Long id) {
		return new OrderCommand(restTemplate,id).execute();
	}

3.1.2 Jmetter 性能工具

https://blog.youkuaiyun.com/qq_39759664/article/details/122135667

3.1.3 Hystrix基础 :服务熔断

https://blog.youkuaiyun.com/qq_39759664/article/details/122148202

3.1.4 sentinel基础:服务熔断

https://blog.youkuaiyun.com/qq_39759664/article/details/122191242

3.1.5 微服务网关

https://blog.youkuaiyun.com/qq_39759664/article/details/122223306

3.1.6 链路追踪

https://blog.youkuaiyun.com/qq_39759664/article/details/122345491

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值