- 首先我们聊一下传统的系统架构模式?
传统应用系统中,我们主要使用了三层架构:
表现层
业务层
数据访问层
传统的web应用程序客户端(浏览器)发起请求,业务层执行业务逻辑,执行业务的过程又通过数据库查询/处理相关的数据,最后在完成业务后将数据结合视图展示给用户。
那么以上传统的应用架构中有什么不足?
所有的的代码在一个项目中维护,最终还是部署在一个应用中。
<1>所有项目都是使用一个代码库, 代码库的内容增加,效率就会变得低下。
<2>如果采取多模块的开发模式,模块之间相互依赖,哪怕是很小的改动也会引起开发环境的同步更新
<3>单系统的架构模式,虽然采用了三层架构来区分不同层的责任与任务,但是从实际的操作中来看,难免存在责任交叉,因此某些地方的改动可能会带来其它层的同步变动,失去了分层的独立性。
<4>有很多团队分为开发团队和运营支持团队,开发团队只负责开发,在完成后交于运营团队管理,虽然运营团队能很好地处理一些日常问题,但遇到系统危机问题时,也不得不求助于开发团队。
<5>当业务逐渐增长,单系统可能被拆解为多个独立的子系统,但系统间是存在一定业务关联的,这时解决基础服务公用的问题就势在必行,需要开发者将通用服务独立发布以便于其它系统调用。 - 针对以上的传统应用架构的不足,我们提出了微服务,将产品或者项目分解众多独立的服务,这些服务独立的部署,并不依赖于其他的服务,因此问服务没有集中的数据库,每个模块都具有自己的存储系统。
接着我们说下微服务的优势:
<1>单系统只用一种开发语言,但是微服务每个服务独立,每个服务可以看成一个项目,因此每个服务可以选择最适合服务特色的技术开发。
<2>开发集中在一个服务中,业务和代码量都不大,开发人员能够很好的把握代码。
<3>服务间进行调用,可以通过api进行通讯,也可以使用分布式服务管理框架如Dubbo(rpc)、springCloud。 - 大家注意了,通过上面的一二点,我们是不是顺理成章的引出dubbo分布式服务治理框架,致力于提供高性能和透明化的rpc远程服务调用方案,可以和spring框架无缝集成,是阿里巴巴soa服务化治理方案的核心框架。
dubbo采用的是一种非常简单的模型,要么提供方提供服务,要么消费方消费服务,所以基于这一点可以抽象出服务提供方和服务消费方。
在大规模服务化之前,应用可能只是通过RMI或Hessian等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡。
- 当服务越来越多时,服务URL配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。
此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。
并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。 - 当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。
这时,需要自动画出应用间的依赖关系图,以帮助架构师理清理关系。 - 接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?
为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。
其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。
- dubbo核心架构
Dubbo框架设计一共划分了10个层:
服务接口层(Service)、配置层(Config)、服务代理层(Proxy)、服务注册层(Registry)、集群层(Cluster)、监控层(Monitor)、远程调用层(Protocol)、信息交换层(Exchange)、网络传输层(Transport)和数据序列化层(Serialize)。
而最上面的Service层是留给实际想要使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层。图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口, 位于中轴线上的为双方都用到的接口。 - dubbo的核心要点
① 服务定义
服务是围绕服务提供方和服务消费方的,服务提供方实现服务,而服务消费方调用服务。
② 服务注册
对于服务提供方,它需要发布服务,而且由于应用系统的复杂性,服务的数量、类型也不断膨胀;对于服务消费方,它最关心如何获取到它所需要的服务,而面对复杂的应用系统,需要管理大量的服务调用。而且,对于服务提供方和服务消费方来说,他们还有可能兼具这两种角色,即既需要提供服务,有需要消费服务。
通过将服务统一管理起来,可以有效地优化内部应用对服务发布/使用的流程和管理。服务注册中心可以通过特定协议来完成服务对外的统一。Dubbo提供的注册中心有如下几种类型可供选择:
Multicast(多播/组播)注册中心(开发测试用)、Zookeeper注册中心(生产环境用官方推荐)、Redis注册中心、Simple注册中心
③ 服务监控
无论是服务提供方,还是服务消费方,他们都需要对服务调用的实际状态进行有效的监控,从而改进服务质量。
④ 远程通信与信息交换
远程通信需要指定通信双方所约定的协议,在保证通信双方理解协议语义的基础上,还要保证高效、稳定的消息传输。Dubbo继承了当前主流的网络通信框架,主要包括如下几个:
Mina、Netty、Grizzly
⑤ 服务调用
节点角色说明:
Provider: 暴露服务的服务提供方。
Consumer: 调用远程服务的服务消费方。
Registry: 服务注册与发现的注册中心。
Monitor: 统计服务的调用次调和调用时间的监控中心。
Container: 服务运行容器。
调用关系说明:
<1>服务容器负责启动,加载,运行服务提供者。
<2>服务提供者在启动时,向注册中心注册自己提供的服务。
<3>服务消费者在启动时,向注册中心订阅自己所需的服务。
<4> 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
<5>服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
<6> 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。 - dubbo的获取
① 官方Maven仓库
阿里巴巴已将Dubbo已发布到Maven中央仓库中:
http://central.maven.org/maven2/com/alibaba/dubbo。
com.alibaba
dubbo
2.6.2
② dubbox/dubbo2.8.4
最新版dubbox集成spring4提供的扩展版本下载地址:
https://github.com/hutai123/dubbox
Dubbo及Dubbox均是基于Maven进行项目管理与构建,源码包下载后导入eclipse进行编译打包即可将dubbox放入本地仓库。
课件资料中已下载该源码包dubbox-master.zip.
应源码时代课程升级要求,Spring版本已整体升至Spring4,所以需要对dubbox的spring版本进行升级,升级过程需要注意以下问题:
编译打包过程如果出现netty测试错误,请在Maven中使用
mvn clean install -Dmaven.test.skip=true
跳过测试。
资料中有升级编译后的管理中心(dubbo-admin-2.8.4a)
和监控中心(dubbo-monitor-simple-2.8.4a-assembly.tar.gz)部署包
相关的jar包请参考使用老师提供的maven仓库。
6. dubbo本地服务化实现
对于传统工程而言,分层的依据是按照包来区分,由于在相同的工程中,所以服务的提供和调用可以方便地实现,但是对于分布式服务架构而言,服务的提供者负责服务的具体实现和接口规范,服务的消费者只关心接口规范即可,但无论是服务提供者还是消费者都会涉及到诸如公共工具类、接口、DO、VO等公共代码,因此,一个最简单的DUBBO服务架构模式如下:
服务提供者: 提供服务接口的实现,发布服务地址,提供服务。
服务消费者:获取服务地址,使用服务接口调用服务,处理服务调用结果。
公共项目:包含公共配置、DO、VO、工具包等…
项目搭建(Maven项目管理方式):
① 创建公共项目工程:普通的Maven工程,提供utils、DO、接口的代码。
pom.xml 无任何依赖
② 创建服务提供者项目:普通的Maven工程(依赖Dubbo),提供服务实现、服务启动功能。
pom.xml
com.alibaba
dubbo
2.6.2
dubbo-api
dubbo-api
0.0.1-SNAPSHOT
com.github.sgroschupf
zkclient
0.1
<!-- junit测试包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
</dependencies>
dubbo-provider.xml
<?xml version="1.0" encoding="UTF-8"?>
<dubbo:application name=“dubbo-test-provider” owner=“sampson”></dubbo:application>
<dubbo:protocol name=“dubbo” port=“20880” ></dubbo:protocol>
<dubbo:registry address=“multicast://239.5.6.7:1234” />
<dubbo:service interface=“cn.itsource.dubbo.core.service.IUserService” ref=“userService”></dubbo:service>
<!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 -->
<dubbo:annotation package="cn.itsource.dubbo.provider.service" />
启动服务监听 String configLocation = "classpath*:/dubbo-provider.xml"; ApplicationContext context = new ClassPathXmlApplicationContext(configLocation); System.out.println("dubbo-server服务正在监听,按任意键退出"); System.in.read(); 7. 服务消费者实现 创建服务消费者项目:普通的Maven工程(依赖Dubbo),完成服务调用功能。 pom.xml com.alibaba dubbo 2.6.2 dubbo-api dubbo-api 0.0.1-SNAPSHOT com.github.sgroschupf zkclient 0.1 dubbo-consumer.xml <?xml version="1.0" encoding="UTF-8"?>
<dubbo:application name="dubbo-test-consumer"></dubbo:application>
<!-- 局域网广播注册中心 -->
<dubbo:registry address="multicast://239.5.6.7:1234" />
<!-- 配置式调用服务 -->
<!-- <dubbo:reference id="helloService" interface="cn.itsource.dubbo.core.service.IHelloService"></dubbo:reference> -->
<!-- 注解式调用服务 -->
<!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 -->
<dubbo:annotation package="cn.itsource.dubbo.consumer" />
JUnit4调用dubbo服务测试类
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.alibaba.dubbo.config.annotation.Reference;
import cn.itsource.dubbo.core.service.IHelloService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({“classpath*:/dubbo-consumer.xml”})
public class DubboServiceTest {
@Reference
private IHelloService helloService;
@Test
public void testHello(){
String sayHi = helloService.sayHi("老宋");
System.out.println(sayHi);
}
}
8. dubbo的服务打包
使用Servlet容器
利用Tomcat、Jetty等WEB容器启动Dubbo服务。
缺点:增加管理配置的复杂性,不必要地使用http端口,浪费内存资源
Java的Main方法(不建议,本地调试可以用)
基于Spring框架,写一个Java类并提供Main方法启动。
缺点:无法使用Dubbo的一些高级特性,服务的管理需要自己额外提供实现
Dubbo框架Main方法
Dubbo框架本身提供了服务运行支持方法,基于com.alibaba.dubbo.container.Main
简单高效地运行服务
很好地支持Dubbo服务的发布、关停(ShutdownHook)
Maven编译打包
Pom.xml
cn.itsource.service
service-user
${service-user.version}
jar
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 打包jar详细配置 -->
<build>
<!-- jar包名字 -->
<finalName>provder</finalName>
<!-- 打包资源配置,如配置文件 -->
<resources>
<resource>
<targetPath>${project.build.directory}/classes</targetPath>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<!-- 结合com.alibaba.dubbo.container.Main
官方文档:dubbo会自动在classes/META-INF/spring下去加载spring的配置文件
因此打包时需要将spring配置文件复制到该目录
-->
<resource>
<targetPath>${project.build.directory}/classes/META-INF/spring</targetPath>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>applicationContext.xml</include>
</includes>
</resource>
</resources>
<pluginManagement>
<plugins>
<!-- 解决Maven插件在Eclipse内执行了一系列的生命周期引起冲突 -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<versionRange>[2.0,)</versionRange>
<goals>
<goal>copy-dependencies</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classesDirectory>target/classes/</classesDirectory>
<archive>
<manifest>
<mainClass>com.alibaba.dubbo.container.Main</mainClass>
<!-- 重要:打包时 MANIFEST.MF文件不记录的时间戳版本 -->
<useUniqueVersions>false</useUniqueVersions>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<type>jar</type>
<includeTypes>jar</includeTypes>
<useUniqueVersions>false</useUniqueVersions>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
</dependencies>
- zookeeper注册中心
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
ZooKeeper包含一个简单的原语集, 提供Java和C的接口。
ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口。其中分布锁和队列有Java和C两个版本,选举只有Java版本。
Zookeeper作为Dubbo服务的注册中心,Dubbo原先基于数据库的注册中心,没采用Zookeeper,Zookeeper是一个分布式的服务框架,是树型的目录服务的数据存储,能做到集群管理数据 ,这里能很好的作为Dubbo服务的注册中心,Dubbo能与Zookeeper做到集群部署,当提供者出现断电等异常停机时,Zookeeper注册中心能自动删除提供者信息,当提供者重启时,能自动恢复注册数据,以及订阅请求。我们先在windows上安装Zookeeper,我们安装最简单的单点,集群环境需要有兴趣的同学主动查找资料并利用虚拟机搭建。
将集成好的项目,使用zookeeper替换multicast广播方式,作为dubbo服务的发布注册中心。
<dubbo:registry address=“zookeeper://127.0.0.1:2181”></dubbo:registry>
10 dubbo管理控制台
Dubbo 管控台可以对注册到 zookeeper 注册中心的服务或服务消费者进行管理,但 管控台是否正常对 Dubbo 服务没有影响,管控台也不需要高可用,因此可以单节点部署。
控制台主要包含: 提供者、 路由 规则 、 动态配置、 访问控制、 权重调节、 负载均衡、 负责人等管理功能,dubbo admin默认使用消息注册中心类型为:zookeeper。
在实际的项目中非常的有用,尤其是在dubbo服务提供数量逐渐加大的情况下,通过Dubbo管理控制台能够很好的被我们所用,从而让我们更好的使用Dubbo提供的服务。
dubbo-admin部署及配置
① 解压 到任意的目录下。
② 复制一份tomcat作为dubbo管理控制台的服务器,并修改对应的端口和Context信息。
③ 配置WEB-INF下dubbo.properties
注意:dubbo.registry.address的值后面有backup代表是集群模式,建议测试取消,保留单机模式。
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
④ 启动管理控制台
bin/startup.bat
⑤ 浏览器访问管理控制台:http://127.0.0.1:端口
默认用户名及密码: root/root guest/guest - dubbo监控中心
Dubbo发布代码中,自带了一个简易的监控中心实现。对于一般的小业务这个监控中心应该能够满足需求,对于那些大业务量的大公司一般都会有自己的监控中心,更加丰富的功能如常用的报警短信通知等等。
监控中心负责为服务的监控运维采集各维度的数据,统计各服务的调用次数、时间等,统计先在服务端和消费端内存中汇总,每隔一分钟发送到监控中心服务器,并以报表的形式展现。
监控中心的作用及特点:
监控中心是独立于服务和管理控制台的,在整个dubbo服务治理环节不是必须的,用户可根据实际情况选择性安装。
监控中心如果出现异常(宕机),并不会影响Provider和Consumer之间的服务调用,但会丢失故障期间的监控数据,再生产环境不会有任何风险。
监控中心可以自定义扩展开发,满足一下需求:
① 个性化运维:服务的健康情况、服务压力及性能分析、告警通知
② 扩展接口:com.alibaba.dubbo.monitor.MonitorFactory
com.alibaba.dubbo.monitor.Monitor
简易监控中心:
SimpleMonitor是官方提供的一个基本功能版本的监控中心,本质上监控中心也是一个标准的dubbo服务。SimpleMonitor采用磁盘存储统计信息,请注意安装机器的磁盘限制,如果要集群,建议用mount共享磁盘,结合Dubbo管理控制台可以清晰地看到服务的访问次数、成功次数、失败次数等基本数据。
简易监控中心部署及配置
① 解压 到任意文件夹目录。
② 更改conf目录下的配置文件dubbo.properties。
③ 启动监控中心
bin/start.bat
④ 查看监控中心服务并访问监控中心
监控中心本身也是一个dubbo服务,因此,如果监控中心成功启动,会在dubbo管理控制中心注册监控服务。
监控中心访问地址:http://localhost:8078
欢迎广大读者的提问,我会第一时间为你们解答,如果你确实学到了东西,那么友情赞助一下以支持文章的继续更新也是可以的。