搭建SpringCloud微服务

系统架构的演化:
单体架构—适合团队不大,软件复杂度不高的场景下
垂直应用架构—
maven project+maven model
分布式服务
流动计算架构

什么是微服务架构
微服务架构风格这种开发方法,是以开发一组小型服务的方式
来开发一个独立的应用系统的。其中每个小型服务都运行在自己的进程
中,并经常采用HTTP资源API这样轻量的机制来相互通信。这些服务围绕
业务功能进行构建,并能通过全自动的部署机制来进行独立部署。这些
微服务可以使用不同的语言来编写,并且可以使用不同的数据存储技术
。对这些微服务我们仅做最低限度的集中管理

    1. 每个微服务可独立运行在自己的进程里;
	2. 一系列独立运行的微服务共同构建起了整个系统;
	3. 每个服务为独立的业务开发,一个微服务一般完成某个特定
的功能,比如:订单管理、用户管理等;
	4. 微服务之间通过一些轻量的通信机制进行通信,例如通过REST
API或者RPC的方式进行调用

微服务设计原则
单一职责原则
服务自治原则
轻量级通信原则
接口明确原则

REST和微服务架构是一个很好的组合,它适合于构建大型的系统。

常见的的开发框架有dubbo(阿里–RPC)、Spring Cloud

SpringCloud和Dubbo区别
Dubbo是阿里的服务治理的核心框架,服务中心采用Zookeeper,服务调用方法为RPC,服务提供者与调用方接口依赖太强,没有REST灵活,服务对平台敏感,难复用,断路器支持不完整,需要整合其它组件实现对应功能
SpringCloud是Pivotal的微服务解决方案,NetFlix微服务架构套件是核心,采用Eureka作注册中心,同时支持其它注册中心组件,服务调用采用REST API,同时针对服务网关、断路器、服务分布式配置、批量任务等,提供对应解决方案

两个应用之间的调用方法:
HttpClient
Spring web从3.0+开始引入了RestTemplate

服务治理: Eureka

1、搭建Eureka服务器
1.1、创建项目添加依赖,创建项目是选择cloud discovery/eureka server

<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>

1.2、在主类上添加注解

@SpringBootApplication
		@EnableEurekaServer
		public class EurekaServerApplication 

1.3、添加Eureka相关的配置信息

server.port=8761当前应用的端口号

		eureka.client.fetch-registry=false是否需要抓取注册信息
		eureka.client.register-with-eureka=false是否需要注册自己的信息
		eureka.client.service-url.default-zone=http://localhost:8761/eureka/对应的eureka的地址	

1.4、验证:

为浏览器中输入http://localhost:8761/	

2、创建服务的提供者项目,具体的开发步骤和SpringBoot的SSM开发一致
2.1、创建项目时额外添加的依赖 选择cloud discovery/eureka discovery

<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>

2.2、在主类上添加注解

@SpringBootApplication
		@EnableEurekaClient
		public class BooksApplication

2.3、添加配置信息

eureka.client.service-url.default-zone=http://localhost:8761/eureka/
		spring.application.name=BookProvider

2.4、先启动Eureka Server,然后启动服务提供者,在Eureka的web管理页面上可以看见当前服务的注册信息

		Application		Status
		BOOKPROVIDER	192.168.20.8:BookProvider			

3、创建服务的消费者项目,具体的开发步骤和SpringBoot的web开发一致
3.1、创建项目时额外添加的依赖 选择cloud discovery/eureka discovery

    <dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>

3.2、在主类上添加注解

	@SpringBootApplication
	@EnableEurekaClient
	public class BooksApplication{
		@Bean
		public RestTemplate restTemplate() {
			return new RestTemplate();
		}
	}

3.3、添加配置信息

eureka.client.service-url.default-zone=http://localhost:8761/eureka/
		spring.application.name=BookConsumer

3.4、在控制器中通过名称查找指定的服务实例信息,例如地址、端口号等

@Controller
@RequestMapping("/books")
public class BookController {
	@Autowired
	private EurekaClient eurekaClient;
	@Autowired
	private RestTemplate restTemplate;

