分布式、RPC、Dubbo
分布式或者说 SOA 分布式重要的就是面向服务,说简单的分布式就是我们把整个系统拆分成不同的服务然后将这些服务放在不同的服务器上减轻单体服务的压力提高并发量和性能。比如电商系统可以简单地拆分成订单系统、商品系统、登录系统等等。
RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。比如两个不同的服务A,B部署在两台不同的机器上,那么服务 A 如果想要调用服务 B 中的某个方法该怎么办呢?使用 HTTP请求 当然可以,但是可能会比较慢而且一些优化做的并不好。RPC 的出现就是为了解决这个问题。
Apache Dubbo 是一款高性能、轻量级的开源Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用、智能容错和负载均衡、以及服务自动注册和发现。简单来说 Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
Dubbo 的架构,Dubbo 官方推荐使用 zookeeper 作为注册中心
上述节点简单说明:
调用关系说明:
其实开发分布式程序,也可以直接基于 HTTP 接口进行通信,但是为什么要用 Dubbo呢?
主要可以从 Dubbo 提供的下面四点特性来说为什么要用 Dubbo:
下载链接:http://archive.apache.org/dist/zookeeper/
进入apache-zookeeper-3.5.6-bin目录
在apache-zookeeper-3.5.6-bin目录下创建data目录
在conf目录下将 zoo_sample.cfg 文件复制一份改名为 zoo.cfg
修改dataDir的值改为
dataDir=../data
进入bin目录下启动服务端,在地址输入cmd回车,输入zkServer.cmd回车启动服务端
同样的方式打开一个dos窗口输入,输入zkCli.cmd启动客户端启动,在客户端输入几个命令看是否启动成功
ls / :查看节点
create -e /test 123456:创建节点
get /test:获取节点
Linux环境: CentOS 7.4
注意:如果是阿里云服务器必须配置一个安全组,不然应用程序会无法访问zookeeper 服务器
我使用的是 CentOS 7.4 阿里云服务器,注意:如果你也同样阿里云服务器必须配置一个安全组,不然你的应用程序会无法访问你的 zookeeper 服务器,这一点我在后面也提到了。
下载链接: http://mirror.bit.edu.cn/apache/zookeeper/
下载完成后上传到Linux上
或者直接在Linux中使用 wget https://archive.apache.org/dist/zookeeper/zookeeper-3.5.6/zookeeper-3.5.6.tar.gz
命令下载
tar -zxvf zookeeper-3.5.6.tar.gz
解压完毕之后修改一下解压之后所得的文件夹名
mv zookeeper-3.5.6 zookeeper
删除 zookeeper 安装包
rm -rf zookeeper-3.5.6.tar.gz
进入zookeeper目录,创建data文件夹
mkdir data
进入 data 文件夹 然后执行pwd
命令,复制所得的当前目录位置
进入/zookeeper/conf目录下,复制zoo_sample.cfg,命名为zoo.cfg
cp zoo_sample.cfg zoo.cfg
使用 vim zoo.cfg
命令修改配置文件
vim 文件------>进入文件----->命令模式------>按i进入编辑模式----->编辑文件 ------->按Esc进入底行模式----->输入:wq/q! (输入wq代表写入内容并退出,即保存;输入q!代表强制退出不保存。)
修改配置文件中的 data 属性:
dataDir=/usr/local/zookeeper/data
进入 /zookeeper/bin 目录然后执行下面的命令
./zkServer.sh start
执行 ./zkServer.sh status
查看当前 zookeeper 状态。
或者运行 netstat -lntup
命令查看网络状态,可以看到 zookeeper 的端口号 2181 已经被占用
注意没有关闭防火墙可能出现的问题!!!
如果使用的是阿里云服务器,注意配置相关安全组:
进入本实例安全组页面
选择配置规则
选择添加安全组规则,然后按照下图配置
某个电商系统,订单服务需要调用用户服务获取某个用户的信息
模块 | 功能 |
---|---|
订单服务Web模块 | 创建订单等 |
用户服务Service模块 | 查询用户信息等 |
测试预期结果:订单服务Web模块在A服务器,用户服务模块在B服务器,A可以远程调用B的功能
建议将服务接口、服务模型、服务异常等均放在 API 包中;
在搭建项目时建议将接口项目、服务提供者以及服务消费者都放在同一空包下
根据Dubbo官方文档服务最佳实践
最终项目样式
1、将服务提供者注册到注册中心(暴露服务)
2、让服务消费者从注册中心订阅服务提供者的服务地址(消费服务)
作用:用于将接口项目、服务提供者以及服务消费者都放在同一空包下
File–>New–>Project–>Empty Project
作用:dubbo-interface 会被打成 jar 包,它的作用只是提供接口。
主要步骤:
1. 创建 Maven 项目;
2. 创建接口类
3. 将项目打成 jar 包供其他项目使用
File->New->Module… ,然后选择Maven类型的项目,其他的按照提示一步一步走就好。
<project xmlns&#61;"http://maven.apache.org/POM/4.0.0"xmlns:xsi&#61;"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&#61;"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0modelVersion><groupId>com.shiorygroupId><artifactId>dubbo-interfaceartifactId><version>1.0-SNAPSHOTversion><packaging>jarpackaging><dependencies><dependency><groupId>org.projectlombokgroupId><artifactId>lombokartifactId><version>1.18.10version><scope>providedscope>dependency>dependencies>project>
实体类&#xff0c;需要进行序列化&#xff0c;不然无法调用&#xff0c;实现Serializable接口即可
import lombok.Data;
import java.io.Serializable;/*** 用户信息实体类* &#64;author 汐小旅Shiory* &#64;Date 2019年10月31日10:06:09*/
&#64;Data
public class User implements Serializable {/*** 用户id*/private Long id;/*** 用户名*/private String username;/*** 用户密码*/private String password;/*** 用户收货地址*/private String address;public User(){}public User(Long id, String username, String password, String address){this.id &#61; id;this.username &#61; username;this.password &#61; password;this.address &#61; address;}
}
接口
/*** 用户服务接口* &#64;author 汐小旅Shiory* &#64;Date 2019年10月31日10:07:25*/
public interface UserService {/*** 根据用户id查询用户信息* &#64;param uid* &#64;return*/public User queryUserById(long uid);
}
/*** 订单服务接口* &#64;author 汐小旅Shiory* &#64;Date 2019年10月31日10:13:25*/
public interface OrderService {/*** 创建订单* &#64;param userId*/public User createOrder(long userId);
}
将项目打成 jar 包&#xff0c;安装到maven仓库供其他项目使用
点击右边的 Maven 然后选择Lifecycle --> install &#xff0c;这样 jar包安装到maven仓库了。
作用&#xff1a;用于提供服务供服务消费者使用
主要步骤&#xff1a;
1. 创建springboot项目;
2. 加入dubbo、zookeeper以及接口的相关依赖 jar 包&#xff1b;
3. 在application.properties 配置文件中配置 dubbo 相关信息&#xff1b;
4. 实现接口类;
5. 服务提供者启动类编写
注意在项目创建之前不要选中dubbo-interface&#xff0c;不然就会是在dubbo-interface上创建项目&#xff0c;所以选中非dubbo-interface的位置
File->New->Module… ,然后选择 Spring Initializr类型的项目
此步注意勾选上 web 模块
需要引入 dubbo 、zookeeper以及接口的相关依赖 jar 包。
注意将本项目和 dubbo-interface 项目的 dependency 依赖的 groupId 和 artifactId 改成自己的。dubbo 整合spring boot 的 jar 包可在下面链接中找到dubbo-spring-boot-starter。注意是阿里巴巴的dubbo
https://mvnrepository.com/artifact/com.alibaba.boot/dubbo-spring-boot-starter
其中dubbo-spring-boot-starter的0.2.0版本已经包含了zookeeper的客户端操作依赖&#xff0c;所以无需再添加。
也可以从dubbo的github上找到&#xff0c;根据对应的SpringBoot版本导入对应的dubbo依赖&#xff0c;此处使用的SpringBoot版本是2.x版本&#xff0c;由于高版本会有很多问题&#xff0c;此处不使用0.2.1.RELEASE版本&#xff0c;而使用0.2.0&#xff0c;
链接&#xff1a;https://github.com/apache/dubbo-spring-boot-project
pom文件中的依赖
<dependencies><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-webartifactId>dependency><dependency><groupId>com.shiorygroupId><artifactId>dubbo-interfaceartifactId><version>1.0-SNAPSHOTversion>dependency><dependency><groupId>com.alibaba.bootgroupId><artifactId>dubbo-spring-boot-starterartifactId><version>0.2.0version>dependency>dependencies>
在 application.properties 配置文件中配置 dubbo 相关信息
配置很简单&#xff0c;这主要得益于 springboot 整合 dubbo 专属的&#64;EnableDubbo
注解提供的 Dubbo 自动配置。
# 应用服务端口
server.port&#61;8081# 1.指定当前服务的名称/应用名称(同样的服务名称相同&#xff0c;不要和别的服务同名)
dubbo.application.name&#61;dubbo-provider
# 2.指定注册中心的位置(协议、地址&#xff1a;IP:端口)
dubbo.registry.protocol&#61;zookeeper
dubbo.registry.address&#61;127.0.0.1:2181
# 3.指定通信规则(通信协议、通信端口)
dubbo.protocol.name&#61;dubbo
dubbo.protocol.port&#61;20880
# 4.连接监控中心(使用协议的方式&#xff1a;让它自己从注册中心发现)
#dubbo.monitor.protocol&#61;registry
# 5.暴露服务&#xff1a;在Service接口实现类中使用dubbo中的&#64;Service注解&#xff0c;再加上一个Spring的&#64;Component注解用于将实现类加到容器中
# 6.开启基于注解的Dubbo功能&#xff1a;在主程序类中加入&#64;EnableDubbo注解
注意&#xff1a; &#64;Service 注解使用的时 Dubbo 提供的而不是 Spring 提供的。另外&#xff0c;加了Dubbo 提供的 &#64;Service
注解之后还需要加入Spring的&#61;&#61;&#64;Component&#61;&#61;注解
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;/*** 用户服务提供者实现用户接口* &#64;author 汐小旅Shiory* &#64;Date 2019年10月31日10:39:54*/&#64;Service //暴露服务&#xff1a;用Dubbo中的&#64;Service注解&#xff0c;而不是Spring中的&#64;Service注解
&#64;Component("userService")
public class UserServiceImpl implements UserService {&#64;Overridepublic User queryUserById(long uid) {//模拟从数据库查询到的用户信息if (uid &#61;&#61; 2L) {User user &#61; new User(2L,"admin","123456","杭州");return user;}return new User();}
}
注意&#xff1a;不要忘记加上 &#64;EnableDubbo 注解开启基于注解Dubbo功能。
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;&#64;EnableDubbo //开启基于注解的Dubbo功能
&#64;SpringBootApplication
public class DubboProviderApplication {public static void main(String[] args) {SpringApplication.run(DubboProviderApplication.class, args);}}
作用&#xff1a;用于消费服务(远程调用服务)
主要步骤&#xff1a;
1. 创建springboot项目;
2. 加入dubbo、zookeeper以及接口的相关依赖 jar 包&#xff1b;
3. 在application.properties 配置文件中配置 dubbo 相关信息&#xff1b;
4. 实现接口类;
5. 服务提供者启动类编写
和提供者创建一致
和提供者的pom文件中的依赖一致
# 应用服务端口
server.port&#61;8082# 1.指定当前服务的名称/应用名称(同样的服务名称相同&#xff0c;不要和别的服务同名)
dubbo.application.name&#61;dubbo-consumer
# 2.指定注册中心的位置(协议、地址)
dubbo.registry.protocol&#61;zookeeper
dubbo.registry.address&#61;127.0.0.1:2181
# 3.指定通信规则(通信协议、通信端口)
dubbo.protocol.name&#61;dubbo
dubbo.protocol.port&#61;20880
# 4.连接监控中心(使用协议的方式&#xff1a;让它自己从注册中心发现)
#dubbo.monitor.protocol&#61;registry
# 5.调用远程服务&#xff1a;使用&#64;Reference注解注入远程服务
# 6.开启基于注解的Dubbo功能&#xff1a;在主程序类中加入&#64;EnableDubbo注解
在Order接口的实现类中调用远程服务&#xff08;也可以在Controller层调用&#xff09;&#xff0c;使用&#61;&#61;&#64;Reference&#61;&#61;注解注入远程服务
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;/*** 订单服务层* &#64;author 汐小旅Shiory* &#64;Date 2019年10月31日13:28:17*/
&#64;Service("orderService")
public class OrderServiceImpl implements OrderService {/*** 使用&#64;Reference注解注入远程服务*/&#64;Reference(interfaceName &#61; "userService")private UserService userService;&#64;Overridepublic User createOrder(long userId) {// 远程调用UserService(服务提供者)User user &#61; userService.queryUserById(userId);return user;}
}
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;/*** 订单服务web层* &#64;author 汐小旅Shiory* &#64;Date 2019年10月31日13:24:58*/
&#64;RequestMapping("/order")
&#64;RestController
public class OrderController {&#64;Resource(name &#61; "orderService")private OrderService orderService;&#64;GetMapping(value &#61; "{uid}")public ResponseEntity<User> createOrder(&#64;PathVariable("uid") long userId){User user &#61; orderService.createOrder(userId);if (user &#61;&#61; null) {return ResponseEntity.notFound().build();}return ResponseEntity.ok(user);}
}
注意&#xff1a;不要忘记加上 &#64;EnableDubbo 注解开启基于注解Dubbo功能。
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;&#64;EnableDubbo //开启基于注解的Dubbo功能
&#64;SpringBootApplication
public class DubboConsumerApplication {public static void main(String[] args) {SpringApplication.run(DubboConsumerApplication.class, args);}
}
保证zookeeper已经启动&#xff0c;启动dubbo-provider、dubbo-consumer
浏览器访问 http://localhost:8082/order/2&#xff0c;页面输出 User的信息&#xff0c;测试成功