一、什么是分布式?
1.1 分布式框架
分布式系统是若干独立系统的集合,但是用户使用起来像是在使用一套系统。
1.2 分布式系统
规模的逐步扩大和业务的复杂,单台计算机抗不住过大流量
1.3 演变
1. 单一架构
- 当网站流量很小的时候,将所有一个用放到一台服务器上,打包运行公司管理系统/超市收银系统
- 优点:开发简单,部署简单
- 缺点:扩展性不容易,不易维护,性能难以提升
2. 垂直应用架构
- 将大应用拆分成为小应用(一般按照业务拆分),根据不同的访问频率决定各自业务部署的服务器数量
- 优点:拓展容易
- 缺点:页面一改,可能造成整个项目重新部署,业务和界面没有分离开,随业务种类增加,怎么解决业务之间的互相调用问题,订单服务器和用户服务器交互效率的问题
3. 分布式架构
- 将业务拆分后,用某种方式实现各个业务模块的远程调用和复用
- 基于RPC:远程过程调用
- dubbo阿里巴巴为了顶住双十一的流量而写的一个分布式的框架。各公司有各公司的分布式框架
- dubbo是一个高性能的RPC框架,解决了分布式中的调用问题
- 优点:解决了分布式系统中互相调用的问题
- 缺点:当用户服务器模块使用率小,但订单服务器模块使用率较高。需要有一个统一管理的调度中心去分配服务器的压力(zookeeper)
二、初识Dubbo
2.1 dubbo性能高的原因
从底层说起,一个RPC框架,主要是远程过程(方法)的调用,其中调用的过程中最关键、最耗时的两个方面就是:序列化和网络通信
-
序列化:本地对象想要在网络上传输,必须实现serializable接口。序列化的方案有:xml、json、二进制流…其中最高效率就是二进制流。Dubbo采用的就是效率最高的二进制。
-
网络通信:不同于HTTP需要进行7步走(三次握手和四次挥手),Dubbo采用Socket通信机制,一步到位,提升了通信效率,并且可以建立长连接,不用反复连接,直接传输数据
2.2 dubbo历史
- dubbo以往都是阿里内部使用框架
- 2011年,dubbo背托管到GitHub上(开源)
- 2014年,宣布停止。此后有一些公司基于dubbo生产出了很多dubbo的变种
- 2017年,随着SpringCloud推出,随后更新了几个版本
- 2018年,阿里将Dubbo捐给了Apache基金会。随后由Apache维护和更新,面向全球使用
2.3 dubbo概述
-
Apache Dubbo是一款高性能,轻量级的开源Java RPC框架,提供三大核心能离:面向接口的远程方法调用,智能容错和负载均衡,以及服务器自动注册和发现
三、Dubbo框架
3.1 基本架构
(官网提供)
节点 | 角色说明 |
---|---|
服务提供者(Provider) | 暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务 |
服务消费者(Consumer) | 调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败选择另外一台机器 |
注册中心(Registry) | 服务注册与发现的注册中心,注册返回服务提供者地址列表给消费者,如有变更,注册中心讲基于长连接推送变量数据给消费者 |
Monitor | 统计服务的调用次数和调用时间的监控中心,定时每分钟发送一次统计数据到监控中心 |
Container | 服务运行容器 |
3.2dubbo支持的协议
- 支持多种协议:dubbo,hessian,rmi,http,webservice,thrift,memcached,redis
- dubbo官方推荐使用dubbo协议。dubbo协议默认端口:20880
- 使用dubbo协议,spring配置文件中加入:
<dubbo:protocol name ="dubbo" port="20880"/>
四、直连方式(无注册中心)
1. 创建一个服务提供者
-
创建一个maven web工程:服务的提供者
-
创建一个实体bean查询的结构
-
提供一个服务接口:xxx
-
实现这个服务接口:xxxImpl
-
配置dubbo服务提供者的核心配置文件
- 声明dubbo服务提供者的名称:保证唯一
- 声明dubbo使用的协议和端口号
- 暴露服务,使用直连方式
-
添加Spring监听器
-
部分代码展示(dubbo的配置文件)
<!--服务的提供者声明名称:必须保证服务名称的唯一性,它的名称是dubbo内部使用的唯一标识-->
<dubbo:application name="Dubbo_01"/>
<!--访问服务协议的名称及端口号,dubbo官方推荐使用dubbo协议,端口号默认为20880-->
<!--
name:指定协议的名称
port:指定协议的端口号(默认为20880)
-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--暴露服务接口->dubbo:service
interface:表示暴露服务接口的全限定类名
ref:接口引用的实现类在spring容器中的标识
registry:如果不适用注册中心,则值为N/A
-->
<dubbo:service interface="com.aiit.dubbo.service.UserService" ref="userService" registry="N/A"/>
<!--将接口的实现类加载到spring容器中-->
<bean id="userService" class="com.aiit.dubbo.service.impl.UserServiceImpl"/>
<!---->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dubbo-userservice-provider.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2. 创建一个服务的消费者
-
创建一个maven web工程:服务的消费者
-
配置pom.xml文件:添加需要的依赖(spring,dubbo)
-
设置dubbo的核心配置文件
-
编写controller
-
因为dubbo面向接口,所以服务的消费者是需要知道提供者的接口。因此我们需要将服务提供者进行打包
-
将服务提供者引入到pom.xml文件中
<!--依赖服务提供者-->
<dependency>
<groupId>com.aiit.dubbo</groupId>
<artifactId>001-link-userservice-provider</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- 书写消费者配置文件
<!--声明服务消费者的名称:保证唯一性-->
<dubbo:application name="002-link-consumer"/>
<!--
引用远程服务接口:
id:远程服务接口对象名称
interface:调用远程接口的全限定类名
url:访问服务接口的地址
registry:不使用注册中心,值为N/A
-->
<dubbo:reference id="userService"
interface="com.aiit.dubbo.service.UserService"
url="dubbo://localhost:20880"
registry="N/A"/>
<!--扫描controller-->
<context:component-scan base-package="com.aiit.dubbo.controller"/>
<!--配置注解驱动-->
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
- 书写Controller通过接口去实现提供者的接口功能
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "/user")
public String userDetail(Model model,Integer id){
User user =this.userService.queryUserById(id);
model.addAttribute("user",user);
return "userDetail";
}
}
五、最佳服务实现
1. dubbo服务化最佳实践
1.1 分包
-
建议将服务接口,服务模型(Bean)放到公共包中。也就是我们必须创建一个业务接口工程,也就是一个maven工程。
-
里面放的内容分别是对外暴露的服务接口(service接口)和实体bean对象
1.2 粒度
-
服务接口尽可能大的粒度,每个服务方法代表一个功能,而非功能的一个步骤
-
服务接口建议以业务场景为单位划分,并对相对业务做抽象,防止接口数量爆炸
-
不建议使用过于抽象的通用接口,如Map Query(map),没有明确语义,给后期维护带来不便
1.3 版本
- 每个接口都应定义版本号,,区分同一个接口不同实现
2. 将直连方式代码升级
- 根据上面三个需要,我们使用dubbo官方推荐的模式,将实体bean和业务接口存放到接口工程中
3. 接口工程
- 只写接口和实体类
public interface UserService {
/*根据用户标识获取用户信息*/
User QueryUserById(Integer id);
/*查询用户数量*/
Integer QueryAllUserCount();
}
4. 业务提供者代码实现(部分)
- dubbo-userservice-provider.xml
<!--声明服务提供者-->
<dubbo:application name="004-link-userservice-provider"/>
<!--声明服务的协议-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--暴漏接口服务-->
<dubbo:service interface="com.aiit.dubbo.service.UserService" ref="userService" registry="N/A"/>
<!--接口实现类注入-->
<bean id="userService" class="com.aiit.dubbo.service.impl.UserServiceImpl"/>
- 实现接口
public class UserServiceImpl implements UserService {
@Override
public User QueryUserById(Integer id) {
User user = new User();
user.setId(id);
user.setUsername("zhangsan");
return user;
}
@Override
public Integer QueryAllUserCount() {
return 52;
}
}
5.服务消费者代码实现(部分)
- dubbo-consumer.xml文件
<!--保证服务的唯一性-->
<dubbo:application name="005-link-userservice-consumer"/>
<!--引入协议-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--引入远程接口服务-->
<dubbo:reference id="userService"
interface="com.aiit.dubbo.service.UserService"
url="dubbo://localhost:20880"
registry="N/A"/>
<!--接口实现类注入-->
<bean id="userService" class="com.aiit.dubbo.service.impl.UserServiceImpl"/>
- applicationContext.xml
<!--扫描组件Controller层-->
<context:component-scan base-package="com.aiit.dubbo.controller"/>
<!--配置注解驱动-->
<mvc:annotation-driven/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"/>
<property name="prefix" value="/"/>
</bean>
- Controller 层
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "/userDetail")
public String userDetail(Model model,Integer id){
//根据哟ing胡标识获取用户详情
User user = userService.QueryUserById(id);
//获取用户总任务
Integer allUserCount = userService.QueryAllUserCount();
model.addAttribute("user",user);
model.addAttribute("allUserCount",allUserCount);
return "userDetail";
}
}
六、注册中心——Zookeeper
6.1 概述
-
对于服务提供方,它需要发布服务,而且由于应用系统的复杂性。服务的数量和类型会不断膨胀,对于服务消费方,最关系是如何获取到它所需要的服务,而面对复杂的系统,需要管理大量的服务调用
-
对于服务提供方和服务消费方来说,有可能兼具两个角色,既需要提供服务,也需要消费服务。通过将服务统一管理起来,有效的优化内部应用对服务发布/使用的流程和管理
-
dubbo提供的注册中心有如下:
- Multicast注册中心:组播方式
- Redis注册中心:使用Redis作为注册中心
- Simple注册中心:一个dubbo服务,提供查找服务的功能
- Zookeeper注册中心:使用Zookeeper作为注册中心
-
简单来说:使用Zookeeper即可,相当于记事本,记录服务的提供者所提供服务的地址。不需要服务的消费者去特意指定某个服务
6.2zookeeper安装
-
上官网即可下载
-
在Windows下安装
- 在zookeeper目录下,新建一个data用于存放临时数据
-
添加参数,本身zookeeper在启动是会启动8080端口,但是8080端口我们会经常用,所以需要修改
-
双击bin下的zkServer,出现如下即说明成功
-
在Linux下安装
-
先将zookeeper上传到Linux中,并进行解压
-
新建文件夹data
-
修改里面的conf文件
-
-
运行zookeeper