tl-微服务专题04-微服务介绍 及Eureka服务注册与发现详解
微服务介绍
及Eureka服务注册与发现详解
目录
一、微服务概述
1、微服务是什么?
2、微服务架构是什么?
3、微服务的优缺点
4、CAP理论
【抛开理论,两个系统之间要保证数据立马一致?还是随时可用?因为两个系统之间涉及到通信,通信就需要时间,需要过程,过程不是完全原子性的,是有跨度的,且过程可能出错。但不能说通信失败也各自干各自的完全不管彼此,那两边就会产生差异错误了。所以通信必须保障不能绕开,即P必选。考虑到通信的跨度及容错,那么要一致,就需要先锁定彼此只干这一件事,别的都暂停,则不可用。要随时可用,那就不能立马一致。所以ca互斥。】
为啥CAP 只能三选二
5:springcloud微服务技术栈有哪些技术
二、eureka应用入门
1、没有使用注册中心搭建的分布式应用
2、服务发现原理初探
3、Eureka入门
4、Eureka 部署架构
5、eureka 的自我保护功能
6、eureka 的高可用 搭建
7、安全配置
一**、**微服务概述
1、微服务是什么?
英文出处:https://martinfowler.com/articles/microservices.html
中文译文:http://blog.cuicc.com/blog/2015/07/22/microservices/
1.1)微服务核心就是把传统的单机应用,根据业务将单机应用拆分为一个一个的服务,彻底的解耦,每一个服务都只提供特定的功能,一个服务只做一件事,类似进程,每个服务都能够单独部署,甚至可以拥有自己的数据库。这样的一个一个的小服务就是 微服务。
1.2) 比如传统的单机电商应用里有 订单/支付/库存/物流/积分等模块(理解为servcie),我们根据 业务模型来拆分,可以拆分为 订单服务,支付服务,库存服务,物流服务,积分服务。
1.3)若不拆分的时候,我们的非核心业务积分模块出现了重大bug导致系统内存溢出,导致整个服务宕机。若拆分之后,只是说我的积分微服务不可用,我的整个系统核心功能还是能使用。
1.4)图解:传统的all in one系统和all in one的集群版本及微服务架构版本
![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2l0d3htaW5n_size_16_color_FFFFFF_t_70][]
1.5)all in on 工程的数据存储 以及微服务的数据存储
2、微服务架构是什么?
微服务架构是一个架构风格,提倡:
- 将一个单一应用程序开发为一组小型服务。
- 每个服务运行在自己的进程中。
- 服务之间通过轻量级的通信机制(http rest api)。
- 每个服务都能够独立的部署。
- 每个服务甚至可以拥有自己的数据库。
微服务以及微服务架构的是二个完全不同的概念。
微服务强调的是服务的大小和对外提供的单一功能,而微服务架构是指把一个一个的微服务组合管理起来,对外提供一套完整的服务。
3、微服务的优缺点
优点:
- :每个服务足够小,足够内聚,代码更加容易理解,专注一个业务功能点(对比传统应用,可能改几行代码 需要了解整个系统)。
- :开发简单,一个服务只干一个事情。(假如你做支付服务,你只要了解支付相关代码就可以了)
- :微服务能够被2-5个人的小团队开发,提高效率。
- :服务松耦合,每个服务都能够开发部署。
- : 前后端分离, 作为java开发人员,我们只要关心后端接口的安全性以及性能,不用去关注页面的人机交互(H5工程师)。根据前后端接口协议,根据入参,返回json的回参。
- :一个服务可拥有自己的数据库。也可以多个服务连接同一个数据库。
缺点:
- :增加了运维人员的工作量,以前只要部署一个war包,现在可能需要部署成百上千个war包。
- :服务之间相互调用,增加通信成本。
- :数据一致性问题(分布式事务问题)。
- :系统监控等。
4、**CAP理论**
【抛开理论,两个系统之间要保证数据立马一致?还是随时可用?因为两个系统之间涉及到通信,通信就需要时间,需要过程,过程不是完全原子性的,是有跨度的,且过程可能出错。但不能说通信失败也各自干各自的完全不管彼此,那两边就会产生差异错误了。所以通信必须保障不能绕开,即P必选。考虑到通信的跨度及容错,那么要一致,就需要先锁定彼此只干这一件事,别的都暂停,则不可用。要随时可用,那就不能立马一致。所以ca互斥。】
分布式系统的三个指标
- :**Consistency (一致性)**
- :**Availability(可用性)**
③:**Partition tolerance(分区容错性)**
结论:这三个指标不可能同时做到。这个结论就叫做 CAP 定理。
4.1)**戏说分区容错性 (Partition tolerance)**
大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败(由于**网络**原因)。比如,一台服务器放在北京,另一台服务器放在上海,这就是两个区,它们之间由于网络抖动原因导致不能通信。
上图中,G1 和 G2 是两台跨区的服务器。G1 向 G2 发送一条消息,G2 可能无法收到。系统设计的时候,必须考虑到这种情况。
一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。
4.2)**Consistency(一致性)(各个时间上,各个服务器上的数据必须要一致的)**
Consistency 中文叫做”一致性”。意思是:写操作之后的读操作,必须返回该值。举例来说,某条记录是 v0,用户向 G1 发起一个写操作,将其改为 v1。
存在的问题:
用户有可能向 G2 发起读操作,由于 G2 的值没有发生变化,因此返回的是 v0。G1 和 G2 读操作的结果不一致,这就不满足一致性了。
解决方案:为了让 G2 也能变为 v1,就要在 G1 写操作的时候,让 G1 向 G2 发送一条消息,要求 G2 也改成 v1。
4.3)**Availability 可用性**
Availability 中文叫做”可用性”,意思是只要收到用户的请求,服务器就必须给出回应。
用户可以选择向 G1 或 G2 发起读操作。不管是哪台服务器,只要收到请求,就必须告诉用户,到底是 v0 还是 v1,否则就不满足可用性。
为啥CAP 只能三选二
Consistency 和 Availability 的矛盾
一致性和可用性,为什么不可能同时成立?答案很简单,因为可能通信失败(即出现分区容错),且通信需要跨度。
如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,G2 不能读写,没有可用性。
如果保证 G2 的可用性,那么势必不能锁定 G2,所以一致性不成立。
综上所述,G2 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。
Eureka是最终一致,可用性,AP。
5:springcloud微服务技术栈有哪些技术
5**.1)推荐的二个springcloud的论坛链接**
http://springcloud.cn/
https://springcloud.cc/spring-cloud-dalston.html
5**.2)微服务技术栈的技术一概总览(springcloud微服务架构生态圈)**
微服务架构技术栈 | 实现技术 |
|
服务开发 | springboot,springmvc |
|
服务配置 | config |
|
服务注册发现 | spring cloud eureka |
|
服务调用 | ribbon,feign |
|
服务路由 | zuul |
|
服务熔断 | hystrix |
|
服务全链路监控 服务部署 | sleuth+zipkin docker k8s |
|
5**.3) spring cloud技术栈图示**
二、eureka应用入门
1、没有使用注册中心搭建的分布式应用
服务消费者(user服务) & 提供者(order服务)
如下图
就是User服务发起一个请求,通过用户Id查询到该用户下的所有订单信息。
比如现在我的用户服务是占用(User服务)8081端口的服务, 此时我的服务提供方(order服务)端口是8080端口,
我们可以通过RestTemplate 调用方式来进行调用
//在用户服务中调用 订单服务
ResponseEntity responseEntity = restTemplate.getForEntity(“http://localhost:8080/order/queryOrdersByUserId/"+userId,List.class);
缺点:
①:从上面看出的缺点就是,我们的在调用的时候,请求的Ip地址和端口是硬编码的**。**若此时,服务提供方(order)服务部署的机器换了端口或者是更换了部署机器的Ip,那么我们需要修改代码重新发布部署。
②:假设我们的order服务压力过大,我们需要把order服务作为集群,那么意味着 order是多节点部署。比如原来的,我们只有一台服务器,现在有多台服务器,那么作为运维人员需要在服务消费方进行手工维护一份注册表(容易出错)
③:有人马上回驳说,可以通过Nginx**来做负载均衡,对,我们首先认为这是可行的,但是微服务成百上千的服务,难道我们要用成百上千ng么?或者使用一个Ng 那么我们能想一下那个ng的配置文件有多么复杂**。
2、**服务发现原理初探**
其实,服务发现机制非常简单,不妨用大家熟悉的MySQL(也可以用redis来做存储)来类比——只需一张表(图中的registry表)即可实现服务发现。
- 应用启动时,自动往registry表中插入一条数据,数据包括服务名称、IP、端口等信息。
- 应用停止时,自动把自己在registry表中的数据的status设为 DOWN 。
- 服务调用,每次调用前,去mysql中去查询 select * from register where server_name=’服务名称’ and status=’UP’的记录,然后替换原来的调用路径地址。
缺点: 上面这个毕竟是一个很简陋的服务注册中心
缺点1:若当前服务宕机,我们必须要把自己的对应的数据标记为down。宕机怎么标?
缺点2:服务每次调用都要发送select 语句,mysql的压力很大。
缺点3:若mysql 服务注册中心挂了,我们也应该提供服务调用。
真正的服务注册发现组件应该满足哪些条件才称为一个合格的服务发现注册组件**?**
1)提供一个服务注册接口,其他微服务启动的时候,把自己的IP,端口都在服务端注册下来**。**
2)提供一个服务发现接口,也就是微服务可以通过service_id 来获取到 对应微服务的网络地址和端口**。**
3)各个微服务与服务注册组件,使用心跳检查机制,若服务注册组件长时间和某微服务没有通信,那么就应该剔除服务**。**
4)**客户端缓存**,各个微服务将需要调用服务的地址缓存在本地,并使用一定机制更新(例如定时任务更新、事件推送更新等)。这样既能降低服务发现组件的压力,同时,即使服务发现组件出问题,也不会影响到服务之间的调用。
3、**Eureka入门**
eureka分为服务端和客户端
3**.1)搭建eureka服务端**
三板斧:
①**加依赖**
②**:写注解。在主启动类上写上@EnableEurekaServer注解**
@EnableEurekaServer
public class MsEurekaServerApplication {
}
③**:编写配置文件**
#eureka服务端应用的端口默认是8761
server.port=9000
#表示是否将自己注册到Eureka Server,默认为true,由于当前应用就是Eureka Server,故而设为false
eureka.client.register-with-eureka=false
# 表示是否从Eureka Server获取注册信息,默认为true,因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,故而设为false
eureka.client.fetch-registry=false
#暴露给其他eureka client 的注册地址
eureka.client.service-url.defaultZone: http://localhost:9000/eureka/
常用服务端配置:
server:
port: 8761
spring:
application:
name: registry-server
# profiles:
# active: peer2
profiles:
active: zone1
security:
basic:
enabled: true
user:
name: admin
password: admin
eureka:
instance:
hostname: localhost
# 过期时间,默认90s, 可不配置
lease-expiration-duration-in-seconds: 90
# 续约时间,默认30s,可不配置
lease-renewal-interval-in-seconds: 30
# ip地址优先
prefer-ip-address: true
server:
# 关闭注册中心自我保护模式,避免注册中心不移除失效的服务,默认为true。
enable-self-preservation: true
# 去除失效服务的时间间隔(毫秒)
eviction-interval-timer-in-ms: 60
client:
# 启用eureka客户端,默认为true, 可不配置
enabled: true
# 取注册信息,默认为true,可不配置
fetchRegistry: false
# 两个心跳参数,默认都是30s,可不配置
instance-info-replication-interval-seconds: 30
registry-fetch-interval-seconds: 30
# 注册到注册中心,默认为true,可不配置
registerWithEureka: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
logging:
level:
com.netflix.eureka: OFF
com.netflix.discovery: OFF
3**.2)搭建eureka客户端**
服务消费者 ms-consumer-user-8001
①**:加依赖**
②**:加入注解@EnableDiscoveryClient **
@EnableDiscoveryClient
public class MsConsumerUser8001Application
③**:编写配置文件**
server.port=8001
#注册到eureka服务端的微服务名称(如果有多个,该名称必须一样。)
spring.application.name=ms-consumer-user
#注册到eureka服务端的地址
eureka.client.service-url.defaultZone=http://localhost:9000/eureka/
#点击具体的微服务,右下角是否显示ip
eureka.instance.prefer-ip-address=true
#显示微服务的名称
eureka.instance.instance-id=ms-consumer-user-8001
mybatis.configuration.map-underscore-to-camel-case=true
#配置数据库
spring.datasource.url=jdbc//47.104.128.12:3306/tuling-cloud
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
logging.level.com.tuling.dao=debug
④**: 调用 使用RestTemplate (调用的时候不再是通过Ip 和地址发起调用,而是通过微服务名称进行调用)**
**需要加入@LoadBanlance 注解**
@RequestMapping("/queryUserInfoById/\{userId\}")
public UserInfoVo queryUserInfoById(@PathVariable("userId") Integer userId) \{
User user = userServiceImpl.queryUserById(userId);
ResponseEntity<List> responseEntity = restTemplate.getForEntity("http://MS-PROVIDER-ORDER/order/queryOrdersByUserId/"+userId,List.class);
List<OrderVo> orderVoList = responseEntity.getBody();
UserInfoVo userInfoVo = new UserInfoVo();
userInfoVo.setOrderVoList(orderVoList);
userInfoVo.setUserName(user.getUserName());
return userInfoVo;
\}
@Configuration
public class MainConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() \{
return new RestTemplate();
\}
}
4、Eureka 部署架构
Eureka有Region和Zone的概念,一个Region可以包含多个Zone,在进行服务调用时,优先访问处于同一个Zone中的服务提供者。
4**.1)首先, us-east-1c us-east-1d us-east-1e是什么东西??**
我们首先需要了解一下 aws(amazon web service) 可以类比中国的阿里云服务器.
Region(us-east-1,)** 可以类比于 阿里云的不同区域,我们在买阿里云服务器的时候,是不是需要你选择区域么?**各个Region 之间的内网是不相通的
Availabitlity zone 可用区(us-east-1c us-east-1d us-east-1e) **可以理解为 我们 一个地区比如华南地区,不同城市的机房,**内网是相通的
比如华南1 华东1 2 ,华北12345
- Eureka Server提供服务发现的能力,各个微服务启动时,会向Eureka Server注册自己的信息(例如IP、端口、微服务名称等),Eureka Server会存储这些信息;
- Eureka Client是一个Java客户端,用于简化与Eureka Server的交互(启动的时候,会向server注册自己的信息)
- 微服务启动后 renew,会周期性(默认30秒)地向Eureka Server发送心跳以续约自己的“租期”;
- 如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳(最后一次续约时间开始计算),Eureka Server将会注销该实例(默认90秒);
- 默认情况下,Eureka Server同时也是Eureka Client。多个Eureka Server实例,互相之间通过增量复制的方式,来实现服务注册表中数据的同步。Eureka Server默认保证在90秒内,Eureka Server集群内的所有实例中的数据达到一致(从这个架构来看,Eureka Server所有实例所处的角色都是对等的,没有类似Zookeeper、选举过程,也不存在主从,所有的节点都是主节点。Eureka官方将Eureka Server集群中的所有实例称为“对等体(peer)”)
- Eureka Client会缓存服务注册表中的信息。这种方式有一定的优势——首先,微服务无需每次请求都查询Eureka Server,从而降低了Eureka Server的压力;其次,即使Eureka Server所有节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者并完成调用
4.2)Eureka配置的总要信息讲解
①**:服务注册配置**
eureka.client.register-with-eureka=true
该项配置说明,是否向注册中心注册自己,**在非集群环境下设置为false,表示自己不注册自己**
eureka.client.fetch-registry=true
该项配置说明,注册中心只要维护微服务实例清单,**非集群环境下,不需要作检索服务,所有也设置为false**
**②**:服务续约配置
eureka.instance.lease-renewal-interval-in-seconds=30(默认)
该配置说明,服务提供者会维持一个心跳告诉eureka server 我还活着,这个就是一个心跳周期
eureka.instance.lease-expiration-duration-in-seconds=90(默认)
该配置说明,你的最后一次续约时间开始,往后推90s 还没接受到你的心跳,那么我就需要把你剔除.
③**:获取服务配置 (前提,eureka.client.fetch-registry为true)**
eureka.client.registry-fetch-interval-seconds=30
缓存在调用方的微服务实例清单刷新时间
5、eureka 的自我保护功能
默认情况下,若eureka server 在一段时间内(90s)没有接受到某个微服务实例的心跳,那么eureka server 就会剔除
该实例,当时由于网络分区故障,导致eureka server 和 服务之间无法通信,此时这个情况就变得很可怕—-因为微服务是实例健康的
,本不应注销该实例.
那么通过eureka server 自我保护模式就起作用了,当eureka server节点短时间(15min是否低于85%)丢失过多客户端是(由于网络分区),那么该eureka server节点就会进入自我保护模式,eureka server 就会自动保护注册表中的微服务实例,不再删除该注册表中微服务的信息,等到网络恢复,eureka server 节点就会退出自我保护功能(宁可放过一千,不要错杀一个)
6、eureka 的高可用 搭建
启动二个eureka server 9000端口 和9001端口
6.1)9000 端口的工程配置
server.port=9000
#表示是否将自己注册到Eureka Server 表示9000的服务端需要向9001工程注册自己
eureka.client.register-with-eureka=true
# 表示是否从Eureka Server获取注册信息,默认为true,需要从9001上同步数据
eureka.client.fetch-registry=true
讲自己注册到9001上去
eureka.client.service-url.defaultZone: http://www.eureka9001.com:9001/eureka/
6.2) 9001端口配置
server.port=9001
#表示是否将自己注册到Eureka Server 表示9001的服务端需要向9000工程注册自己
eureka.client.register-with-eureka=true
# 表示是否从Eureka Server获取注册信息,默认为true,需要从9000上同步数据
eureka.client.fetch-registry=true
讲自己注册到9000上去
eureka.client.service-url.defaultZone: http://www.eureka9000.com:9000/eureka/
6.3)微服务提供者配置,需要向二个注册中心进行注册
eureka.client.service-url.defaultZone=http://www.eureka9000.com:9000/eureka/,http://www.eureka9001.com:9001/eureka/
6.4)截图
7、安全配置
我们现在访问eureka server 直接访问 没有授权
7.1)导入安全配置 依赖
7.2)修改yml配置文件
//注册的时候需要带入 用户名 密码 基本格式为 http:用户名:密码@ip:端口/eureka/
eureka.client.service-url.defaultZone: http://$\{spring.security.user.name\}:$\{spring.security.user.name\}@www.eureka9000.com:9000/eureka/
//开启默认的认真
spring.security.basic.enable=true
spring.security.user.name=root
spring.security.user.password=123456
===============================================================客户端配置
注册地址修改为这个
eureka.client.service-url.defaultZone=http://$\{security.login.username\}:$\{security.login.pass\}@www.eureka9000.com:9000/eureka/
还没有评论,来说两句吧...