1. 微服务架构演变过程
传统架构:即单点应用,也就是ssh/ssm项目,该架构模式没有对业务逻辑实现拆分,所有代码都写入到同一个工程中里,适合小公司开发团队或者个人开发;这种架构模式最大的缺点是如果该系统一个模块出现不可用、会导致整个系统无法使用。
分布式架构:分布式架构模式是基于传统的架构模式演变过来,将传统的单点项目根据业务模块实现拆分、会拆分为会员系统、订单系统、支付系统、秒杀系统等。 从而降低我们项目的耦合度,这种架构模式开始慢慢的适合于互联网公司开发团队。
SOA面向服务架构:SOA架构模式也称作为:面向服务架构模式、俗称面向与接口开发,将共同存在的业务逻辑抽取成一个共同的服务,提供给其他的服务接口实现调用、服务与服务之间通讯采用rpc远程调用技术。SOA架构通讯中,采用XML方式实现通讯、在高并发下通讯过程中协议存在非常大冗余性,所以在最后微服务架构模式中使用JSON格式替代了XML;SOA架构模式实现方案为WebService或者是ESB企业服务总线 底层通讯协议SOAP协议(Http+XML)实现传输。
微服架构务:粒度更加精细,让专业的人去做专业的事情,每个服务与服务之间互不影响,微服务架构中 每个服务必须独立部署、互不影响,微服务架构模式体现轻巧、轻量级、适合于互联网公司开发模式。服务与服务通讯协议采用Http协议,使用restful风格API形式来进行通讯,数据交换格式轻量级json格式通讯,整个传输过程中,采用二进制,所以http协议可以跨语言平台,并且可以和其他不同的语言进行相互的通讯。
2. 服务注册与发现
服务治理概念: 在RPC远程调用过程中,服务与服务之间依赖关系非常大,服务Url地址管理非常复杂,所以这时候需要对我们服务的url实现治理,通过服务治理可以实现服务注册与发现、负载均衡、容错等。
注册中心概念:次调用该服务如果地址直接写死的话,一旦接口发生变化的情况下,需要重新发布版本,所以需要一个注册中心统一管理我们的服务注册与发现。常用的注册中心有eureka、consul、zookeeper、nacos等。
服务注册:我们的服务启动的时候,会将当前服务自己的信息地址注册到注册中心,key为服务名称、value为该服务调用地址,该类型为集合类型。
服务发现:消费者从我们的注册中心上获取生产者调用的地址(集合),在使用负载均衡的策略获取集群中某个地址实现本地rpc远程调用。
3. Nacos搭建并整合SpringCloud
Nacos可以实现分布式服务注册与发现/分布式配置中心框架,官网介绍:https://nacos.io/zh-cn/docs/what-is-nacos.html
Nacos可以跨平台安装,支持Linux,Windows,Mac,安装教程地址:https://nacos.io/zh-cn/docs/quick-start.html
【手动注册】
参考官网,可以手动实现服务注册:
http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=app-member&ip=192.168.0.108&port=8080
http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=app-member&ip=192.168.0.108&port=8081
参考官网,可以手动实现服务发现:
http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=app-member,可以查到,是一个集群效果,并且登录nacos(默认用户名和密码都是nacos),进入服务管理 - 服务列表可以看到集群信息。
【整合SpringCloud】
新建聚合项目,springcloud-nacos,新建两个module分别为service-member,service-order,在父模块引入公共依赖:
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-discovery
0.2.2.RELEASE
新建service-member和service-order配置文件如下:
spring:
application:
# 服务的名称
name: service-member
cloud:
nacos:
discovery:
# nacos注册地址
server-addr: 127.0.0.1:8848
server:
port: 8080
spring:
application:
# 服务的名称
name: service-order
cloud:
nacos:
discovery:
# nacos注册地址
server-addr: 127.0.0.1:8848
server:
port: 8090
启动类只需加@SpringBootApplication即可,不像eureka还得加入@EnableEurekaServer
①. 手写类似Ribbon效果实现RestTemplate调用
首先在service-member服务编写getUser接口
@RestController
public class MemberService {
@Value("${server.port}")
private String serverPort;
/**
* 会员服务提供的接口被订单服务调用
* @param userId
* @return
*/
@GetMapping("/getUser")
public String getUser(Integer userId) {
System.out.println(userId);
return "会员服务-端口号为:" + serverPort;
}
}
启动两个member服务,端口分别为8080,8081
接下来编写service-order服务,首先在启动类把RestTemplate注入到Spring容器中:
@SpringBootApplication
public class AppOrder {
public static void main(String[] args) {
SpringApplication.run(AppOrder.class);
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
编写负载均衡器:
@Component
public class RotationLoadBalancer {
// 从0开始计数
private AtomicInteger atomicInteger = new AtomicInteger(0);
public ServiceInstance getSingleAddres(List serviceInstances) {
int index = atomicInteger.incrementAndGet() % serviceInstances.size(); // 每次计数器+1
return serviceInstances.get(index);
}
}
编写订单服务,并用RestTemplate调用会员服务
@RestController
public class OrderService {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
@Autowired
private RotationLoadBalancer loadBalancer;
/**
* 订单服务调用到会员服务接口
* @return
*/
@RequestMapping("/orderToMember")
public Object orderToMember() {
// 1.根据服务名称从 注册中心获取集群列表地址
List instances =
discoveryClient.getInstances("service-member");
// 2.列表任意选择一个 实现本地rpc调用 rest 采用我们负载均衡的算法
ServiceInstance serviceInstance = loadBalancer.getSingleAddres(instances);
URI rpcMemberUrl = serviceInstance.getUri();
String result = restTemplate.getForObject(rpcMemberUrl + "/getUser", String.class);
return "订单调用会员返回结果:" + result;
}
}
此时浏览器访问order接口orderToMember,会发现轮询调用会员服务
【服务下线动态感知】
我们可以手动下线/上线服务,当对8081端口下线后,则订单调会员只会走8080,而重新上线后,则继续轮询,期间不用重启服务,直接点击按钮即可。
最后,SpringCloud自带了Robbon/LoadBalanced实现了客户端负载均衡效果:
// 加上LoadBalanced 注解就可以实现我们的本地负载均衡
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@RequestMapping("/orderToRibbonMember")
public Object orderToRibbonMember() {
String result = restTemplate.getForObject("http://service-member/getUser", String.class);
return "订单调用会员返回结果:" + result;
}
SpringCloudAlibaba默认继承了Ribbon,直接调用即可,而如果是SpringCloudNetflix,则需要引入依赖如下:
org.springframework.cloud
spring-cloud-starter-ribbon