1. 最初的单体应用时代, 如果我一个服务是产品服务,一个试订单服务. 产品服务想要去访问订单服务, 我们都是怎么做的呢?
也就是说: 商品服务调用订单服务, 通过的是http远程调用的方式实现的, 这样的问题是什么呢?
- 如果订单服务宕机了, 商品服务还能调通么?
- 如果订单服务的ip地址更改了, 商品服务的远程调用地址是不是也要一起发生变化?
- 如果订单服务一台服务器不够用了, 需要增加一台服务器, 商品服务就要自己维护一个订单服务的ip列表. 并按照一定规则访问
这就是单体服务的问题, 因为ip是写死在商品服务里面的, 所以, 一旦发生变化, 不能自动感知, 必须手动修改.
2. 订单服务流量增多, 变成了多个订单服务
这个时候, 我们怎么做的呢? 我们要满足实际业务的需求, 订单量太大了, 单台服务器经常支撑不了了, 于是就想到, 部署多台服务来分担压力.
就出现了上面的模型, 可是, 这个模型存在什么样的问题呢?
- 程序员自己维护的ip列表, 如果订单服务某一台挂了怎么办, 那就请求不通了
- 如果订单服服务依然不能满足需求, 还要继续扩容, 程序员又要重新维护一份订单服务的ip列表.
手动维护ip列表肯定不好, 一方面一旦有任何变动, 就需要进行维护; 另一方面, 从效率上来讲, 也不高. 还容易出错. 于是慢慢有就有了nginx
3. 使用nginx来维护订单服务的ip列表
商品服务的所有请求过来了, 不要直接去请求订单服务. 通过nginx去请求订单服务. 在nginx中维护了订单服务的ip列表. 并且可以指定负载均衡策略.
嗯, 这个选择好像还不错, 不用程序员经常改商品服务代码了, 也不用程序员自己写如何分配请求的流量了. 那么他就满足我们所有的需求么?当然也不是
- 虽然程序员不用在代码中维护ip列表了, 但是在nginx中依然要维护. 如果订单服务有很多很多, 怎么办? 我们知道在nginx上是通过upstream来维护ip的, 如果有成百上千的服务, 那么我们要维护成百上千个ip么?
- 如果订单服务扩缩容了, 是不是一样要修改nginx的配置文件呢?
于是我们就想,有没有一种办法, 能够让微服务自动的就被注册上呢?这个需求迫在眉睫
4. 于是, 就有了注册中心的概念. 最初, 我们的想法也很简单
首先有一个数据库表来维护所有的服务, 并标记这些服务的启动状态
然后, 每当有一个服务启动, 那么都调用注册接口, 其实注册接口就是一个insert服务器信息到数据库的过程
第三, 每次商品服务要调用订单服务了, 先去数据库里面查询可用的订单服务列表. 然后根据策略选择服务ip,
第四, 根据ip发送请求.
这里面也会有一些问题
- 服务宕机了怎么办? 还来不及发出通知
- 每次商品服务调用订单服务, 都要去数据库查询可用的服务列表, 这样当流量大了, 就会给数据库造成很大的压力, 而且, 每次都查数据库, 效率也不高.
- 注册中心宕机 了怎么办?
于是, 想到将我们的注册中心进行改造. 改造的更加完美一些
5. 改造后的注册中心
这个就是在上面的基础上改造过来的
1. 增加了一个last_heartTime, 记录心跳时间.
2. 当商品服务和订单服务启动的时候, 需要调用注册接口, 告诉注册中心, 我上线了, 实质上这是一个insert记录的过程
3. 商品服务和订单服务有一个定时任务timetask1, 定期发送心跳. 然后注册中心就会修改这个心跳时间. 通常是30秒发送一次.
4. 商品服务有一个定时任务timerTask2, 定期去任务中心拉取服务列表, 并将其保存在客户端缓存中, 当请求过来的时候, 通过ribbon拉取客户端缓存的ip, 按照负载均衡策略, 选择指定的订单服务发送远程调用,
5. 在注册中心有一个定时任务timerTask3, 如果注册中心在规定的时间内, 没有收到微服务的心跳, 那么就认为服务挂了, 将其状态设置为down, 下次拉取的时候, 这台服务器不会被拉取过去. 其实,这是一个状态修改的过程
6. 当服务停止的时候, 会调用服务注销接口, 通知注册中心,服务停止, 注册中心就是将其从注册表中删除. 其实这就是一个delete记录的过程
bin/startup.sh ‐m standalone
也可以修改默认启动方式
父级maven
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring-nacos</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>firsrt-nacos</module>
<module>two-nacos</module>
</modules>
<properties>
<java.version>1.8</java.version>
<spring.cloud.alibaba.version>2.2.5.RELEASE</spring.cloud.alibaba.version>
<spring.boot.version>2.3.11.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR8</spring.cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- spring boot 依赖 spring boot版本管理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibbba 版本管理以及微服务组件 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud 版本管理以及微服务组件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
firsrt-nacos 项目
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-nacos</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>firsrt-nacos</artifactId>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<!-- nacos 服务的注册与发现。 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
application.properties
server.port=8002
#微服务名称
spring.application.name=firsrt-nacos
#配置 Nacos server 的地址
spring.cloud.nacos.discovery.server‐addr=localhost:8848
TestController
package com.yqx.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author yanqx
* @date 2023/11/13 14:18
*/
@RestController
@RequestMapping("/order")
public class TestController {
@Value("${server.port}")
String port;
@RequestMapping("/reduct")
public String reduct() throws InterruptedException {
System.out.println("扣减库存");
return "扣减库存:"+port;
}
}
启动后会发现
two-nacos 项目
pom
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-nacos</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>two-nacos</artifactId>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<!-- nacos 服务的注册与发现。 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
application.properties
server.port=8003
#微服务名称
spring.application.name=two-nacos
#配置 Nacos server 的地址
spring.cloud.nacos.discovery.server‐addr=localhost:8848
Application
package com.yqx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author yanqx
* @date 2023/11/13 14:10
*/
@SpringBootApplication
public class TwoNacosApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(TwoNacosApplication.class, args);
}
}
调用第一个方法的controller
package com.yqx.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author yanqx
* @date 2023/11/13 14:53
*/
@RestController
@RequestMapping("/two")
public class TwoController {
@Autowired
RestTemplate restTemplate;
@RequestMapping("/add")
public String add(){
System.out.println("下单成功!");
String msg = restTemplate.getForObject("http://firsrt-nacos/order/reduct", String.class);
return "Hello World"+msg;
}
}
Nacos注册中心架构