什么是服务治理?
Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务治理
在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册!什么是服务注册与发现
Eureka采用了CS的设计架构,Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka的客户端连接到 Eureka Server并维持心
跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个服务是否正常运行。
在服务注册与发现中,有一个注册中心,当服务器启动的时候,会把当前自己服务器的信息比如服务地址、通讯地址等以别名方式注册到注册中心上。另一方 (消费者|服务提供
者) ,以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。RPC远程调用框架核心设计思想: 在于注册中心,因为使用注册中心管理每个服务与
服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))
Eureka包含两个组件: Eureka Server和Eureka Client
Eureka Server提供服务注册服务:
各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
EurekaClient通过注册中心进行访问:
是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robinm)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳默认周期为30秒。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除 (默认90秒)。
我们直接利用eureka搭建一个服务注册与发现的集群,实现一个微服务调用的的功能
UTF-8
1.8
1.8
4.12
1.18.10
1.2.12
8.0.18
1.1.10
1.3.2
org.springframework.boot
spring-boot-dependencies
2.2.2.RELEASE
pom
import
org.springframework.cloud
spring-cloud-dependencies
Hoxton.SR1
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.1.0.RELEASE
pom
import
mysql
mysql-connector-java
${mysql.version}
runtime
com.alibaba
druid-spring-boot-starter
${druid.version}
org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis.spring.boot.version}
junit
junit
${junit.version}
log4j
log4j
${log4j.version}
(cloud-eureka-server7001、cloud-eureka-server7002、cloud-eureka-server7003)
主启动类:其他两个就不贴了
@EnableEurekaServer //表示此项目是eureka的服务注册中心
@SpringBootApplication
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}
pom.xml
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-devtools
runtime
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
application.yml 另外两个就不贴了,改下port和defaultZone
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己(想注册也可以,不过没必要)
register-with-eureka: false
#false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-reapplication.ymlgistry: false
service-url:
#设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址 单机
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#集群版 相互注册,相互守望
defaultZone: http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/
# defaultZone是固定写法,如果想自定义,需要按以下写法才行:
# region: eureka-server
# availability-zones:
# eureka-server: server1,server2
# service-url:
# server1: http://eureka7002.com:7002/eureka/
# server2: http://eureka7003.com:7003/eureka/
server:
#关闭自我保护,默认为true
enable-self-preservation: false
#心跳的间隔时间,单位毫秒
eviction-interval-timer-in-ms: 2000
修改下hosts文件:
cloud-api-commons
包路径为:
com.cjian.springcloud.bean
public class CommonResult {
private Integer code;
private String message;
private T data;
public CommonResult(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public CommonResult(Integer code, String message){
this(code, message, null);
}
public CommonResult() {
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
public class Payment implements Serializable {
private Long id;
private String serial;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSerial() {
return serial;
}
public void setSerial(String serial) {
this.serial = serial;
}
}
cloud-provider-payment8001、cloud-provider-payment8002
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
com.cjian.springloud
cloud-api-commons
${project.version}
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
com.alibaba
druid-spring-boot-starter
1.1.10
mysql
mysql-connector-java
8.0.18
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-devtools
runtime
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
application.yml
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: com.mysql.cj.jdbc.Driver # mysql驱动包
url: jdbc:mysql://127.0.0.1:3306/mysql?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: 123456
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.cjian.springcloud.bean # 所有Entity别名类所在包
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7001.com:7002/eureka,http://eureka7001.com:7003/eureka
instance:
instance-id: payment8001
prefer-ip-address: true #访问路径可以显示ip地址
#Eureka客户端向服务端发送心跳的时间间隔,单位秒(默认30秒)
lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待的时间上限,单位秒(默认90秒),超时剔除服务
lease-expiration-duration-in-seconds: 2
包路径:com.cjian.springcloud
@Mapper
public interface PaymentDao {
public int create(Payment payment);
public Payment getPaymentById(@Param("id") Long id);
}
public interface PaymentService {
public int create(Payment payment);
public Payment getPaymentById(@Param("id") Long id);
}
@Service
public class PaymentServiceImpl implements PaymentService {
@Resource
private PaymentDao paymentDao;
public int create(Payment payment)
{
return paymentDao.create(payment);
}
public Payment getPaymentById(Long id)
{
return paymentDao.getPaymentById(id);
}
}
@RestController
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@PostMapping(value = "/payment/create")
public CommonResult create(@RequestBody Payment payment)
{
int result = paymentService.create(payment);
System.out.println(("*****插入结果:" + result));
if(result > 0)
{
return new CommonResult(200,"插入数据库成功,serverPort: "+serverPort,result);
}else{
return new CommonResult(444,"插入数据库失败",null);
}
}
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id)
{
Payment payment = paymentService.getPaymentById(id);
if(payment != null)
{
return new CommonResult(200,"查询成功,serverPort: "+serverPort,payment);
}else{
return new CommonResult(444,"没有对应记录,查询ID: "+id,null);
}
}
}
insert into payment(serial) values(#{serial});
主启动类:
这里
@SpringBootApplication
//@EnableEurekaClient 不加该注解也是可以的,下面分析eureka原理的时候再说
public class PaymentMain001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain001.class, args);
}
}
建表sql:
CREATE TABLE `payment`(
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`serial` varchar(200) DEFAULT '',
PRIMARY KEY (id)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4
另一个服务提供者不做赘述~
cloud-consumer-order80
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
com.cjian.springloud
cloud-api-commons
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-devtools
runtime
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
@Configuration
public class ApplicationContextConfig {
//往容器中添加一个RestTemplate
//RestTemplate提供了多种便捷访问远程http访问的方法
@Bean
@LoadBalanced//开启负载均衡功能
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@RestController
public class OrderController {
// public static final String PAYMENT_URL = "http://localhost:8001";
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
@Resource
private RestTemplate restTemplate;
//因为浏览器只支持get请求,为了方便这里就用get
@GetMapping("/consumer/payment/create")
public CommonResult create(Payment payment){
System.out.println("********插入的数据:" + payment);
//postForObject分别有三个参数:请求地址,请求参数,返回的对象类型
return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult getPayment(@PathVariable("id") Long id){
System.out.println("********查询的id:" + id);
//getForObject两个参数:请求地址,返回的对象类型
return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
}
}
application.yml
#访问一个网站时,默认是80端口,给用户80端口,用户就可以不用加端口直接访问页面
server:
port: 81
spring:
application:
name: cloud-order-service
eureka:
client:
register-with-eureka: true
etch-registry: true
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7001.com:7002/eureka,http://eureka7001.com:7003/eureka
instance:
instance-id: consumer81
prefer-ip-address: true #访问路径可以显示ip地址
#Eureka客户端向服务端发送心跳的时间间隔,单位秒(默认30秒)
lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待的时间上限,单位秒(默认90秒),超时剔除服务
lease-expiration-duration-in-seconds: 2
主启动类:
@SpringBootApplication
//@EnableDiscoveryClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
依次启动3个注册中心、消费者和2个服务提供者,访问 localhost:7001
访问 http://localhost:81/consumer/payment/get/3
再次访问: