作者: 鸭血粉丝  2020-05-19 08:15:16
开发
架构
分布式 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。

创新互联建站坚持“要么做到,要么别承诺”的工作理念,服务领域包括:网站建设、成都网站制作、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的海丰网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。
一、先来一张图
说起 Dubbo,相信大家都不会陌生!阿里巴巴公司开源的一个高性能优秀的服务框架,可以使得应用可通过高性能的 RPC 实现服务的输出和输入功能,同时可以和 Spring 框架无缝集成。
Dubbo 架构图
节点角色说明:
二、实现思路
今天,我们以一个用户选择商品下订单这个流程,将其拆分成3个业务服务:用户中心、商品中心、订单中心,使用 Springboot + Dubbo 来实现一个小 Demo!
服务交互流程如下:
本文主要是介绍 Springboot 与 Dubbo 的框架整合以及开发实践,而真实的业务服务拆分是一个非常复杂的过程,比我们介绍的这个要复杂的多,上文提到的三个服务只是为了项目演示,不必过于纠结为什么要这样拆分!
好了,废话也不多说了,下面我们开撸!
三、zookeeper安装
在使用 Dubbo 之前,我们需要一个注册中心,目前 Dubbo 可以选择的注册中心有 zookeeper、Nacos 等,一般建议使用 zookeeper!
首先在安装 Zookeeper 之前,需要安装并配置好 JDK,本机采用的是Oracle Java8 SE。
- yum -y install java-1.8.0-openjdk
 
- java -version
 
- #创建一个zookeeper文件夹
 - cd /usr
 - mkdir zookeeper
 - #下载zookeeper-3.4.14版本
 - wget http://mirrors.hust.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
 - #解压
 - tar -zxvf zookeeper-3.4.14.tar.gz
 
- #创建数据和日志存放目录
 - cd /usr/zookeeper/
 - mkdir data
 - mkdir log
 - #把conf下的zoo_sample.cfg备份一份,然后重命名为zoo.cfg
 - cd conf/
 - cp zoo_sample.cfg zoo.cfg
 
- #编辑zoo.cfg文件
 - vim zoo.cfg
 
- #进入Zookeeper的bin目录
 - cd zookeeper/zookeeper-3.4.14/bin
 - #启动Zookeeper
 - ./zkServer.sh start
 - #查询Zookeeper状态
 - ./zkServer.sh status
 - #关闭Zookeeper状态
 - ./zkServer.sh stop
 
出现如下信息,表示启动成功!
四、项目介绍
五、代码实践
5.1、初始化数据库
首先在 mysql 客户端,创建3个数据库,分别是:dianshang-user、dianshang-platform、dianshang-business。
5.2、创建工程
数据库表设计完成之后,在 IDEA 下创建一个名称为dianshang的Springboot工程。
最终的目录如下图:
目录结构说明:
在父类pom文件中加入dubbo和zookeeper客户端,所有依赖的项目都可以使用。
org.projectlombok lombok 1.18.4 provided org.apache.dubbo dubbo-spring-boot-starter 2.7.3 org.apache.zookeeper zookeeper 3.4.13 org.slf4j slf4j-api org.slf4j slf4j-log4j12 log4j log4j org.apache.curator curator-framework 4.2.0 org.apache.curator curator-recipes 4.2.0 
温馨提示:小编在搭建环境的时候,发现一个坑,工程中依赖的zookeeper版本与服务器的版本,需要尽量一致,例如,本例中zookeeper服务器的版本是3.4.14,那么在依赖zookeeper文件库的时候,也尽量保持一致,如果依赖3.5.x版本的zookeeper,项目在启动的时候会各种妖魔鬼怪的报错!
5.3、创建用户中心项目
在 IDEA 中,创建dianshang-user子模块,并依赖dianshang-common模块
org.project.demo dianshang-common 1.0.0 
同时,创建dianshang-user-provider和dianshang-user-api模块。
5.3.1、配置dubbo服务
在dianshang-user-provider的application.yml文件中配置dubbo服务,如下:
- #用户中心服务端口
 - server:
 - port: 8080
 - #数据源配置
 - spring:
 - datasource:
 - druid:
 - driver-class-name: com.mysql.cj.jdbc.Driver
 - url: "jdbc:mysql://localhost:3306/dianshang-user"
 - username: root
 - password: 111111
 - #dubbo配置
 - dubbo:
 - scan:
 - # 包名根据自己的实际情况写
 - base-packages: org.project.dianshang.user
 - protocol:
 - port: 20880
 - name: dubbo
 - registry:
 - #zookeeper注册中心地址
 - address: zookeeper://192.168.0.107:2181
 
5.3.2、编写服务暴露接口以及实现类
在dianshang-user-api模块中,创建一个UserApi接口,以及返回参数对象UserVo!
- public interface UserApi {
 - /**
 - * 查询用户信息
 - * @param userId
 - * @return
 - */
 - UserVo findUserById(String userId);
 - }
 
其中UserVo,需要实现序列化,如下:
- @Data
 - @EqualsAndHashCode(callSuper = false)
 - @Accessors(chain = true)
 - public class UserVo implements Serializable {
 - private static final long serialVersionUID = 1L;
 - /**
 - * 用户ID
 - */
 - private String userId;
 - /**
 - * 用户中文名
 - */
 - private String userName;
 - }
 
在dianshang-user-provider模块中,编写UserApi接口实现类,如下:
- @Service(interfaceClass =UserApi.class)
 - @Component
 - public class UserProvider implements UserApi {
 - @Autowired
 - private UserService userService;
 - @Override
 - public UserVo findUserById(String userId) {
 - QueryWrapper
 queryWrapper = new QueryWrapper (); - queryWrapper.eq("user_id",userId);
 - User source = userService.getOne(queryWrapper);
 - if(source != null){
 - UserVo vo = new UserVo();
 - BeanUtils.copyProperties(source,vo);
 - return vo;
 - }
 - return null;
 - }
 - }
 
其中的注解@Service指的是org.apache.dubbo.config.annotation.Service下的注解,而不是Spring下的注解哦!
接着,我们继续创建商品中心项目!
5.4、创建商品中心项目
与用户中心项目类似,在 IDEA 中,创建dianshang-platform子模块,并依赖dianshang-common模块
org.project.demo dianshang-common 1.0.0 
同时,创建dianshang-platform-provider和dianshang-platform-api模块。
5.4.1、配置dubbo服务
在dianshang-platform-provider的application.yml文件中配置dubbo服务,如下:
- #用户中心服务端口
 - server:
 - port: 8081
 - #数据源配置
 - spring:
 - datasource:
 - druid:
 - driver-class-name: com.mysql.cj.jdbc.Driver
 - url: "jdbc:mysql://localhost:3306/dianshang-platform"
 - username: root
 - password: 111111
 - #dubbo配置
 - dubbo:
 - scan:
 - # 包名根据自己的实际情况写
 - base-packages: org.project.dianshang.platform
 - protocol:
 - port: 20881
 - name: dubbo
 - registry:
 - #zookeeper注册中心地址
 - address: zookeeper://192.168.0.107:2181
 
5.4.2、编写服务暴露接口以及实现类
在dianshang-platform-api模块中,创建一个ProductApi接口,以及返回参数对象ProductVo!
- public interface ProductApi {
 - /**
 - * 通过商品ID,查询商品信息
 - * @param productId
 - * @return
 - */
 - ProductVo queryProductInfoById(String productId);
 - }
 
其中ProductVo,需要实现序列化,如下:
- @Data
 - @EqualsAndHashCode(callSuper = false)
 - @Accessors(chain = true)
 - public class ProductVo implements Serializable {
 - private static final long serialVersionUID = 1L;
 - /**商品ID*/
 - private String productId;
 - /**商品名称*/
 - private String productName;
 - /**商品价格*/
 - private BigDecimal productPrice;
 - }
 
在dianshang-platform-provider模块中,编写ProductApi接口实现类,如下:
- @Service(interfaceClass = ProductApi.class)
 - @Component
 - public class ProductProvider implements ProductApi {
 - @Autowired
 - private ProductService productService;
 - @Override
 - public ProductVo queryProductInfoById(String productId) {
 - //通过商品ID查询信息
 - Product source = productService.getById(productId);
 - if(source != null){
 - ProductVo vo = new ProductVo();
 - BeanUtils.copyProperties(source,vo);
 - return vo;
 - }
 - return null;
 - }
 - }
 
