RPC分布式服务器框架,选择dubbo,或者SpringCloud
比如A模块调用B模块:A访问注册中心,知道B的地址后进行远程调用B
ZooKeeper就是注册中心,Dubbo做的就是分布式的调用
下载镜像
[root@localhost ~]# docker pull zookeeper
运行镜像
[root@localhost ~]# docker run --name zk01 -p 2181:2181 --restart always -d 454af3da184c
2181是客户端交互的端口,默认还有2888,3888做集群的端口
创建两个工程,一个服务提供者,一个服务消费者
创建空工程
接着使用spring初始化向导创建模块
引入依赖
<!--引入dubbo-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
服务启动时,就会扫描指定包,发布到dubbo的注册中心地址去
对于提供者
1、引入dubbo和zkclient相关依赖
2、配置dubbo的扫描包和注册中心地址
dubbo.application.name=provider-ticket
dubbo.registry.address=zookeeper://192.168.0.108:2181
dubbo.scan.base-packages=com.sjg.ticket.service
3、使用@Service发布服务
import com.alibaba.dubbo.config.annotation.Service;
import com.sjg.ticket.service.TicketService;
import org.springframework.stereotype.Component;
@Component //添加到spring容器
@Service //将服务发布出去
public class TicketServiceImpl implements TicketService{
@Override
public String getTicket() {
return "《厉害了》";
}
}
对于消费者
dubbo.application.name=consumer-user
dubbo.registry.address=zookeeper://192.168.0.108:2181
@Service
public class UserService {
@Reference //远程引用,去注册中心找已经发布的全类名
TicketService ticketService;
public void hello(){
String ticket = ticketService.getTicket();
System.out.println("买到票了" + ticket);
}
}
测试
@SpringBootTest
class ConsumerUserApplicationTests {
@Autowired
UserService userService;
@Test
void contextLoads() {
userService.hello();
}
}
dubbo是分布式框架,解决的是服务之间的调用问题
springCloud是分布式整体解决方案,也就是分布式系统里需要考虑的问题,springcloud都有解决方案
注册中心,使用EUreka
A服务和B服务互联互调,比如A服务 部署了多个实例,B服务部署多个实例,要调用不同实例,使用Ribbon负载均衡
短路器,快速响应断路
创建空工程
三个模块
server:
port: 8761
eureka:
instance:
hostname: eureka-server #eureka实例主机名
client:
register-with-eureka: false # 不把自己注册到eureka上,因为我们自己就是注册中心
fetch-registry: false # 不从eureka上获取服务的注册信息
service-url:
defaultZone: http://localhost:8761/eureka # 服务地址
server:
port: 8001
spring:
application:
name: provider-ticket
eureka:
instance:
prefer-ip-address: true # 注册服务的时候使用服务的ip地址
client:
service-url:
defaultZone: http://localhost:8761/eureka # 服务地址
eureka使用http协议来提供服务,所以向外部方法
@RestController
public class TicketController {
@Autowired
TicketService ticketService;
@GetMapping("/ticket")
public String getTicket(){
return ticketService.getTicket();
}
}
启动后发现,实例注册到注册中心了
打两个包,一个8001,一个8002端口
同一个应用在注册中心注册多个:
可以看到注册了两个实例
配置文件:配置消费者的端口以及名字
并且也要把它注册到注册中心,以便它可以获取提供者提供的服务
spring:
application:
name: consumer-user
server:
port: 8200
eureka:
instance:
prefer-ip-address: true # 注册服务的时候使用服务的ip地址
client:
service-url:
defaultZone: http://localhost:8761/eureka # 服务地址
主程序中,要开启发现服务功能,这样才能让消费者找到可以提供服务的提供者
还要将restTemplate放入spring容器,以便调用发现的服务
同时使用了负载均衡机制
@EnableDiscoveryClient //开启发现服务功能
@SpringBootApplication
public class ConsumerUserApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerUserApplication.class, args);
}
//restTemplate用来发送http请求,以便调用发现的服务
@LoadBalanced //使用负载均衡机制
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
消费提供者的服务,使用restTemplate从注册中心获取服务,直接使用http协议,从提供者中提供的服务进行消费
@RestController
public class UserController {
//用来消费服务
@Autowired
RestTemplate restTemplate;
@GetMapping("/buy")
public String buyTicket(String name){
//url指定httpxieyi,不需要写IP地址,只需要服务名,加上/ticket请求,就是去找提供者的服务
//返回值转成字符串String
String s = restTemplate.getForObject("http://PROVIDER-TICKET/ticket", String.class);
return name + "购买了" + s;
}
}
启动消费者应用后,发现消费者注册到了注册中心
直接访问可以完成,也就是调用的提供者的服务
再来看负载均衡,之前开启了两个提供者
每次访问,都会有一个提供者响应,
也就是说,默认的负载均衡是轮巡的模式
与dubbo相比,确实方便了很多