	@GetMapping("")
	public String list(Model model) throws Exception {
		InstanceInfo info = eurekaClient.getNextServerFromEureka("BOOKPROVIDER", false);
		String uri = info.getHomePageUrl();
		Book[] blist = restTemplate.getForObject(uri + "/v1.0/books/", Book[].class);
		model.addAttribute("bookList", blist);
		System.out.println(blist);
		return "books/list";
	}

商品管理
(商品编号、商品名称、价格、图片、商品描述)

以信息为中心的表述性状态转移(Representational State Transfer,REST)已经称为替代传统SOAP Web 服务的流行方案.SOAP关注的一般是行为和处理,而REST关注的是要处理的数据.从Spring3.0开始,Spring为创建Rest API提供了良好的支持.

RestTemplate
借助RestTemplate,Spring应用能够方便地使用REST资源.Spring的RestTemplate访问使用了模版方法的设计模式.

delete()在特定的URL上对资源执行HTTP DELETE操作
exchange()在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中映射得到的
execute()在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象

getForEntity()发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象
getForObject()发送一个HTTP GET请求,返回的请求体将映射为一个对象

getForEntity(String url, Class responseType, Object... urlVariables):该方法提供了三个参数,其
   中url为请求的地址,responseType为请求响应体,body的包装类型,urlVariables为url中的参数绑定。GET请
   求的参数绑定通常使用url中拼接的方式,比如http://USER-SERVICE/user?name=did可以像这样自已将参数拼
   接到url中,但更好的方法是在url中使用占位符并配合urlVariables参数实现GET请求的参数绑 定,比如url定义
   为http://USER-SERVICE/user?name={l),然后可以这样来调用:
   getForEntity("http://USER-SERVICE/user?name={l}", String.class, "ddi")其中第三个参数didi会替
   换url中的{1}占位符。这里需要注意的是由于urlVariables参数是一个数组,所以它的顺序会对应url中占位符定
   义的数字顺序。

getForEntity(String url, Class responseType, Map urlVariables):该方法提供的参数中只有urlVariables
   的参数类型与上面的方法不同。这里使用了Map类型,所以使用该方法进行参数绑定时需要在占位符中指定Map中参
   数的key值,比如url定义为http://USER-SERVICE/user?name={name),在Map类型urlVariables中就需要put一
   个key为name的参数来绑定url中{name}占位符的值

postForEntity()POST数据到一个URL,返回包含一个对象的ResponseEntity,这个对象是从响应体中映射得到的

postForObject()POST数据到一个URL,返回根据响应体匹配形成的对象

put() PUT 资源到特定的URL

Eureka是Netflix开发的服务发现组件,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。Spring cloud将它集成在子项目spring-cloud-netflix中,以实现Spring Cloud的服务发现功能。

Eureka 客户端的服务注册
Eureka客户端在运行时会向Eureka服务端发送周期性的心跳,Eureka 服务端利用客户端周期性的心跳续约请求来保证注册表的实时性。其中客户端会向服务端提供一个如果多久没有向服务端发送心跳请求,就不再维护这个客户端的时间阈值。

Eureka 客户端的服务拉取
在通常情况下服务提供者可能为多个实例,服务调用者在调用服务时通过一些特定的负载均衡算法来把请求转发到该服务调用者的实例上。Eureka 客户端也会定时向服务端获取最新的服务列表,如果想保证实时性更高的话需要修改其配置来实现。

Eureka-Client接口
提供多种方法获取应用集合Applications和应用实例信息集合InstanceInfo。提供方法获取本地客户端信息,如应用管理器ApplicationInfoManager和Eureka-Client配置EurekaClientConfig。提供方法注册本地客户端的健康检查和 Eureka 事件监听器。

InstanceInfo info=eurekaClient.getNextServerFromEureka("provider",false);false表示是否使用https
String uri=info.getHomePageUrl();
restTemplate.getForObject(uri+"/show",List.class);

DiscoveryClient接口
实现EurekaClient接口,用于与Eureka-Server交互。实现方法:1、向Eureka-Server注册自身服务。2、向Eureka-Server续约自身服务。3、向Eureka-Server取消自身服务,当关闭时。4、从Eureka-Server查询应用集合和应用实例信息

将org.springframework.cloud.client.discovery.DiscoveryClient;对象注入。消费者的第二方法:的唯一区别就是启动类上注解变成了@EnableDiscoveryClient,声明这是一个Eureka Client

List<ServiceInstance> list = discoveryClient.getInstances("bookprovider");
System.out.println("discoveryClient.getServices().size() = " + discoveryClient.getServices().size());

for (String s : discoveryClient.getServices()) {
	System.out.println("services " + s);
	List<ServiceInstance> serviceInstances = discoveryClient.getInstances(s);
	for (ServiceInstance si : serviceInstances) {
		System.out.println("services:" + s + ":getHost()=" + si.getHost());
		System.out.println("services:" + s + ":getPort()=" + si.getPort());
		System.out.println("services:" + s + ":getServiceId()=" + si.getServiceId());
		System.out.println("services:" + s + ":getUri()=" + si.getUri());
		System.out.println("services:" + s + ":getMetadata()=" + si.getMetadata());
	}
}

System.out.println(list.size());
if (list != null && list.size() > 0) {
	System.out.println(list.get(0).getUri());
}

discoveryClient.getServices().size() = 2
services bookprovider
    services:bookprovider:getHost()=localhost
    services:bookprovider:getPort()=8080
    services:bookprovider:getServiceId()=BOOKPROVIDER
    services:bookprovider:getUri()=http://localhost:8080
    services:bookprovider:getMetadata()=vlsi.utils.CompactHashMap@7bac814d
1
http://localhost:8080

Eureka是单点的不适合于生产环境,那如何实现Eureka的高可用
Eureka Server都是单节点的,一旦该节点在生产中挂掉,就无法再提供服务的注册,为了保证注册中心的高可用,在生产中一般采用多节点的服务注册中心。

Eureka 的自我保护机制
Eureka在CAP理论当中是属于AP,也就说当产生网络分区时,Eureka保证系统的可用性,但不保证系统里面数据的一致性。默认情况下,当eureka server在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒),但是,如果短时间内丢失大量的实例心跳,便会触发eureka server的自我保护机制。在自我保护模式下eureka虽然收不到实例的心跳,但它认为实例还是健康的,eureka会保护这些实例,不会把它们从注册表中删掉。
保护机制的目的是避免网络连接故障,在发生网络故障时,微服务和注册中心之间无法正常通信,但服务本身是健康的,不应该注销该服务,如果eureka因网络故障而把微服务误删了,那即使网络恢复了,该微服务也不会重新注册到eureka server了,因为只有在微服务启动的时候才会发起注册请求,后面只会发送心跳和服务列表请求,这样的话,该实例虽然是运行着,但永远不会被其它服务所感知。所以eureka server在短时间内丢失过多的客户端心跳时,会进入自我保护模式,该模式下eureka会保护注册表中的信息,不在注销任何微服务,当网络故障恢复后,eureka会自动退出保护模式。自我保护模式可以让集群更加健壮。

