微服务分布式构架开发实战(txt+pdf+epub+mobi电子书下载)

作者:龚鹏

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

微服务分布式构架开发实战

微服务分布式构架开发实战试读:

前言

在当下的互联网世界里,系统开发既简单又困难。说它简单,是因为各技术社区的贡献及各框架的完善,使整个生态越来越丰富,绝大多数的需求都可以使用现有的库实现(不用重新发明“轮子”),并且现在很多的库都非常注重使用体验,以快速实现为目标,通过少量的配置及代码便可集成使用。但合理地编排这些库以构建一个高效、稳健、灵活的系统,并不是一件容易的事,人们一般将专精此道的人称为架构师。

一个完善可靠的微服务分布式架构需要解决众多的问题,我们可以用多种方法去解决这些问题,但刚开始接触时很难确定哪种方法是最优方案。在不确定并且刚接触如此庞大的架构时,选择信任、成熟且活跃的框架及第三方库提供的解决方案显然是明智之举。当建立起对微服务分布式架构的认知后,再重新回归最初的问题逐步审视并深入,最终形成属于自己的方案。

以往的图书大多只针对微服务分布式架构自身的知识点讲解,周边的相关知识点并未涉及,在进行项目实践时,最终效果则根据读者自身的知识储备而定。本书特色从实际出发

本书并没有过多地探讨理论性的内容,而是基于现有成熟框架,围绕实际项目中遇见的具体需求,以微服务分布式架构的角度去逐一分解并且实现这些需求。掌握这些知识的读者,完全有能力快速搭建出可靠、高效、灵活的微服务分布式架构。与行业动向接轨

借助于现有框架进行微服务分布式架构实践的成本越来越低,并且这种形式正在逐渐成为主流架构。在进行框架及第三方库的选择时,也同样紧跟行业动向。简单易懂

本书中的每一个示例都尽量用最少的代码和最快的方式解决具体的问题,为读者呈现复杂系统中简单的一面,其目的是快速接受并理解各知识点在微服务分布式架构中所处的位置及其相互关系。本书面向读者● Java工程师● 初级架构师● 独立开发者与自学读者● 高校相关专业师生● Java培训班学员学习前的一些建议明确目标

技术服务于商业,尽量避免陷入技术细节的漩涡中,不要为了技术而技术。在进入学习状态之前,根据书中的章节与自己的经验明确学习目标,不断地提出问题并验证,最终找出答案。先定个小目标

面对一个复杂架构体系,从简单的知识点入手逐个攻破,用小成就感驱动自己最终完成设定的计划。持之以恒

学习从来都不是一件容易的事,从学习ABC到写出自己的第一篇文章,从建立账号到超越第一个BOSS或者赢得第一场胜利,这之间的过程都是学习,都需要投入大量的时间和精力。如果你想要做出心目中理想的网站,或者将其作为自己赖以谋生的技能,坚持下去,你才能够做到。积极探索

互联网技术的优势是,当你遇到问题时,往往可以在互联网上寻求答案。互联网行业的大牛同样活跃在互联网上,找到他们,向他们学习。订阅公众号或者相关博客,积极了解行业发展和最新动向。这是其他学科无法比拟的优势。第1章微服务介绍1.1 什么是微服务架构1.2 垂直应用与微服务1.3 实现一个最简单的微服务框架1.4 主流微服务框架介绍

随着用户需求个性化、产品生命周期变短,微服务架构是未来软件架构朝着灵活性、扩展性、伸缩性以及高可用性发展的必然方向。这里主要将对比传统的垂直应用与分布式微服务应用之间的区别。1.1 什么是微服务架构

微服务是一种软件架构风格,目标是将一个复杂的应用拆分成多个服务模块,每个模块专注单一业务功能对外提供服务,并可以独立编译及部署,同时各模块间互相通信彼此协作,组合为整体对外提供完整服务。微服务架构就像是活字印刷术,每个文字模都可以看成是一个微服务,它可以独立地提供印刷服务,又可以将模块之间组合,最终形成一篇完整文章提供更为复杂的印刷服务。

由于每个模块都独立部署,各自拥有互不干扰的内存空间,模块之间无法直接调用,所以需要借助RPC(远程过程调用协议)或HTTP协议让各个模块之间传递通信报文及交换数据,实现远程调用,整个通信管理的过程也是微服务架构重要的组成部分。1.2 垂直应用与微服务

MVC模式构建的垂直应用非常适合项目初期,使用其能够方便地进行开发、部署、测试,但随着业务的发展与访问量的增加,垂直应用的问题也随之暴露出来,而微服务架构可以很好地解决这些问题。代码维护

垂直应用里,大部分逻辑都部署在一个集中化、单一的环境或服务器中运行。垂直应用程序通常很大,由一个大型团队或多个团队维护。庞大的代码库可能给希望熟悉代码的开发人员增加学习成本,还会让应用程序开发过程中使用的开发环境工具和运行容器不堪重负,最终导致开发效率降低,可能会阻止对执行更改的尝试。

微服务架构将这个庞大并且复杂的应用拆分成多个逻辑简单且独立的小应用,每个小应用交由不同的团队或开发人员维护,彼此之间互不干扰,通过标准接口互相通信。对于希望熟悉代码的开发人员来说只需掌握他所负责的应用即可,这样做的好处是简单、快速、逻辑清晰。部署

垂直应用需要处理一个庞大的应用程序,编译、部署需要花费很长时间,一个小的修改就可能导致重新构建整个项目。

微服务架构中对其中某一个服务进行修改,只需重新编译、部署被改动的服务模块。资源控制

垂直应用里,当请求量过大导致单台服务器无法支撑时,一般会将垂直应用部署在多台服务器形成服务集群,并通过反向代理实现负载均衡。集群中的每个服务必须部署完整的应用,但在实际业务需求中仅有部分功能使用频繁,但这种架构必须为不常用的功能分配计算资源。

微服务将提供功能的各服务拆分为多个服务模块,它具有天生的集群属性,能够轻松地根据用量部署。例如系统中的消息功能使用频率占了整个系统的90%,而密码找回功能则只占到2%。为了分解消息功能的压力,以传统负载均衡的方式进行集群化时,每个服务必须为使用量只有2%的密码找回功能分配资源,这无疑造成了浪费。在微服务架构中,消息功能使用率占据90%,则将消息模块多部署几个实例形成集群,而密码找回功能所在的用户模块只部署一个就可以了。稳定

垂直应用中如果有一个小的问题,就可能使整个系统崩溃。

微服务所拆分出的各个模块中,由于模块之间的耦合度很低,当发生问题时影响范围被固定在该模块本身,整个系统依然健全。1.3 实现一个最简单的微服务框架

基本工作流程如下。

① 客户端发起调用请求。

② 将调用的内容序列化后通过网络发给服务端。

③ 服务端接收到调用请求,执行具体服务并获得结果。

④ 将结果序列化后通过网络返回给客户端。1.3.1 公共接口

在发起远程调用时,需要基于接口(Interface)来约定客户端与服务端所调用服务的具体内容。为了方便管理依赖关系,这里使用Maven构建应用并编写一些接口,以提供给客户端与服务端使用。

当然也可以使用普通的Java应用来实现此简单微服务框架,只需将该应用编译后的jar包提供给后续的服务端与客户端即可。Maven 参数groupId:org.book artifactId:rpc-interface version:0.0.1-SNAPSHOT packaging:jar

编写接口。public interface HelloService { public String hello(String name); }1.3.2 服务端

新建用于提供服务的Maven应用,并引入刚编写的接口应用依赖。Maven 参数groupId:org.book artifactId:rpc-server version:0.0.1-SNAPSHOT packaging:jar

① 在pom.xml文件中引入依赖。 org.book rpc-interface 0.0.1-SNAPSHOT

② 实现服务接口。public class HelloServiceImple implements HelloService { public String hello(String name) { System.out.println("收到消息:" + name); return "你好:" + name; } }