接着,我们继续创建订单中心项目!
5.5、创建订单中心项目
与商品中心项目类似,在 IDEA 中,创建dianshang-business子模块,并依赖dianshang-common模块
org.project.demo dianshang-common 1.0.0 
同时,创建dianshang-business-provider和dianshang-business-api模块。
5.5.1、配置dubbo服务
在dianshang-business-provider的application.yml文件中配置dubbo服务,如下:
- #用户中心服务端口
 - server:
 - port: 8082
 - #数据源配置
 - spring:
 - datasource:
 - druid:
 - driver-class-name: com.mysql.cj.jdbc.Driver
 - url: "jdbc:mysql://localhost:3306/dianshang-business"
 - username: root
 - password: 111111
 - #dubbo配置
 - dubbo:
 - scan:
 - # 包名根据自己的实际情况写
 - base-packages: org.project.dianshang.business
 - protocol:
 - port: 20882
 - name: dubbo
 - registry:
 - #zookeeper注册中心地址
 - address: zookeeper://192.168.0.107:2181
 
5.5.2、编写服务暴露接口以及实现类
在dianshang-business-api模块中,创建一个OrderApi接口,以及返回参数对象OrderVo!
- public interface OrderApi {
 - /**
 - * 通过用户ID,查询用户订单信息
 - * @param userId
 - * @return
 - */
 - List
 queryOrderByUserId(String userId); - }
 
其中OrderVo,需要实现序列化,如下:
- @Data
 - @EqualsAndHashCode(callSuper = false)
 - @Accessors(chain = true)
 - public class OrderVo implements Serializable {
 - private static final long serialVersionUID = 1L;
 - /**订单ID*/
 - private String orderId;
 - /**订单编号*/
 - private String orderNo;
 - /**订单金额*/
 - private BigDecimal orderPrice;
 - /**下单时间*/
 - private Date orderTime;
 - }
 
在dianshang-business-provider模块中,编写OrderApi接口实现类,如下:
- @Service(interfaceClass = OrderApi.class)
 - @Component
 - public class OrderProvider implements OrderApi {
 - @Autowired
 - private OrderService orderService;
 - @Override
 - public List
 queryOrderByUserId(String userId) { - QueryWrapper
 queryWrapper = new QueryWrapper (); - queryWrapper.eq("user_id",userId);
 - List
 sourceList = orderService.list(queryWrapper); - if(!CollectionUtils.isEmpty(sourceList)){
 - List
 voList = new ArrayList<>(); - for (Order order : sourceList) {
 - OrderVo vo = new OrderVo();
 - BeanUtils.copyProperties(order, vo);
 - voList.add(vo);
 - }
 - return voList;
 - }
 - return null;
 - }
 - }
 
至此,3个项目的服务暴露接口已经开发完成!接下来我们来编写怎么进行远程调用!
5.6、远程调用
5.6.1、编写创建订单服务
在dianshang-business-provider模块中,编写创建订单接口之前,先依赖dianshang-business-api和dianshang-user-api,如下:
org.project.demo dianshang-platform-api 1.0.0 org.project.demo dianshang-user-api 1.0.0 
在dianshang-business-provider模块中,编写创建订单服务,如下:
- @RestController
 - @RequestMapping("/order")
 - public class OrderController {
 - @Autowired
 - private OrderService orderService;
 - @Autowired
 - private OrderDetailService orderDetailService;
 - @Reference(check =false)
 - private ProductApi productApi;
 - @Reference(check =false)
 - private UserApi userApi;
 - /**
 - * 新增
 - */
 - @JwtIgnore
 - @RequestMapping(value = "/add")
 - public boolean add(String productId,String userId){
 - LocalAssert.isStringEmpty(productId,"产品Id不能为空");
 - LocalAssert.isStringEmpty(userId,"用户Id不能为空");
 - ProductVo productVo = productApi.queryProductInfoById(productId);
 - LocalAssert.isObjectEmpty(productVo,"未查询到产品信息");
 - UserVo userVo = userApi.findUserById(userId);
 - LocalAssert.isObjectEmpty(userVo,"未查询到用户信息");
 - Order order = new Order();
 - order.setOrderId(IdGenerator.uuid());
 - order.setOrderNo(System.currentTimeMillis() + "");
 - order.setOrderPrice(productVo.getProductPrice());
 - order.setUserId(userId);
 - order.setOrderTime(new Date());
 - orderService.save(order);
 - OrderDetail orderDetail = new OrderDetail();
 - orderDetail.setOrderDetailId(IdGenerator.uuid());
 - orderDetail.setOrderId(order.getOrderId());
 - orderDetail.setProductId(productId);
 - orderDetail.setSort(1);
 - orderDetailService.save(orderDetail);
 - return true;
 - }
 - }
 
