分布式应用
应用架构的变迁
1、单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
2、垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
3、分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
4、流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
在分布式系统中,国内常用zookeeper+dubbo组合,而Spring Boot推荐使用全栈的Spring,Spring Boot+Spring Cloud
ZooKeeper和Dubbo
1、ZooKeeper
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
2、Dubbo
Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
Dubbo + ZooKeeper 示例
1、安装Zookeeper
①查看本地是否有Zookeeper的镜像
docker images
②加速下载Zookeeper
docker pull registry.docker-cn.com/library/zookeeper
如果加速下载不成功的话,可以不使用加速:
docker pull zookeeper
③运行Zookeeper:
docker run --name zk01 -p 2181:2181 --restart always -d 2a7f6fc5c8a1
2、创建服务提供者和服务消费者
①创建一个空项目dubbo_zk:此处只是为了展示方便,将服务提供者和服务消费者放在同一个空项目下
②在空项目下创建一个SpringBoot模块作为服务提供者provider_ticket
③在空项目下再创建一个SpringBoot模块作为服务消费者consumer_user
④在两个模块中都引入dubbo和zkclient的依赖
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
⑤在服务提供者中编写服务接口和服务实现
接口:
package com.bdm.ticket.service;
public interface TicketService {
public String getTicket();
}
实现:
package com.bdm.ticket.service.impl;
import com.bdm.ticket.service.TicketService;
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "《霸王别姬》";
}
}
⑥在Zookeeper中通过dubbo暴露服务,只需要在主配置文件文件中进行如下配置:
配置:
#bubbo应用名
dubbo.application.name=provider_ticket
#zookeeper服务器地址和端口
dubbo.registry.address=zookeeper://192.168.2.107:2181
#暴露的服务所在的包,该包下的接口若有使用dubbo的@Service注解的接口实现则会暴露为dubbo服务
dubbo.scan.base-packages=com.bdm.ticket.service
实现类加dubbo的@Service注解,并将该类纳入Spring容器:
package com.bdm.ticket.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.bdm.ticket.service.TicketService;
import org.springframework.stereotype.Component;
@Component //将实现纳入IOC
@Service //注意该注解是dubbo提供的注解,在com.alibaba.dubbo.config.annotation.Service包下
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "《霸王别姬》";
}
}
⑦将服务提供者的接口定义(不需要拷贝接口实现)复制一份到服务消费者项目consumer_user中,注意包名和接口名等要完全一致,这是因为dubbo识别服务靠的是包名,而不像SpringCloud靠的是应用名和Http接口名
⑧在服务消费者中配置dubbo:由于不需要暴露服务,只需要配置zookeeper地址和端口即可,也就是说只要配置了dubbo.registry.address就可以实现服务订阅,因此服务提供者肯定也实现了服务订阅
#bubbo应用名
dubbo.application.name=consumer_user
#zookeeper服务器地址和端口
dubbo.registry.address=zookeeper://192.168.2.107:2181
⑨在服务消费者中使用dubbo订阅远程服务:使用dubbo提供的@Reference注解,注意包名
package com.bdm.user.service;
import com.alibaba.dubbo.config.annotation.Reference;
import com.bdm.ticket.service.TicketService;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Reference //使用dubbo提供的该注解订阅服务
TicketService ticketService;
public void getTicket() {
String ticket = ticketService.getTicket();
System.out.println(ticket);
}
}
⑩测试:先启动服务提供者,再在服务消费者中调用getTikcet()
@RunWith(SpringRunner.class)
@SpringBootTest
public class ConsumerUserApplicationTests {
@Autowired
UserService userService;
@Test
public void contextLoads() {
userService.getTicket();
}
}
在服务消费者的控制台中可以看到打印结果
dubbo + zookeeper的远程服务调用流程
1、服务提供者中配置了zookeeper的服务地址和端口以及暴露服务的包,这样在服务提供者启动时会将需要暴露的服务注册至zookeeper,这些暴露的服务必须要有使用dubbo的@Service注解的实现
2、服务消费者中也配置了zookeeper的服务地址和端口,这样服务消费者启动后就可以从zookeeper中获取到服务的远程实现,为了区别是使用本地实现(消费者端也可以提供本地实现)还是使用远程实现,在使用远程实现时需要使用dubbo的@Reference注解标明
3、服务消费者在消费服务的时候是根据包名或者说接口的全类名来区别服务的实现的,如果有多个该服务的实现的话,就会负载均衡算法进行调度,或者根据分组明确指定调用哪个服务实现