③ 编写监听服务类。public class Server { private static ExecutorService executor = Executors.newFixedThreadPool(10); private static final HashMap serviceRegistry = new HashMap(); public void register(Class serviceInterface, Class impl) { //注册服务 serviceRegistry.put(serviceInterface.getName(), impl); } public void start(int port) throws IOException { final ServerSocket server = new ServerSocket(); server.bind(new InetSocketAddress(port)); System.out.println("服务已启动"); while (true) { executor.execute(new Runnable() { public void run() { Socket socket = null; ObjectInputStream input = null; ObjectOutputStream output = null; try { socket = server.accept(); // 接收到服务调用请求,将码流反序列化定位具体服务 input = new ObjectInputStream(socket.getInputStream()); String serviceName = input.readUTF(); String methodName = input.readUTF(); Class[] parameterTypes = (Class[]) input.readObject(); Object[] arguments = (Object[]) input.readObject(); // 在服务注册表中根据调用的服务获取到具体的实现类 Class serviceClass = serviceRegistry.get(serviceName); if (serviceClass == null) { throw new ClassNotFoundException(serviceName + " 未找到"); } Method method = serviceClass.getMethod(methodName, parameterTypes); // 调用获取结果 Object result = method.invoke(serviceClass.newInstance(), arguments); // 将结果序列化后发送回客户端 output = new ObjectOutputStream(socket.getOutputStream()); output.writeObject(result); } catch (Exception e) { e.printStackTrace(); } finally { // 关闭资源 try { if (socket != null) socket.close(); if (input == null) input.close(); if (output == null) output.close(); } catch (IOException e) { e.printStackTrace(); } } } }); } } }register()

提供一个数组保存所注册的服务接口及实现类。start()

启动一个阻塞式的Socket服务用于等待客户端发起的调用请求,当收到请求后将码流反序列化成对象,并根据接口从注册列表中寻找具体实现类,最终通过反射的方式调用该实现类返回结果。

④ 注册服务并启动服务端。public class App { public static void main(String[] args) throws IOException { Server server = new Server(); // 注册服务 server.register(HelloService.class, HelloServiceImple.class); // 启动并绑定端口 server.start(8020); } }1.3.3 客户端

新建用于调用服务的Maven应用,并引入刚编写的接口应用依赖。Maven 参数groupId:org.book artifactId:rpc-client version:0.0.1-SNAPSHOT packaging:jar

① 在pom.xml文件中引入依赖。 org.book rpc-interface 0.0.1-SNAPSHOT

② 编写远程调用类。public class Client { @SuppressWarnings("unchecked") public static T get(final Class serviceInterface, final InetSocketAddress addr) { T instance = (T) Proxy.newProxyInstance(serviceInterface. getClassLoader(), new Class[]{serviceInterface}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = null; ObjectOutputStream output = null; ObjectInputStream input = null; try { // 连接服务端 socket = new Socket(); socket.connect(addr); // 将调用的接口类、方法名、参数列表等序列后发送给服务提供者 output = new ObjectOutputStream(socket.getOutputStream()); output.writeUTF(serviceInterface.getName()); output.writeUTF(method.getName()); output.writeObject(method.getParameterTypes()); output.writeObject(args); // 同步阻塞等待服务器返回应答,获取应答后返回 input = new ObjectInputStream(socket.getInputStream()); return input.readObject(); } finally { if (socket != null) socket.close(); if (output != null) output.close(); if (input != null) input.close(); } } }); return instance; } }

使用JDK动态代理方式,根据提供的服务接口类将接口序列化成码流,向目标服务端发起Socket远程调用请求,获得服务端反馈的结果并反序列化成对象后返回。

③ 调用测试。public class App { public static void main(String[] args) throws IOException { HelloService service = Client.get(HelloService.class, new InetSocketAddress ("localhost", 8020)); System.out.println(service.hello("RPC")); } }

运行结果如下所示:// 客户端 hello : RPC // 服务端 服务已启动 收到消息:RPC

本章示例代码详见异步社区网站本书页面。1.3.4 完善框架

服务之间的调用已基本实现,但想将它投入正式开发使用还有很多细节需要完善。通信

当请求过大后会发现,BIO(同步阻塞式)的通信方式会消耗过多的资源导致服务器变慢甚至崩溃。序列化与反序列化

在发起网络请求前,将对象转换成二进制串便于网络传输;收到消息请求后,将二进制串反转换成对象便于后续处理。序列化及反序列化直接影响到整个RPC框架的效率及稳定性。服务注册中心

发起服务调用时,都需要指定服务提供方的访问地址(ip + 端口),如果当前服务提供方有多个或一个服务部署在多个机器上,调用时每次手动指定访问地址非常麻烦,这时就需要一个公共的注册中心去管理这些服务。负载均衡

实施微服务的目的是为了让系统在进行横向扩展时能够拥有更多的计算资源,如果发现某一提供服务的机器负载较大,这就需要将新的需求转发到其他空闲的机器上。服务监控

服务提供方有可能崩溃无法继续提供服务,在客户端进行调用时就需要将这些无法使用的服务排除掉。异常处理

当服务端有异常发生导致无法返回正确的结果时,客户端并不知道该如何处理,只能等待并最终以超时结束此次远程调用请求。以上所有的问题在后续将要介绍的Dubbo与Spring Cloud分布式框架中都得到了很好的解决,甚至基于Spring Boot构建的应用能让整个开发过程变得轻松愉快。1.4 主流微服务框架介绍1.4.1 Dubbo

阿里巴巴在2011年开源了Dubbo框架,虽然在2013年停止更新,但在2017年9月又重启维护并发布了新版本。目前已有很多的公司将自己的业务建立在Dubbo之上,同时阿里云也推出了企业级分布式应用服务EDAS,为Dubbo提供应用托管。

Dubbo采用Zookeeper作为注册中心,RPC作为服务调用方式,致力于提供高性能和透明化的RPC远程服务调用方案。它与Spring无缝集成,基于服务提供方(服务端)与服务调用方(客户端)角色构建简单模型,其优点是使用方便、学习成本低。

① 服务提供方发布服务到服务注册中心。

② 服务消费方从服务注册中心订阅服务。

③ 注册中心通知消息调用方服务已注册。

④ 服务消费方调用已经注册的可用服务。

⑤ 监控计数。1.4.2 Spring Cloud

Spring Cloud基于Spring Boot实现,使用HTTP的RESTful风格API作为调用方式。它所包含的多个子项目共同构建了微服务架构体系。Netflix Eureka

Spring Cloud 的服务注册中心提供服务注册、服务发现、负载均衡等功能。Netflix Hystrix

当某个服务发生故障之后,则触发熔断机制(Hystrix)向服务调用方返回结果标识错误,而不是一直等待服务提供方返回结果,这样就不会使得线程因调用故障服务而被长时间占用不释放,避免了故障在分布式系统中的蔓延。Netflix Zuul

代理各模块提供的服务,统一暴露给第三方应用。提供动态路由、监控、弹性、全等的边缘服务。Config Server

分布式架构下多微服务会产生非常多的配置文件,分布式配置中心(Config Server)将所有配置文件交由GIT或SVN进行统一管理,避免出错。Spring Boot

在使用Spring开发时,通常需要完成Spring框架及其他第三方工具配置文件的编写,非常麻烦。Spring Boot通过牺牲项目的自由度来减少配置的复杂度,约定一套规则,把这些框架都自动配置集成好,从而达到“开箱即用”。第2章模块拆分2.1 拆分逻辑2.2 单模块2.3 基础模块2.4 复杂模块

将完整地使用本地调用方式的垂直应用拆分成多个微小的服务,每个服务模块负责提供各自独立的服务接口,并通过网络调用的方式将各个服务模块组织起来形成完整的微服务系统。

这里介绍微服务架构中拆分模块的基本逻辑,更为完善的模块拆分可以基于领域驱动设计(Domain-Driven Design,DDD)进行。2.1 拆分逻辑

模块拆分是分布式微服务实施时的困难之一,它将直接影响到系统的复杂度、团队协作、代码维护难度、硬件资源分配等方面。模块拆分得越细,则能够更灵活地分配硬件资源与更方便地进行团队协作,但这样也会增加系统复杂度与代码维护难度,在团队人数较少的情况下无疑增加了负担。拆分模块时需要以具体的业务需求与系统请求压力分布为出发点进行权衡取舍。系统复杂度

业务的复杂性决定了被拆分的模块之间必然存在一定的依赖,模块被拆分得越细就意味着会产生更多的依赖关系,在拆分解耦的同时必然增加了整个系统的复杂度。

随着业务的丰富不可避免地使系统越来越复杂,我们没有办法拒绝复杂但应通过规范、约定、框架等手段尽量做到结构及代码的清晰与整洁。团队协作

当垂直应用变得庞大且复杂需要更多的工程师维护时,一般会使用Maven的多模块依赖特性将单一的应用拆分成多个模块,每个模块分给不同的工程师维护,最终团队成员提交模块,根据依赖关系打包成一个应用发布。

微服务天生由多模块组成,各个模块交由具体的专人负责,团队之间通过模块所暴露的服务进行协作。拆分模块的同时也确定了团队协作的方式。代码维护难度

微服务能够解决在垂直应用中错综复杂的业务逻辑耦合在一起的维护困难问题,但也并不是将模块拆分得越细越好,过多的模块反而会增加工作量与代码维护难度。

每个模块都处理着属于自己的业务逻辑,它们提供服务并维护着与其他模块的依赖关系,如果服务提供方的返回结果发生了变动,则各个调用方均要修改自己的代码。

在实际开发中不可避免地要跨模块调试,调试过程中所涉及的模块数量越多,则整个过程就越麻烦。硬件资源分配

系统中存在请求压力不均衡的情况,模块拆分得越细,则能更有针对性地为高压力模块分配更多的计算资源,避免浪费。2.2 单模块

为了设计出低耦合、高内聚的系统,需要确保每个模块都具有一定的独立性,每个模块只完成它所负责的业务功能,并且模块之间做到最少联系及接口简单。模块之间的边界则是思考的重点。

单个模块内聚了相关性较强的功能,并且拥有独立的数据库(ORM)、单元测试、运行内存、业务逻辑处理等。可以将单个模块看成是一个完整的垂直应用,只是在输入(接受请求)、输出(结果输出)时有差别。

大部分请求都是同步的,即消费方发起请求后等待提供方完成计算并返回结果,但如果等待的过程过于漫长,则需要借助消息队列与回调将请求的过程变为异步,消费方向服务提供方的消息队列中发送请求消息,服务方计算完成后调用消费方的方法通知结果。异步请求适合处理批量处理类的功能,例如群发邮件,一次性发送1000封邮件需要一定的发送时间,采用异步处理,则消费方只需向发送邮件的服务队列中增加收件列表,任务完成后调用消费方的接口告知发送结果即可。2.3 基础模块

一个复杂的业务功能需要依赖多个模块所提供的功能实现,在进行模块拆分时需要提前对业务所涉及的模块进行梳理,最终如图所示, 各个模块由上至下依次层级依赖。

各个模块提供的服务具有一定的原子性,保持独立不重叠。将不需要依赖其他模块或依赖较少的模块抽象为基础模块,为更为复杂的业务逻辑做准备,提高复用性与扩展性。2.4 复杂模块

为实现复杂业务将基础模块进行聚合重组时,每个模块对自身数据库操作事务的管理比较简单,但基于网络跨模块的二阶事务管理则会将整个过程变得无比复杂,并且耗费更多的资源,所以在进行模块拆分时且尽量规避二阶事务的产生。在无法避免分布式事务的情况下,可以采用 TCC(Trying Confirming Canceling)补偿性事务解决方案实现对二阶事务的管理。

垂直应用在处理购物车或登录状态管理等功能时一般会基于Session实现,但在分布式架构下Session的共享与传递会增加整个系统的耦合度并且提高复杂性。模块在处理自身业务逻辑及服务调用时,尽量以无状态协议的角度进行设计,请求完立刻释放资源。维护状态的工作可由服务提供方增加状态检查的服务,但面对高查询、低修改的场景时可以基于约定交由公共缓存系统(Redis)维护。复杂的订单模块为了产生一张订单,需要用户模块提供的买卖双方信息,产品模块提供的货物信息,财务模块提供的账户余额、消息模块提供的短信通知等基础服务。第3章Spring Boot3.1 目录结构3.2 主要文件3.3 编辑器集成

Spring Boot是Spring官方的顶级项目之一,基于Spring Platform 对 Spring 框架和第三方库进行处理,提供默认配置以降低使用复杂度,可轻松创建单独运行的、基于生产级的Spring应用程序。

后续将要介绍的Spring Cloud 分布式微服务框架也是在Spring Boot的基础上构建的,并且Dubbo框架的社区也提供了Spring Boot的支持。为了更加方便愉快地开发,后续所有例子都将基于Spring Boot进行讲解。3.1 目录结构

Spring Boot基于Maven构建,官网提供了快速初始化服务,只需提供相关Maven信息及需要引入的第三方依赖包,便可自动生成应用并打包成zip压缩包下载。

将下载好的zip压缩包解压后得到的目录如下:src/main/java

用于存放源代码文件。src/main/resources

用于存放配置文件,如果在使用Spring Initializr创建应用时勾选了spring-boot-starter-web依赖,则会在此目录自动创建static目录用于存放静态文件及templates目录用于存放界面模板文件。src/test/java

用于存放测试文件。target

用于存放Maven编译后的文件。3.2 主要文件Application.java@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

通过注解@SpringBootApplication指定该类为Spring Boot启动类,Spring Boot将根据该类所在包路径自动扫描子路径下所有的Spring Beans 并且完成自动配置。application.properties

Spring Boot的默认配置文件,根据文件名application自动加载,并且支持以.yml为后缀的配置文件。

application.properties 示例spring.application.name=demo

application.yml 示例spring: application: name: demopom.xml

Maven用于管理依赖的重要文件,Spring Boot 基于Maven的项目集成特性在parent节点中配置了相关信息,同时指定了spring-boot-maven-plugin插件用于编译Spring Boot应用。mvnw

对Maven的mvn命令的封装,mvnw.cmd用于Windows系统,而mvnw则用于Linux系统。3.3 编辑器集成

目前主流的编辑器如Eclipse、IntelliJ IDEA等都集成了Spring Initializr用于创建Spring Boot应用,并且默认支持Maven,使整个开发过程变得轻松愉快。Eclipse

使用插件的方式集成Spring Initializr

插件名称:Spring Tools(aka Spring IDE and Spring Tool Suite)

安装方式:菜单栏 → Helps → Eclipse Marketplace → 搜索 STSIntelliJ IDEA

已默认集成Spring Initializr新建应用的方式。第4章Dubbo4.1 注册中心4.2 接口工程4.3 服务端4.4 消费方4.5 网关4.6 监控中心4.7 服务管理4.8 负载均衡4.9 服务降级4.10 集群容错

最基本的Dubbo工程由服务提供方、消费方、服务接口组成,接口工程中编写所提供服务的接口(Interface)由服务提供方实现具体业务逻辑并注册服务,消费方则基于接口工程中所规定的服务接口进行调用,各工程之间基于Maven管理依赖。服务方与消费方都依赖于接口服务4.1 注册中心

Dubbo支持多种注册中心,其中Zookeeper最为可靠,并且官方也推荐使用。

Zookeeper是 Apache Hadoop 的子项目,主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

Zookeeper 的安装非常简单,从官网下载后解压,进入conf目录中把zoo_sample.cfg重命名为zoo.cfg便可开始配置。tickTime=2000 initLimit=10 syncLimit=5 dataDir=E:\\apache\\zookeeper-3.5.3-beta\\data clientPort=2181 admin.serverPort=9090tickTime

服务器之间或客户端与服务器之间维持心跳的时间间隔。initLimit

配置在集群中与其他Zookeeper的连接最大心跳时间间隔数。syncLimit

标识 Leader与Follower之间发送消息时请求和应答的时间长度,规定了在此期间最长不能超过多少个心跳数。dataDir

保存数据的目录。clientPort

客户端连接服务器的端口,zookeeper 会监听这个端口,接受客户端的访问请求。admin.serverPort

Jetty服务的监听端口,默认是8080。集群配置

server.A:B:C:D,其中 A 表示服务器编号,B表示该服务器的IP地址,C 和 D 是两个TCP 端口号,分别用于仲裁和 Leader 选举。

server.1:192.169.1.22:2222:2223

server.2:192.169.1.23:2222:2223

示例表示当前的Zookeeper与IP为22和23的Zookeeper组成集群,如果IP相同,则用于仲裁和选举的端口号需要区分。启动

启动脚本存放在zookeeper的bin目录中,根据你的操作系统选择。

Windows:由CMD或PowerShell命令进入Zookeeper的bin目录中,并执行.\zkServer.cmd。

Linux:进入Zookeeper的bin目录中,并执行zkServer.sh start。4.2 接口工程

与之前“实现一个最简单的微服务框架”中的公共接口一样,这里需要新建一个Maven应用,并服务于服务提供方与消费方。Maven参数groupId:org.book.rpc.dubbo artifactId:dubbo-api version:0.0.1-SNAPSHOT packaging:jar

编写接口public interface IHello { public String say(String msg); }4.3 服务端

① 新建Spring Boot应用。在Eclipse中可以使用STS插件新建,地址为:菜单栏 → File → New → Spring Starter ProjectMaven参数groupId:org.book.rpc.dubbo artifactId:dubbo-service version:0.0.1-SNAPSHOT packaging:jar

② 在pom.xml文件中添加Dubbo与接口应用的依赖。 io.dubbo.springboot spring-boot-starter-dubbo 1.0.0 org.book.rpc.dubbo dubbo-api 0.0.1-SNAPSHOT

③ 编写代码实现接口。@Service public class HelloImple implements IHello { @Override public String say(String msg) { System.out.println("你好:" + msg); return msg; } }

Dubbo的@Service注解用于暴露服务,其可配置的属性如下。version

指定该服务的版本。group

服务所属分组,当一个接口有多种实现时,可以用group区分。cache

该服务的缓存策略。● lru 基于“最近最少使用”原则删除多余缓存,保持最热的

数据被缓存。● threadlocal 当前线程缓存,比如一个页面渲染,用到很多

portal,每个portal都要去查用户信息,通过线程缓存,可以减少

这种多余访问。async

基于NIO的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务的功能,相对多线程开销较小。delay

延迟暴露服务,如果你的服务需要warmup时间,比如初始化缓存、等待相关资源就位等,可以使用delay进行延迟暴露。为-1时,则表示延迟到Spring初始化完成后,再暴露服务(基于Spring的ContextRefreshedEvent事件触发暴露)。timeout

调用服务时的超时时间,单位为秒。mock

设为true,表示使用缺省Mock类名,即接口名 + Mock后缀,服务接口调用Mock实现类,该Mock类必须有一个无参构造函数,与Local的区别在于,Local总是被执行,而Mock只在出现非业务异常(比如超时、网络异常等)时执行;Local在远程调用之前执行,Mock在远程调用后执行。retries

远程服务调用重试次数,不包括第一次调用,不需要重试设为0。token

令牌验证。如果为空,表示不开启;如果为true,表示随机生成动态令牌;否则使用静态令牌。令牌的作用是防止消费者绕过注册中心直接访问,保证注册中心的授权功能有效,如果使用点对点调用,需关闭令牌功能。dynamic

服务是否动态注册,如果设为false,注册后将显示disable状态,需人工启用,并且服务提供者停止时,也不会自动取消册,需人工禁用。register

该协议的服务是否注册到注册中心。deprecated

服务是否过时,如果设为true,消费方引用时将打印服务过时警告error日志。accesslog

设为true,将向logger中输出访问日志,也可填写访问日志文件路径,直接把访问日志输出到指定文件。executes

在暴露服务中的每个方法服务器端并发执行(或占用线程池中的线程数)。actives

在暴露服务中的每个方法客户端并发执行(或占用连接的请求数)。loadbalance

负载均衡策略,可选值为random、roundrobin、leastactive,分别表示随机、轮循、最少活跃调用。

此参数均为小写。connections

限制客户端服务使用连接数(如果是长连接,比如Dubbo协议,connections表示该服务对每个提供者建立的长连接数)。protocol

该服务所使用的协议,不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议,默认为Dubbo。● Dubbo协议,采用单一长连接和NIO异步通信,适合于“小

数据量大并发”的服务调用,以及服务消费者机器数远大于服务

提供者机器数的情况。● Hessian协议,传入传出参数数据包较大,提供者比消费者

个数多,提供者压力较大,可传文件。● RMI协议,采用JDK标准的java.rmi实现,常规远程服务方法

调用,与原生RMI服务互操作。● HTTP协议,可用浏览器查看,通过表单或URL传入参数。● WebService协议,SOAP文本序列化,多用于系统集成,跨

语言调用。● Thrif协议,对 thrift(Facebook的RPC框架) 的原生协议的

扩展。

④ 在appaction.properties文件中配置Dubbo。spring.dubbo.application.name=provider spring.dubbo.registry.address=zookeeper://127.0.0.1:2181 spring.dubbo.protocol.name=dubbo spring.dubbo.protocol.port=-1 spring.dubbo.scan=org.bookspring.dubbo.application.name

当前应用名称,用于注册中心计算应用间依赖关系。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书

若在网站上没有找合适的书籍,可联系网站客服获取,各类电子版图书资料皆有。

客服微信:xzh432

登入/注册
卧槽~你还有脸回来
没有账号? 忘记密码?