Dubbo微服务影院系列(12):系统部署

运行环境 CentOS 6 云服务器 创建用户 创建一个 cinema 用户: [root@huawei ~]# useradd cinema [root@huawei ~]# passwd cinema Changing password for user cinema. New password: BAD PASSWORD: it does not contain enough DIFFERENT characters Retype new password: passwd: all authentication tokens updated successfully. 给予其权限,首先需要赋予当前用户对 /etc/sudoers 的写权限,然后在 sudoers 文件中的 root ALL = (ALL) ALL 下增加一行,赋予其在任何地方执行任何命令的权限: chmod u+w /etc/sudoers vim sudoers ## Allow root to run any commands anywhere root ALL=(ALL) ALL cinema ALL=(ALL) ALL 最后,取消当前用户的写权限: ...

May 3, 2020 · 4 min

Dubbo微服务影院系列(11):服务监控

章节概要 了解 Dubbo 监控相关内容 熟练掌握 Dubbo-admin 使用 熟练掌握链路监控 完成业务系统部署 Dubbo-monitor 源码下载和打包 目前,还可以从当当网的项目 Dubbox 中获取(很久没有维护了):https://github.com/dangdangdotcom/dubbox ,在项目中执行以下命令打包并拷贝到本地仓库(跳过单元测试): mvn package -Dmaven.test.skip=true 其中,可能会遇到 Missing artifact com.alibaba:dubbo:jar:2.8.4 的坑,需要在根项目的 pom.xml 文件中添加以下 maven 插件: 这样在本地仓库就有了 ~/.m2/repository/com/alibaba/dubbo-monitor-simple/2.8.4/dubbo-monitor-simple-2.8.4-assembly.tar.gz 这个 tar.gz 包,解压它可以得到以下文件: 启动服务监控 在 conf 文件夹下,编辑 dubbo.properties,将相关参数配置如下: dubbo.container=log4j,spring,registry,jetty dubbo.application.name=simple-monitor dubbo.application.owner= #dubbo.registry.address=multicast://224.5.6.7:1234 dubbo.registry.address=zookeeper://127.0.0.1:2181 #dubbo.registry.address=redis://127.0.0.1:6379 #dubbo.registry.address=dubbo://127.0.0.1:9090 dubbo.protocol.port=7070 dubbo.jetty.port=8090 dubbo.jetty.directory=monitor dubbo.charts.directory=monitor/charts dubbo.statistics.directory=monitor/statistics dubbo.log4j.file=monitor/dubbo-monitor-simple.log dubbo.log4j.level=WARN 然后,进入 bin 目录,运行 start.sh 就可以启动 Dubbo-Monitor 了,运行在配置好的 8090 端口(需要先打开 Zookeeper)。 启动服务提供者和消费者后,可以在 Applications 中看到如下信息: 同时,可以点击 Providers 查看服务某一服务提供者的详细信息,并且可以将其取消注册: ...

April 24, 2020 · 3 min

Dubbo微服务影院系列(10):分布式事务

