下一篇:Ribbon
简单介绍下SpringCloud,SpringCloud是基于SpringBoot的微服务全套解决方案,可保证高并发,高可用。何为微服务???从前我们没有高并发的时代,基本都用的是单体服务,也就是整个系统都编写在一个项目package下,但是随着现在互联网普及,用户量越来越大,如果还一个系统都只编写在一个项目包下,那么启动起来要花多少时间,而且万一崩了,整个项目就崩了,所以出现了微服务架构,将每个功能分别写成一个模块,比如支付模块,搜索模块,订单模块等等,每个模块部署在不同的服务器上,这样的话,启动也比较高效,响应也快,重要的是,就算一个服务器的模块崩了,其他模块并不会受影响,不同团队程序员负责自己模块即可。
Eureka叫服务注册与发现,是SpringCloud下的一个组件,目的是让微服务架构的不同模块间的功能可以相互调用,只要通过Eureka中间桥梁,在其中注册,就可以用到其他模块提供的接口,Eureka的模型图如下
比如用户模块是Service Consumer(消费者),支付模块是Service Provider(生产者),那么不同模块怎么通信呢?就通过Eureka Server这个桥梁,如果用户需要对商品进行支付,那么支付模块和用户模块都会在Eureka Server中注册(也可以直接理解成就在Eureka中注册),相当于它们就产生关系了,然后Service Consumer就可以拿到支付模块的内容了(实际是调用支付模块提供的接口),这样就通过这个Server中间桥梁间接执行了支付模块中的支付,表面上用户是感觉不到的,就像一个黑盒,用户不管执行原理,只要支付成功就行。后面实战例子会让你有所体会。
注意:除了Eureka Server之外都是Client,只不过Client中分生产者和消费者,服务A调用另一个服务B,则服务A就是Consumer,服务B就是Provider,因为服务B为服务A提供了某个方法供它调用
首先你要创建一个SpringBoot项目,也就是Spring Initializr,如果你跟我一样第一个Default的选项一直无法初始化,你就跟我一样用阿里云的创建,一直next,什么都不用√
然后将不要的都删除只剩最基本的
将maven配成自己的,不配就会用默认的,会保存在C盘的一个目录,可能下载依赖会非常慢
第一步:导入父工程pom依赖,这里用目前最新的Hoxton.SR12,配合与其兼容的2.3.12.RELEASE版本
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.yxgroupId>
<artifactId>springcloud1artifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springcloud1name>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>2.3.12.RELEASEspring-boot.version>
<spring.cloud-version>Hoxton.SR12spring.cloud-version>
properties>
<packaging>pompackaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring.cloud-version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
project>
第二步:创建一个eureka_server01模块,new moudle,选择maven创建,然后向其导入依赖,这个模块是Eureka Server
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
第三步:在resources下配置application.yml文件
server:
port: 8761 #EurekaServer服务端口
eureka:
instance:
hostname: localhost #主机名
client: #这两个false是防止自己去尝试连接主机(EurekaServer),因为自己就是主机,单机版,就是只有一个Eureka时都写false
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 配置服务名
spring:
application:
name: Eureka
第四步:在java包下配置EurekaServerApplication启动类,@EnableEurekaServer很关键,是开启EurekaServer
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class,args);
}
}
最后运行EurekaServerApplication ,启动成功后在浏览器输入localhost:8761
,然后就会运行出下面效果,这个就是可视化Eureka,可以看到哪些服务注册到了Eureka中。
这部分的目录结构如下
多个Client,一个作为Consumer,一个作为Provider,我们就拿用户要支付为例子,用户是一个Client(Consumer),支付也是一个Client(Provider),然后它们之间通信,也就是用户通过Server调用支付功能
新建一个module,选择maven创建,我将其命名为eureka_client_customer
,同样经过几步,配pom.xml,配application.yml,写启动类,然后启动
第一步:pom.xml,新增下面依赖,注意这里就变成spring-cloud-starter-netflix-eureka-client
,创建Client当然导入client相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
第二步:resources下配application.yml,这里就表示这个client向http://localhost:8761/eureka/
中注册,服务命名为client_customer
,这里没有配端口,就会默认用8080端口
# 指定往哪个EurekaServer服务中注册
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
# 指定服务名称,为了区分创建的服务
spring:
application:
name: client_customer
第三步:写启动类ClientCustomerApplication ,@EnableEurekaClient开启EurekaClient,让它去配置文件application.yml中指定Eureka Server里注册
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ClientCustomerApplication {
public static void main(String[] args) {
SpringApplication.run(ClientCustomerApplication.class,args);
}
}
运行它,然后浏览器刷新之前运行的Eureka可视化页面,就会出现你注册的client服务
目录结构如下
同理上面3.1一样注册,新建module,命名为eureka_client_pay,然后分三步,配pomx.ml,配application.yml,配启动类
第一步:pom.xml和之前client一样,新增依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
第二步:resources下配application.yml,由于8080用了,所以我们这个用8081,同样向localhost:8761
的Eureka注册,并指定服务名称
# 指定往哪个EurekaServer服务中注册
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
# 指定服务名称,为了区分创建的服务
spring:
application:
name: client_pay
server:
port: 8081
第三步:启动类,开启EurekaClient,然后启动
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ClientPayApplication {
public static void main(String[] args) {
SpringApplication.run(ClientPayApplication.class,args);
}
}
启动后,刷新浏览器Eureka可视化界面,如果你电脑内存比较小,开的服务多就会很卡,建议加内存,开发现在一般都要16G内存才够了,正常出现注册的信息,现在Eureka Server中就注册了两个Client服务,接着不同的服务之间就可以通信了,形象的说,就是以前用户Client和支付Client没有在Eureka注册,他们两个根本不认识对方,然后注册后,两个就认识了,可以通信对话了
我们开始讲了实现用户能访问到支付模块,也就是调用支付模块的接口,用户调用支付,用户就是消费者,支付就是生产者(提供支付功能)
先写支付Client提供的支付功能,新建一个controller,定义接口,返回支付成功,然后用户Clent访问这个接口
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PayController {
@GetMapping("/pay")
public String pay(){
String msg = "小明购买了一个充电宝,支付成功";
return msg;
}
}
再定义用户这边Controller,这里需要介绍一个叫RestTemplate的东西,它的作用是:消费者需要利用restTemplate来获取提供者注册的功能
这里要做两个操作,1、注册restTemplate的bean 2、ClientController编写
ClientCustomerApplication中新增下面
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
CustomerController.java
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class CustomerController {
@Autowired
private RestTemplate restTemplate; //消费者需要利用restTemplate来获取提供者注册的功能,配置new RestTemplate();
@Autowired
private EurekaClient eurekaClient;
@GetMapping("/customer")
public String client(){
//1、通过eurekaClient获取到client_pay服务的信息
InstanceInfo info = eurekaClient.getNextServerFromEureka("client_pay", false);//第二个参数false表示获取用的是http,true为安全的https
//2、获取到访问的地址
String url = info.getHomePageUrl();
System.out.println(url);//控制台打印访问的地址
//3、通过restTemplate访问
String res = restTemplate.getForObject(url + "/pay", String.class);//第二个值为返回值类型
//4、返回结果
return res;
}
}
重启ClientCustomerApplication和ClientPayApplication两个服务,重启完毕后到浏览器输入localhost:8080/customer,那么我们输入访问的是用户Client的/customer,但是却访问到了支付pay接口,这就是服务间的通信
如何保证Eureka的安全性?
SpringCloud提供了一种安全认证配置保证安全
首先需要在eureka_server01这个服务pom文件中新增一个安全的依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/eureka/**");//csrf做安全认证,底层用的是、HashSet
super.configure(http);
}
}
配置eureka_server01服务中application.yml,加上密码,账号密码要是root,root才能登录,重启EurekaServerApplication
刷新localhost:8761这个Eureka可视化界面,登录后,发现注册的两个Client服务不见了,为什么?因为还没配置他们登录到locahost:8761的账号密码,所以无法访问Eureka Server
配置两个Client账号密码,只要配置他们的application.yml
即可,加上root:root@
,表示访问localhost:8761/eureka/
会自动以root,root为账号和密码登录
重新启动两个Client,然后刷新Eureka可视化界面,就出现了,这就是加上了安全验证的Eureka
实际中就是宕机前已经输入localhost:8080/customer
间接调用了localhost:8081/pay
,那么在提供者一方会缓存调用执行的结果,即使Eureka宕机了,再运行localhost:8080/customer
也还是有之前相同结果的,但是没有调用过,就不会有缓存,这样宕机就不会有结果。
如何保证高可用?那就是配置多个Eureka,就算宕机一台,还有其他的保证服务可用。
我们现在来配两台Eureka,先全部stop停止
同样新建一个module,以maven创建,命名为eureka_server02,这里配置和eureka_server01一模一样,可以把eureka_server01内容都复制然后改改
1、pom.xml和server01的依赖一样
2、WebSecurityConfig不用改,直接复制
3、Server02Application除了名字不一样,和之前一样
4、eureka_server01的application.yml需要改下,也就是注册到8762的eureka上,eureka之间互相注册,实现数据同步,还有配置Eureka集群要把false变为true
eureka_server02的application.yml
两个Eureka Server就配置好了,并且能相互通信,保证数据同步
最后只要将两个Client注册到两个Eureka即可
重新启动四个
输入localhost:8761,另一个页面localhost:8762,登录后等几十秒,然后刷新才会同步,因为数据同步需要时间,同步后两个Eureka的服务一模一样,这样多个Eureka集群就能保证高可用,就算一个宕机了,其他也能使得Client服务正常进行
代码如下分享:
链接:https://pan.baidu.com/s/1-AZjb0-_ribbU_drIWL-Yw
提取码:6666
C(Consistency):一致性
A(Availability):可用性
P(Partition tolerance):分区容错性
一致性:不同服务器之间数据的一致性,也就是数据同步
可用性:客户端的请求能快速给出响应,这就是可用性好
分区容错性:不同地区的服务器因为网络延迟、信号传输等不可避免的因素,数据传输肯定是有微小延迟的,需要容忍这个微小误差。
以上三个特性在分布式环境下,无法都满足,只能满足两个,而且分区容错性P在分布式环境下必须满足,所以需要再A、C之间权衡
如果选择A,也就是AP组合,保证可用性,那么在一定时间内,可能几秒钟内,数据是不同步的,但是能保证很快响应
如果选择C,也就是CP组合,保证一致性,可能会造成系统在一定时间内是不可用的,因为使数据同步是需要时间的,可能时间太长,几分钟,造成的损失就巨大,比如双十一,用户不可能等几分钟加载。
Eureka选择的是AP组合,保证高可用,所以开多个Eureka时,会感觉到,多个Eureka之间数据不会马上同步,通常需要等待十几秒或更长,然后刷新两个Eureka中注册的服务才会一致
下一篇:Ribbon