其中的@Reference注解,是属于org.apache.dubbo.config.annotation.Reference下的注解,表示远程依赖服务。
参数check =false表示启动服务时,不做远程服务状态检查,这样设置的目的就是为了防止当前服务启动不了,例如用户中心项目没有启动成功,但是订单中心又依赖了用户中心,如果check=true,此时订单中心启动会报错!
5.6.2、编写用户查询自己的订单信息
同样的,在dianshang-user-provider模块中,编写用户查询自己的订单信息接口之前,先依赖dianshang-business-api和dianshang-user-api,如下:
org.project.demo dianshang-business-api 1.0.0 org.project.demo dianshang-user-api 1.0.0 
在dianshang-user-provider模块中,编写用户查询自己的订单信息接口,如下:
- @RestController
 - @RequestMapping("/user")
 - public class UserController {
 - @Reference(check =false)
 - private OrderApi orderApi;
 - /**
 - * 通过用户ID,查询订单信息
 - * @param userId
 - * @return
 - */
 - @RequestMapping("/list")
 - public List
 queryOrderByUserId(String userId){ - return orderApi.queryOrderByUserId(userId);
 - }
 - }
 
至此,远程服务调用,编写完成!
六、服务测试
在将项目部署在服务器之前,咱们先本地测试一下,看服务是否都可以跑通?
接着启动订单中心dianshang-business-provider
最后,我们来测试一下服务接口是否为我们预期的结果?
打开浏览器,输入http://127.0.0.1:8082/order/add?productId=1&userId=1测试创建订单接口,页面运行结果显示正常!
我们再来看看数据库,订单是否生成?
ok!很清晰的看到,数据已经进去了,没啥问题!
我们再来测试一下在用户中心订单查询接口,输入http://127.0.0.1:8080/user/list?userId=1,页面运行结果如下!
到此,本地服务测试基本通过!
七、服务器部署
在上文中,我们介绍了服务的构建、开发和测试,那如何在服务器端部署呢?
首先,修改各个项目的application.yml文件,将其中的数据源地址、dubbo注册中心地址修改为线上能联通的地址,然后在dianshang目录下使用maven工具对整个工程执行如下命令进行打包!
- mvn clean install
 
也可以在 IDEA 环境下,通过maven配置clean install命令执行打包。
将各个项目target目录下的dianshang-user-provider.jar、dianshang-platform-provider.jar、dianshang-business-provider.jar拷贝出来。
分别上传到对应的服务器目录,本服务器采用的是 CentOS7,总共4台服务器,其中一台部署zookeeper,另外三台部署三个微服务项目。
登录服务器,输入如下命令,确保JDK已经安装完成!
- java -version
 
关闭所有服务器的防火墙,放行端口访问!
- #关闭防火墙
 - systemctl stop firewalld.service
 - #禁止开机启动
 - systemctl disable firewalld.service
 
- nohup java -jar dianshang-user-provider.jar > service.log 2>&1 &
 
- nohup java -jar dianshang-platform-provider.jar > service.log 2>&1 &
 
- nohup java -jar dianshang-business-provider.jar > service.log 2>&1 &
 
打开浏览器,输入http://192.168.0.109:8082/order/add?productId=1&userId=1测试创建订单接口,页面运行结果显示正常!
我们再来测试一下在用户中心订单查询接口,输入输入http://192.168.0.108:8080/user/list?userId=1,页面运行结果如下!
很清晰的看到,输出了2条信息,第二条订单是在测试环境服务器生成的,第一条是本地开发环境生成的。
到此,服务器部署基本已经完成!
如果是生产环境,可能就需要多台zookeeper来保证高可用,至少2台服务器来部署业务服务,通过负载均衡来路由!
八、总结
整片文章比较长,主要是围绕 springboot + dubbo 的整合,通过注解开发实现远程服务调用像传统的 springmvc 开发一样轻松,当然还可以通过xml配置方式实现dubbo服务的调用,这个会在后期去介绍。
同时也介绍了服务器的部署,从中可以看出,开发虽然简单,但是由于分布式部署,如何保证服务高可用成了开发人员头等工作任务,所以,分布式微服务开发虽然开发简单,但是如何确保部署的服务高可用?运维方面会带来不少的挑战!
九、参考
1、apache - dubbo - 官方文档
                文章题目:利用Springboot+Dubbo,构建分布式微服务,全程注解开发
                
                本文URL:http://www.csdahua.cn/qtweb/news44/248094.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网