软件架构的发展经历了单体架构、垂直架构、SOA架构、微服务架构的演进过程。
1、单体架构:
单体架构中,所有功能代码全部都在同一个部署包中。
单体架构优点:
架构简单,前期开发成本低、开发周期短,适合小型项目(OA、CRM、ERP 企业内部应用)
单体架构缺点:
1.1.代码模块边界很混乱,只会越来越乱!
1.2.随着代码的增加,构建和部署的时间也会增加
1.3.技术革新很难,想要引入新的框架或技术平台非常困难。
1.4.团队协作难度高,如多人使用 git 很可能在同一个功能上,多人同时进行了修改,作为一个大而全的项目,可能个人只是需要开发其中一个小的模块的需求,却需要导入整个项目全量的代码
2、垂直架构
按照业务进行切割,形成小的单体项目。
垂直架构优点:技术栈可扩展(不同的系统可以用不同的编程语言编写)
垂直架构缺点:
2.1 垂直架构中每一个系统还是单体架构
2.2 项目之间功能冗余、数据冗余,多个项目中可能要编写重复的功能代码,加载重复的数据。
项目之间没有联系,导致代码重复,比如三个过程都会要用户和商品代码。
3、SOA架构
SOA全称为 "Service-Oriented Architecture",即面向服务的架构。
它可以根据需求通过网络对松散耦合的粗粒度应用组件(服务)进行分布式部署、组合和使用。一个服务通常以独立的形式存在于操作系统进程中。
SOA架构的优点
① 可重用性高
重复功能或模块抽取为服务,提高开发效率。
② 维护成本低
修改一个功能,可以直接修改一个项目,单独部署。
③ 可扩展性强
不同的系统可以用不同的语言、不同的技术进行编写。并且可以按照需要,对不同的系统进行集群扩充
SOA架构的缺点
① 抽取服务的粒度大(相对微服务而言)
各系统之间业务不同,很难确认功能或模块是重复的
4、微服务架构
微服务是在 SOA 上做的升华,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”。
原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。这些小应用之间通过服务完成交互和集成。
微服务的优点
① 服务拆分粒度更细,遵循单一职责原则,有利于提高开发效率。
② 可采用Http协议进行服务间的调用
③ 可以针对不同服务制定对应的优化方案,适用于互联网时代,产品迭代周期更短。
微服务的缺点
① 对开发团队技术要求高
Apache Dubbo是一款高性能的Java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。
Dubbo官网地址:Apache Dubbo
Dubbo提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
RPC 远程过程调用
RPC并不是一个具体的技术,而是指整个网络远程调用过程。
比如两台服务器A和B,A服务器上部署一个应用,B服务器上部署一个应用,A服务器上的应用想调用B服务器上的应用提供的方法,由于两个应用不在一个内存空间,不能直接调用,所以需要通过网络来表达调用的语义和传达调用的数据。
Dubbo Java中的RPC框架
Java中的RPC框架比较多,广泛使用的有RMI、Hessian、Dubbo等。
监控中心:统计服务的调用次数和调用时间的监控中心
Container:服务运行容器
服务容器负责启动,加载,运行服务提供者。
服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者在启动时,向注册中心订阅自己所需的服务。
注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
服务消费者,从提供者地址列表中,基于负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
蓝色虚线:在启动时完成的功能
服务注册中心Zookeeper
Dubbo官方推荐使用Zookeeper作为服务注册中心。
zookeeper为什么能作为注册中心?做注册中心需要有哪些能力?
1.记录数据(消费者与提供者的地址)
2.有监控变化,从而及时推送的功能
Zookeeper
Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用 。
Zookeeper树型目录服务:
流程说明:
· 服务提供者(Provider)启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址
· 服务消费者(Consumer)启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址
· 监控中心(Monitor)启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址
安装Zookeeper
下载地址:Index of /dist/zookeeperhttp://archive.apache.org/dist/zookeeper/当然,我直接用老师给的,将压缩包解压到Windows/Linux电脑的没有中文的路径下即可
配置Zookeeper
将conf
目录中的zoo_sample.cfg
文件复制一份到conf
目录并命名为zoo.cfg
修改zoo.cfg
文件: 大概在第12行,设置dataDir=../data
在zookeeper的安装目录中,创建data
目录
启动、停止Zookeeper
启动Zookeeper: 进入bin
目录,双击zkServer.cmd
停止Zookeeper: 关闭Zookeeper的DOS窗口
1、开发服务提供者
创建maven工程用一种神奇的插件把它改成maven形式的web工程,
然后是在pom文件中导入依赖,,,真的是无语,幸好咱只是复制而已
- <packaging>war</packaging>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
- <spring.version>5.0.5.RELEASE</spring.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jdbc</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-aspects</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jms</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context-support</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <!-- dubbo相关 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>dubbo</artifactId>
- <version>2.6.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.zookeeper</groupId>
- <artifactId>zookeeper</artifactId>
- <version>3.4.7</version>
- </dependency>
- <dependency>
- <groupId>com.github.sgroschupf</groupId>
- <artifactId>zkclient</artifactId>
- <version>0.1</version>
- </dependency>
- <dependency>
- <groupId>javassist</groupId>
- <artifactId>javassist</artifactId>
- <version>3.12.1.GA</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.47</version>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-maven-plugin</artifactId>
- <version>9.4.15.v20190215</version>
- <configuration>
- <!-- 如果检测到项目有更改则自动热部署,每隔n秒扫描一次。默认为0,即不扫描-->
- <scanIntervalSeconds>2</scanIntervalSeconds>
- <webAppConfig>
- <!--指定web项目的根路径,默认为/ -->
- <contextPath>/</contextPath>
- </webAppConfig>
- <httpConnector>
- <!--端口号,默认 8080-->
- <port>8000</port>
- </httpConnector>
- </configuration>
- </plugin>
- </plugins>
- </build>
创建提供者服务的接口
- public interface HelloService {
- public String sayHello(String name);
- }
创建提供者服务的服务实现类
重点注意这里的@Service注解
注意`Service`注解要导入`com.alibaba.dubbo.config.annotation.Service`,用于对外发布服务
- @Service
- public class HelloServiceImpl implements HelloService {
- @Override
- public String sayHello(String name) {
- return "Hello "+name+" , I see you";
- }
- }
创建applicationContext-service.xml
在spring的配置文件,注册服务,创建在src/main/resources下
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
- <!--dubbo的配置:向注册中心注册服务-->
- <!--1.配置应用名:要求每一个应用的应用名唯一-->
- <dubbo:application name="dubbodemo-provider" />
- <!--2.配置注册中心地址-->
- <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
- <!--
- 3.配置rpc协议,name表示协议名,port表示提供者的端口号默认是20880,每一个提供者的端口号应该唯一
- -->
- <dubbo:protocol name="dubbo" port="20881"/>
- <!--
- 4. dubbo的包扫描
- -->
- <dubbo:annotation package="com.atguigu"/>
- </beans>
创建的位置参考图如下:
通过jetty
插件启动服务提供者
配置web.xml
让它帮我们启动spring的配置文件
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
- version="4.0">
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:applicationContext*.xml</param-value>
- </context-param>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- </web-app>
2、开发服务消费者
创建服务消费者工程,命名为dubbodemo-consumer
,通过插件改成javaweb
工程
pom文件中导入让人无语到极致的依赖,,
- <packaging>war</packaging>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
- <spring.version>5.0.5.RELEASE</spring.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jdbc</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-aspects</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jms</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context-support</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <!-- dubbo相关 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>dubbo</artifactId>
- <version>2.6.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.zookeeper</groupId>
- <artifactId>zookeeper</artifactId>
- <version>3.4.7</version>
- </dependency>
- <dependency>
- <groupId>com.github.sgroschupf</groupId>
- <artifactId>zkclient</artifactId>
- <version>0.1</version>
- </dependency>
- <dependency>
- <groupId>javassist</groupId>
- <artifactId>javassist</artifactId>
- <version>3.12.1.GA</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.47</version>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-maven-plugin</artifactId>
- <version>9.4.15.v20190215</version>
- <configuration>
- <webAppConfig>
- <!--指定web项目的根路径,默认为/ -->
- <contextPath>/</contextPath>
- </webAppConfig>
- <httpConnector>
- <!--端口号,默认 8080-->
- <port>8082</port>
- </httpConnector>
- </configuration>
- </plugin>
- </plugins>
- </build>
创建消费者服务接口
因为和提供者服务接口一样,直接复制就好。(这里明显感觉代码重复了,为一会优化做铺垫)
- public interface HelloService {
- public String sayHello(String name);
- }
创建HelloController
Controller中注入HelloService使用的是Dubbo提供的@Reference注解,而不再是我们以前的@Autowired了
注意这里的@Reference是alibaba包下的
- @Controller
- @RequestMapping("/demo")
- public class HelloController {
- @Reference
- private HelloService helloService;
-
- @RequestMapping("/hello")
- @ResponseBody
- public String getName(String name){
- //基于接口远程调用服务
- String result = helloService.sayHello(name);
- System.out.println(result);
- return result;
- }
- }
创建applicationContext-web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
- <!--1. springmvc的配置-->
- <!--1.1 包扫描-->
- <context:component-scan base-package="com.atguigu"/>
-
-
- <!--2. dubbo的配置-->
- <!--2.1 配置应用名-->
- <dubbo:application name="dubbodemo-consumer"/>
- <!--2.2 配置注册中心的地址-->
- <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
- <!--2.3 配置dubbo的包扫描-->
- <dubbo:annotation package="com.atguigu"/>
- <!--2.4 配置启动时不检查:当启动消费者的时候不检查是否有提供者-->
- <dubbo:consumer check="false"/>
- </beans>
创建位置参考:
消费者服务配置web.xml
看的我都有点想哭,虽然都学过,也都能看得懂,但是真的烦啊,咋看着这么多
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
- version="4.0">
- <servlet>
- <servlet-name>dispatcherServlet</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:applicationContext-web.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>dispatcherServlet</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
-
- <!-- 配置过滤器解决 POST 请求的字符乱码问题 -->
- <filter>
- <filter-name>CharacterEncodingFilter</filter-name>
- <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
- <!-- encoding参数指定要使用的字符集名称 -->
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- <!-- 请求强制编码 -->
- <init-param>
- <param-name>forceRequestEncoding</param-name>
- <param-value>true</param-value>
- </init-param>
- <!-- 响应强制编码 -->
- <init-param>
- <param-name>forceResponseEncoding</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>CharacterEncodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </web-app>
使用jetty
插件启动服务消费者
启动测试
注意顺序:先启动注册中心,再启动提供者、消费者
然后在浏览器输入 http://localhost:8082/demo/hello?name=Alice
查看浏览器输出结果
优化及一些思考
记得我前面提过,在服务提供者工程(dubbodemo-provider)和服务消费者工程(dubbodemo-consumer)俩个的HelloService接口是一模一样的。
解决方案:单独创建一个maven工程,将此接口创建在这个maven工程中。需要依赖此接口的工程只需要在自己工程的pom.xml文件中引入maven坐标即可。
在服务消费者工程(dubbodemo-consumer)中只是引用了HelloService接口,并没有提供实现类,Dubbo是如何做到远程调用的?
答:Dubbo底层是基于代理技术为HelloService接口创建代理对象,远程调用是通过此代理对象完成的。
Zookeeper服务这么重要 ,如何防止Zookeeper单点故障呢?
答:Zookeeper其实是支持集群模式的,可以配置Zookeeper集群来达到Zookeeper服务的高可用,防止出现单点故障
创建工程service-api,
pom文件也是什么依赖都没有引入,干干净净
创建HelloService接口,参考位置如下:
最终
① 删除服务提供者和服务消费者中的HelloService
接口
② 在服务提供者和服务消费者的pom.xml
中添加依赖service-api
- <dependency>
- <groupId>com.atguigu</groupId>
- <artifactId>service-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
重新启动服务,测试是没问题的,我还是经得住考验的!
Dubbo管理控制台
搭建监控中心,实则就是一个war包。
那怎么运行一个war包呢?
将dubbo-admin-2.6.0.war文件复制到tomcat的webapps目录下,启动Tomcat,此时war文件会自动解压
进入解压的目录中修改WEB-INF下的dubbo.properties文件
1.我们取巧,先启动tomcat,这样就能让tomcat帮我们解压这个war包了,我们再关了tomcat,“X”掉小黑窗,把这个解压的war包删了(这步很重要)
去bin目录下找到,双击启动tomcat
2.进入解压的目录中修改WEB-INF下的dubbo.properties文件
- dubbo.registry.address=zookeeper://127.0.0.1:2181
- dubbo.admin.root.password=root
- dubbo.admin.guest.password=root
注意dubbo.registry.address对应的值需要对应当前使用的Zookeeper的ip地址和端口号