项目架构演变过程
1、单体架构
单体架构所有模块和功能都集中在一个项目中 ,部署时也是将项目所有功能部整体署到服务器中
- 优点
- 小项目开发快 成本低
- 架构简单
- 易于测试
- 易于部署
- 缺点
- 大项目模块耦合严重 不易开发 维护 沟通成本高
- 新增业务困难
- 核心业务与边缘业务混合在一块,出现问题互相影响
2. 垂直架构
根据业务把项目垂直切割成多个项目,因此这种架构称之为垂直架构。为了避免上面提到的那些问题,可以针对模块做垂直划分,做垂直划分的原则是需要基于产品的业务特性,核心目标,第一个是为了业务之间互不影响,第二个是为了提高效率,减少互相之间的依赖。
- 优点
- 系统拆分实现了流量分担,解决了并发问题
- 可以针对不同系统进行优化
- 方便水平扩展,负载均衡,容错率提高
- 系统间相互独立,互不影响,新的业务迭代时更加高效
- 缺点
- 服务系统之间接口调用硬编码
- 搭建集群之后,实现负载均衡比较复杂
- 服务系统接口调用监控不到位 调用方式不统一
- 服务监控不到位
- 数据库资源浪费,充斥慢查询,主从同步延迟大
3.分布式架构(SOA )
SOA全称为Service Oriented Architecture,即面向服务的架构 。它是在垂直划分的基础上,将每个项目拆分出多个具备松耦合的服务,一个服务通常以独立的形式存在于操作系统进程中。各个服务之间通过网络调用,这使得构建在各种各样的系统中的服务可以 以一种统一和通用的方式进行交互。在上面垂直划分以后,业务模块随之增多,系统之间的RPC逐渐增多,维护的成本也越来越高,一些通用的业务和模块重复的也越来越多,这个时候上面提到的接口协议不统一、服务无法监控、服务的负载均衡等问题更加突出,为了解决上面的这些问题,需要对原有的业务层进一步拆分,将通用的业务逻辑继续下沉到通用服务层,通过接口暴露,供其他业务场景调用。同时引入RPC框架例如阿里巴巴开源的Dubbo来完成服务治理的工作。
- 优点
- 服务以接口为粒度,为开发者屏蔽远程调用底层细节 使用Dubbo 面向接口远程方法调用屏蔽了底层调用细节
- 业务分层以后架构更加清晰 并且每个业务模块职责单一 扩展性更强
- 数据隔离,权限回收,数据访问都通过接口 让系统更加稳定 安全
- 服务应用本身无状态化 这里的无状态化指的是应用本身不做内存级缓存 而是把数据存入db
- 服务责任易确定 每个服务可以确定责任人 这样更容易保证服务质量和稳定
- 缺点
- 粒度控制复杂 如果没有控制好服务的粒度 服务的模块就会越来越多 就会引发 超时 分布式事务等问题
- 服务接口数量不宜控制 容易引发接口爆炸 所以服务接口建议以业务场景进行单位划分 并对相近的业务做抽象 防止接口爆炸
- 版本升级兼容困难 尽量不要删除方法 字段 枚举类型的新增字段也可能不兼容
- 调用链路长 服务质量不可监控 调用链路变长 下游抖动可能会影响到上游业务 最终形成连 锁反应 服务质量不稳定 同时链路的变成使得服务质量的监控变得困难
4.微服务架构
微服务架构是一种将单个应用程序 作为一套小型服务开发的方法,每种应用程序都在其自己的进程中独立运行,并使用轻量级机制(通常是HTTP资源的API)进行通信。这些服务是围绕业务功能构建的,可以通过全自动部署机制进行独立部署。这些服务的集中化管理非常少,它们可以用不同的编程语言编写,并使用不同的数据存储技术。
微服务是在SOA上做的升华 , 粒度更加细致,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”。
Dubbo架构
1、Dubbo 架构概述
Apache Dubbo是一款高性能的Java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。
三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
Dubbo 的服务治理:
服务治理(SOA governance),企业为了确保项目顺利完成而实施的过程,包括最佳实践、架构原则、治理规程、规律以及其他决定性的因素。服务治理指的是用来管理SOA的采用和实现的过程。
参考官网 服务治理的需求
2.Dubbo 处理流程
节点说明:
节点 | 角色名称 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 负责启动 加载 运行服务提供者 |
调用关系说明:
- 虚线 代表异步调用 实线代表同步访问
- 蓝色虚线 是在启动时完成的功能
- 红色虚线 是程序运行中执行的功能
调用流程:
- 服务提供者在服务容器启动时 向注册中心 注册自己提供的服务
- 服务消费者在启动时 向注册中心订阅自己所需的服务
- 注册中心返回服务提供者地址列表给消费者 如果有变更 注册中心会基于长连接推送变更数据给消费者服务消费者 从提供者地址列表中 基于软负载均衡算法 选一台提供者进行调用 如果调用失败 则重新选择一台
- 服务提供者和消费者 在内存中的调用次数 和 调用时间 定时每分钟发送给监控中心
3.服务注册中心Zookeeper
通过前面的Dubbo架构图可以看到,Registry(服务注册中心)在其中起着至关重要的作用。Dubbo官方推荐使用Zookeeper作为服务注册中心。Zookeeper 是 Apache Hadoop 的子项目,作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用。
Zookeeper的安装及其使用见上一模块,此处不再赘述。
4、Dubbo开发实战
在Dubbo中所有的的服务调用都是基于接口去进行双方交互的。双方协定好Dubbo调用中的接口,提
供者来提供实现类并且注册到注册中心上。
调用方则只需要引入该接口,并且同样注册到相同的注册中心上(消费者)。即可利用注册中心来实现集
群感知功能,之后消费者即可对提供者进行调用。
所有的项目都是基于Maven去进行创建,这样相互在引用的时候只需要以依赖的形式进行展现就可以了。
并且这里会通过maven的父工程来统一依赖的版本。
程序实现分为以下几步骤:
- 建立maven工程 并且 创建API模块: 用于规范双方接口协定
- 提供provider模块,引入API模块,并且对其中的服务进行实现。将其注册到注册中心上,对外来
统一提供服务。 - 提供consumer模块,引入API模块,并且引入与提供者相同的注册中心。再进行服务调用。
创建接口
- 创建maven工程,添加依赖管理
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.elvis</groupId>
<artifactId>dubbo-study</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>service-api</module>
<module>service-provider</module>
<module>service-consumer</module>
</modules>
<properties>
<dubbo.version>2.7.8</dubbo.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-netty4</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 日志配置 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<!-- json数据化转换 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
创建api模块
- 创建maven
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dubbo-study</artifactId>
<groupId>com.elvis</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-api</artifactId>
</project>
- 创建接口
package com.elvis.service;
/**
* @author Elvis
* @create 2021-06-13 9:23
*/
public interface HelloService {
String helloService(String name);
}
创建服务提供者
- 创建maven
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dubbo-study</artifactId>
<groupId>com.elvis</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-provider</artifactId>
<dependencies>
<dependency>
<groupId>com.elvis</groupId>
<artifactId>service-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-netty4</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
</dependency>
</dependencies>
</project>
- 创建dubbo配置文件
在resources目录下创建dubbo.properties
dubbo.application.name=dubbo-demo-annotation-provider
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
- 创建接口实现类
package com.elvis.service.impl;
/**
* @author Elvis
* @create 2021-06-13 9:26
*/
import com.elvis.service.HelloService;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.annotation.Service;
/**
* @program: dubbo-study
* @Description
* @author Elvis
* @date 2021-06-13 9:26
*/
@DubboService
public class HelloServiceImpl implements HelloService {
@Override
public String helloService(String name) {
return "hello :" + name;
}
}
- 创建provider的启动类
package com.elvis.main;
/**
* @author Elvis
* @create 2021-06-13 9:27
*/
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.io.IOException;
/**
* @program: dubbo-study
* @Description
* @author Elvis
* @date 2021-06-13 9:27
*/
public class ServiceProviderMain {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
context.start();
System.in.read();
}
@Configuration
@EnableDubbo(scanBasePackages = "com.elvis.service.impl")
@PropertySource("classpath:/dubbo.properties")
static class ProviderConfiguration {
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://192.168.137.144:2181?timeout=10000");
return registryConfig;
}
}
}
- 运行
创建服务消费者
- 创建maven
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dubbo-study</artifactId>
<groupId>com.elvis</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-consumer</artifactId>
<dependencies>
<dependency>
<groupId>com.elvis</groupId>
<artifactId>service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-netty4</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
</dependency>
</dependencies>
</project>
- 创建dubbo配置文件
resources目录下创建dubbo.properties
dubbo.application.name=service-consumer
dubbo.registry.address=zookeeper://192.168.137.144:2181
dubbo.consumer.timeout=4000
- 创建调用代理对象
package com.elvis.bean;
/**
* @author Elvis
* @create 2021-06-13 9:42
*/
import com.elvis.service.HelloService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Component;
/**
* @program: dubbo-study
* @Description
* @author Elvis
* @date 2021-06-13 9:42
*/
@Component
public class ConsumerBean {
@DubboReference
HelloService hello;
public String helloService(String name) {
return hello.helloService(name);
}
}
- 创建消费者的启动类
package com.elvis.main;
/**
* @author Elvis
* @create 2021-06-13 9:41
*/
import com.elvis.bean.ConsumerBean;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.io.IOException;
/**
* @program: dubbo-study
* @Description
* @author Elvis
* @date 2021-06-13 9:41
*/
public class ServiceConsumerMain {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
context.start();
ConsumerBean bean = context.getBean(ConsumerBean.class);
while (true) {
System.in.read();
String hello = bean.helloService("world");
System.out.println("result:"+hello);
}
}
@Configuration
@PropertySource("classpath:/dubbo.properties")
@ComponentScan(basePackages = "com.elvis.bean")
@EnableDubbo
static class ConsumerConfiguration{
}
}
- 运行
如果启动时出现下面的异常 qos-server can not bind localhost:22222, dubbo version: 2.7.8
在配置文件中添加dubbo.application.qosEnable=false
关闭qos功能
或者修改qos绑定的端口dubbo.application.qosPort=33333
- 测试
xml配置方式
参考官网,快速开始指南