在开发测试阶段,需要频繁地重启发布eureka.server.enable-self-preservation=false
在生产环境,不会频繁重启,所以,一定要把自我保护机制打开,否则网络一旦终端,就无法恢复。

Eureka在一个服务启动后最长需要2分钟才能被其它服务所感知
这是由三处缓存 + 一处延迟造成的
首先,Eureka对HTTP响应做了缓存。首先会去缓存中查询数据,如果没有则生成数据返回(即真正去查询注册列表),且缓存的有效时间为30s。也就是说,客户端拿到Eureka的响应并不一定是即时的,大部分时候只是缓存信息。
其次,Eureka Client对已经获取到的注册信息也做了30s缓存。即服务通过eureka客户端第一次查询到可用服务地址后会将结果缓存,下次再调用时就不会真正向Eureka发起HTTP请求了。
再次,负载均衡组件Ribbon也有30s缓存。Ribbon会从Eureka Client获取服务列表,然后将结果缓存30s。
最后,如果你并不是在Spring Cloud环境下使用这些组件(Eureka, Ribbon),你的服务启动后并不会马上向Eureka注册,而是需要等到第一次发送心跳请求时才会注册。心跳请求的发送间隔也是30s。

随着系统的的上线,用户量也会逐步上升,很明显一台服务器已经满足不了系统的负载,这时就要在服务器还没有超载时,提前做好准备。常见的情况是单体架构,优化架构在短时间内是不现实的,增加机器是一个不错的选择。这时,可能要把应用和数据库服务单独部署,如果有条件也可以把文件服务器单独部署。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值