章节概要 事务简介 分布式事务的前世今生 分布式事务解决方案 主流分布式事务框架介绍 事务简介 事务是用来保证一组数据操作的完整性和一致性的 事务必须满足 ACID 的四大特性 事务具有四种隔离级别 事务具有七种传播行为 事务属性 原子性(Atomicity) 一致性(Consistency) 隔离型(Isolation) 持久性(Durability) 分布式事务 概念 分布式事务就是将多个节点的事务看成一个整体处理 分布式事务由事务参与者、资源服务器、事务管理器等组成 常见的分布式事务的例子:支付、下订单等 实现思路 两段式事务和三段式事务 基于 XA 的分布式事务 基于消息的最终一致性方案 TCC 编程式补偿性事务 分布式事务类型 两段式和三段式事务 两段式事务 三段式事务 基于 XA 的分布式事务 基于消息的一致性方案 TCC 补偿性事务 基于消息的一致性方案和 TCC 补偿性事务的区别 基于消息的事务是强一致性事务,会存在浪费 TCC 事务是柔性事务,在 try 阶段要对资源做预留 TCC 事务在确认或取消阶段释放资源 与基于消息的事务对比,TCC 的时效性更好 分布式事务框架 全局事务服务(Global Transaction Service,简称 GTS) 蚂蚁金服分布式事务(Distributed Transaction-eXtended,简称 DTX) 开源 TCC 框架(TCC-Transaction)(https://github.com/changmingxie/tcc-transaction) 开源 TCC 框架(ByteTCC)(https://github.com/liuyangming/ByteTCC) TCC-Transaction 分布式事务框架 Github 仓库:https://github.com/changmingxie/tcc-transaction ...

April 17, 2020 · 7 min

Dubbo微服务影院系列(9):Dubbo服务开发(支付模块开发)

章节概要 完成支付模块业务开发 Dubbo 特性学习:隐式参数、参数验证等 Dubbo 本地存根 本地存根类似于 Dubbo 的静态代理 Dubbo 会在客户端生成一个代理,处理部分业务 Stub 必须有可传入 Proxy 的构造函数 官方文档:https://dubbo.apache.org/zh-cn/docs/user/demos/local-stub.html 远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。 在 spring 配置文件中按以下方式配置: <dubbo:service interface="com.foo.BarService" stub="true" /> 或 <dubbo:service interface="com.foo.BarService" stub="com.foo.BarServiceStub" /> 提供 Stub 的实现: package com.foo; public class BarServiceStub implements BarService { private final BarService barService; // 构造函数传入真正的远程代理对象 public BarServiceStub(BarService barService){ this.barService = barService; } public String sayHello(String name) { // 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等 try { return barService.sayHello(name); } catch (Exception e) { // 你可以容错,可以做任何AOP拦截事项 return "容错数据"; } } } Stub 必须有可传入 Proxy 的构造函数。 在 interface 旁边放一个 Stub 实现,它实现 BarService 接口,并有一个传入远程 BarService 实例的构造函数 Dubbo 本地伪装 本地伪装是本地存根的一个子集 通常会使用本地伪装处理服务降级 建议本地伪装在客户端实现 官方文档:https://dubbo.apache.org/zh-cn/docs/user/demos/local-mock.html ...

April 11, 2020 · 2 min

Dubbo微服务影院系列(8):Dubbo服务开发(订单模块开发)

章节概要 完成订单模块业务开发 完成限流和熔断、降级相关内容 Dubbo 特性之分组、聚合和版本控制 订单模块问题 订单模块的横向和纵向分表如何解决? 服务限流如何处理? 服务熔断和降级? 如何保证多版本的蓝绿上线? 横向拆分和纵向拆分 Dubbo 服务分组 官方文档:https://dubbo.apache.org/zh-cn/docs/user/demos/service-group.html 当一个接口有多种实现时,可以用 group 区分。 服务 <dubbo:service group="feedback" interface="com.xxx.IndexService" /> <dubbo:service group="member" interface="com.xxx.IndexService" /> 引用 <dubbo:reference id="feedbackIndexService" group="feedback" interface="com.xxx.IndexService" /> <dubbo:reference id="memberIndexService" group="member" interface="com.xxx.IndexService" /> 任意组: <dubbo:reference id="barService" interface="com.foo.BarService" group="*" /> Dubbo 分组聚合 https://dubbo.apache.org/zh-cn/docs/user/demos/group-merger.html 按组合并返回结果,比如菜单服务,接口一样,但有多种实现,用 group 区分,现在消费方需从每种 group 中调用一次返回结果,合并结果返回,这样就可以实现聚合菜单项。 配置 搜索所有分组 <dubbo:reference interface="com.xxx.MenuService" group="*" merger="true" /> 合并指定分组 <dubbo:reference interface="com.xxx.MenuService" group="aaa,bbb" merger="true" /> 指定方法合并结果,其它未指定的方法,将只调用一个 Group <dubbo:reference interface="com.xxx.MenuService" group="*"> <dubbo:method name="getMenuItems" merger="true" /> </dubbo:reference> 某个方法不合并结果,其它都合并结果 <dubbo:reference interface="com.xxx.MenuService" group="*" merger="true"> <dubbo:method name="getMenuItems" merger="false" /> </dubbo:reference> 指定合并策略,缺省根据返回值类型自动匹配,如果同一类型有两个合并器时,需指定合并器的名称 <dubbo:reference interface="com.xxx.MenuService" group="*"> <dubbo:method name="getMenuItems" merger="mymerge" /> </dubbo:reference> 指定合并方法,将调用返回结果的指定方法进行合并,合并方法的参数类型必须是返回结果类型本身 <dubbo:reference interface="com.xxx.MenuService" group="*"> <dubbo:method name="getMenuItems" merger=".addAll" /> </dubbo:reference> Dubbo 多版本 当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。 可以按照以下的步骤进行版本迁移: 在低压力时间段,先升级一半提供者为新版本 再将所有消费者升级为新版本 然后将剩下的一半提供者升级为新版本 配置 老版本服务提供者配置: <dubbo:service interface="com.foo.BarService" version="1.0.0" /> 新版本服务提供者配置: <dubbo:service interface="com.foo.BarService" version="2.0.0" /> 老版本服务消费者配置: <dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" /> 新版本服务消费者配置: ...

April 5, 2020 · 2 min

Dubbo微服务影院系列(7):Dubbo服务开发(影院模块开发)

章节概要 完成影院模块业务开发 修改全局异常返回 学习 Dubbo 特性:结果缓存,连接和并发控制 Dubbo 结果缓存 官方文档:https://dubbo.apache.org/zh-cn/docs/user/demos/result-cache.html 用于加速热门数据的访问速度,Dubbo 提供声明式缓存,以减少用户加缓存的工作量。 缓存类型 lru 基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。 threadlocal 当前线程缓存,比如一个页面渲染,用到很多 portal,每个 portal 都要去查用户信息,通过线程缓存,可以减少这种多余访问。 配置 <dubbo:reference interface="com.foo.BarService" cache="lru" /> 或: <dubbo:reference interface="com.foo.BarService"> <dubbo:method name="findBar" cache="lru" /> </dubbo:reference> 了解 Dubbo 结果缓存与 Redis 缓存等的区别: Dubbo 结果缓存是本地缓存,保存在当前 JVM 中,多台机器存储多份缓存。适合数据量小的数据,存储在本地占用资源少,而且速度较快。 Redis 缓存则是分布式缓存,多台机器共享缓存。 小数据量的可以放在 Dubbo 结果缓存中,需要计算和共享的缓存数据可以放在 Redis 中。 Dubbo 连接、并发控制 Dubbo 可以对连接、并发数量进行控制 超出部分以错误形式返回 Dubbo 连接控制 官方文档:https://dubbo.apache.org/zh-cn/docs/user/demos/config-connections.html 服务端连接控制 限制服务器端接受的连接不能超过 10 个: <dubbo:provider protocol="dubbo" accepts="10" /> 或 <dubbo:protocol name="dubbo" accepts="10" /> 客户端连接控制 限制客户端服务使用连接不能超过 10 个(如果是长连接,比如 Dubbo 协议,connections 表示该服务对每个提供者建立的长连接数): <dubbo:reference interface="com.foo.BarService" connections="10" /> 或 <dubbo:service interface="com.foo.BarService" connections="10" /> 如果 dubbo:service 和 dubbo:reference 都配了 connections,dubbo:reference 优先。 ...

March 30, 2020 · 1 min

Dubbo微服务影院系列(6):Dubbo服务开发(影片模块开发)

章节概要 掌握 API 网关服务聚合功能的实现 掌握 Mybatis-plus 自定义 SQL 实现 掌握 Dubbo 异步调用 服务聚合 服务聚合就是将多个服务调用封装 服务聚合可以简化前端调用方式 服务聚合提供更好的安全性、可扩展性 业务功能开发流程 根据接口文档思考功能列表 实现 API 接口和实体 服务提供者实现 影片模块创建 从 guns-user 拷贝一份重命名为 guns-film,修改相关配置 API 网关功能聚合 优点 六个接口,一次请求,同一时刻节省了5次HTTP请求 同一个接口对外暴露,降低了前后端分离开发的难度和复杂度 缺点: 一次获取数据过多,容易出现问题 如 gateway 中的影片模块的获取首页信息接口,将 filmServiceApi 的多个方法所获得的对象聚合为 FilmIndexVO 对象返回给前端,将原本需要的多个接口聚合为一个 /film/getIndex 接口,避免了前端对不同接口的多次调用。 @RequestMapping(value = "getIndex", method = RequestMethod.GET) public ResponseVO getIndex() { FilmIndexVO filmIndexVO = new FilmIndexVO(); // 获取banner信息 filmIndexVO.setBanners(filmServiceApi.getBanners()); // 获取热映的影片 filmIndexVO.setHotFilms(filmServiceApi.getHotFilms(true, 99, 99, 99, 99, 1, 8)); // 获取即将上映的影片 filmIndexVO.setSoonFilms(filmServiceApi.getSoonFilms(true, 99, 99, 99, 99, 1, 8)); // 获取票房排行榜 filmIndexVO.setBoxRanking(filmServiceApi.getBoxRanking()); // 获取人气榜单 filmIndexVO.setExpectRanking(filmServiceApi.getExpectRanking()); // 获取排行前100影片 filmIndexVO.setTop100(filmServiceApi.getTop()); return ResponseVO.success(IMG_PRE, filmIndexVO); } Mybatis-plus 自定义 SQL 实现 在相应的 Mapper 接口中添加方法 ...

March 22, 2020 · 3 min

Dubbo微服务影院系列(5):Dubbo基本特性(用户模块开发)

章节概要 学会 API 网关权限验证和其他服务交互 学会开发 SpringBoot 的自定义配置 学会 Dubbo 负载均衡策略选择和使用 修改 Guns 中的 JWT 模块 增加忽略验证 URL 配置 修改返回内容匹配业务 增加 Threadlocal 的用户信息保存 业务功能开发 增加用户服务并提供接口 初步了解 API 网关与服务之间交互的过程 根据接口文档开发用户接口 创建用户表 DROP TABLE IF EXISTS user; CREATE TABLE user( UUID INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键编号', user_name VARCHAR(50) COMMENT '用户账号', user_pwd VARCHAR(50) COMMENT '用户密码', nick_name VARCHAR(50) COMMENT '用户昵称', user_sex INT COMMENT '用户性别 0-男,1-女', birthday VARCHAR(50) COMMENT '出生日期', email VARCHAR(50) COMMENT '用户邮箱', user_phone VARCHAR(50) COMMENT '用户手机号', address VARCHAR(50) COMMENT '用户住址', head_url VARCHAR(50) COMMENT '头像URL', biography VARCHAR(200) COMMENT '个人介绍', life_state INT COMMENT '生活状态 0-单身,1-热恋中,2-已婚,3-为人父母', begin_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间' ) COMMENT '用户表' ENGINE = INNODB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC; insert into user(user_name,user_pwd,nick_name,user_sex,birthday,email,user_phone,address,head_url,life_state,biography) values('admin','0192023a7bbd73250516f069df18b500','管理员',0,'2018-07-31','admin@gmail.com','13888888888','浙江省杭州市西湖区某路某号','cinema/img/head-img.jpg',0,'我是苦逼的管理员'); insert into user(user_name,user_pwd,nick_name,user_sex,birthday,email,user_phone,address,head_url,life_state,biography) values('test','5e2de6bd1c9b50f6e27d4e55da43b917','测试用户',0,'2018-08-20','test@gmail.com','13866666666','测试地址','cinema/img/head-img.jpg',1,'我是测试用户'); 用户服务与网关交互 在 guns 项目中复制一份 guns-gateway 模块并重命名为 guns-user(修改相应子模块和主模块的 pom.xml 等),并在 application.yml 中将其鉴权机制等关闭(网关才需要) ...

March 11, 2020 · 5 min

Dubbo微服务影院系列(4):业务基础环境构建

章节概要 构建基于 Guns + SpringBoot + Dubbo 的框架 学会抽离业务接口 学会 API 网关变形应用 API 网关介绍 API 网关有点类似于设计模式中的 Facade 模式 API 网关一般都是微服务系统中的门面 API 网关是微服务的重要组成部分 API 网关的常见作用 身份验证和安全 审查和检测 动态路由 压力测试 负载均衡(Dubbo 自带) 静态相应处理 Guns 环境构建 导入 guns 项目 创建 guns_rest 数据库 创建 user 表 -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `userName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES (1, 'admin'); SET FOREIGN_KEY_CHECKS = 1; 添加 log4j 依赖 <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> 修改 datasource 的 url 修改 application.yml 中 spring 的 datasource 的 url 为 ...

March 9, 2020 · 2 min

Dubbo微服务影院系列(3):环境搭建

基础环境搭建 基于Guns + SpringBoot + Dubbo构建影院平台 Spring + Dubbo SpringBoot + Dubbo 微服务基本概念 Provider:服务提供者 Consumer:服务调用者,调用 Provider 提供的服务实现 同一个服务可以即是 Provider,又是 Consumer 以下可以选用 Spring 或 SpringBoot Spring基础环境构建 项目结构 主模块(Spring-Dubbo-Demo) 在 pom.xml 中添加 dependencies <dependencies> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.9</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.9</version> <type>pom</type> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.5.3</version> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.6.Final</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.21.0-GA</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- spring相关jar --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.3.3.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> 子模块(provider、consumer) 在 resources 中添加 applicationContext.xml(可更改后缀) ...

March 8, 2020 · 3 min