传统项目:面向企业,如OA( 办公自动化系统 ),HR( 人力资源 ),CRM( 客户资源管理系统 )…
互联网项目:面向个人用户,如淘宝,京东,微信…
互联网项目特点:①用户多②流量大,并发高③海量数据④易受攻击无⑤功能繁琐⑥变更快
大型互联网项目架构目标
衡量性能指标
响应时间:指执行一个请求从开始到最后收到响应数据所花费的总体时间。
并发数:指系统同时能处理的请求数量。
并发连接数:指的是客户端向服务器发起请求,并建立了TCP连接。每秒钟服务器连接的总TCP数量
请求数:也称为QPS(Query Per Second) 指每秒多少请求.
并发用户数:单位时间内有多少用户
吞吐量:指单位时间内系统能处理的请求数量。
一个项目部署在多个服务器上
集群的目的就是为了,增加服务器缓解客户端的请求压力。
特点:
可扩展性:集群的性能不限制于单一的服务实体,新的服务实体可以动态的添加到集群,从而增强集群的性能。
高可用行:一台服务器的宕机不会影响整体的使用。
高可管理:管理部署服务器时,由于每台服务器都是一样的,由此部署难度小,就像单台机器一样
必须具备的能力:
缺点
将一个项目分为多个子项目,部署在多个服务器上
分布式目的就是为了解决业务量过大,代码量过于庞大,维护困难等问题,产生的。
引入分布式系统,既方便了代码的测试与维护,也方便了开发,不会有各个子项目之间的冲突
特点:
缺点
分布式服务依赖网络
维护成本高
一致性,可用性,分区容错性无法同时满足
一致性©:在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):保证每个请求不管成功或者失败都有响应。
分区容忍性§:系统中任意信息的丢失或失败不会影响系统的继续运作。
单体架构
多个模块放在一个应用程序,部署集群(多机单体架构),部署在一个服务器(单机单体架构)
优点:
缺点:
垂直架构
单体架构中多个模块拆分为多个独立的项目,形成多个独立的单体架构
优点
缺点
分布式架构
将公共业务(重复)模块抽取出来,其他模块调用该模块,以实现服务的共享和重用。
RPC: Remote Procedure Call远程过程调用。有非常多的协议和技术来都实现了RPC的过程。比如: HTTP REST风格,JavaRMI规范、WebService SOAP协议、 Hession等等。
优点
缺点
SOA架构
SOA:(Service-Oriented Architecture,面向服务的架构)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和契约联系起来。
微服务架构
微服务架构是在SOA上做的升华,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”,原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。这些小应用之间通过服务完成交互和集成。
微服务架构= 80%的SOA服务架构思想+100%的组件化架构思想+80%的领域建模思想。
特点:
服务实现组件化:开发者可以自由选择开发技术。也不需要协调其他团队。
服务之间交换一般使用REST API。
去中心化:每个微服务有自己私有的数据库持久化业务数据。
自动化部署:把应用拆分成一个一个独立的单个服务,方便自动化部署,测试,运维。
Dubbo是阿里巴巴公司(已贡献给apache)开源的一个高性能,轻量级的Java RPC框架
RPC:远程过程调用
致力于提供高性能透明化的RPC远程服务调用方案,以及SOA服务治理方案
角色
服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
容器(Container):服务提供者所在的容器
消费者要去调用 服务提供者 ,但是不能直接调用
服务提供者需要运行在Container中,将服务提供者启动起来
启动起来后,然后向注册中心注册自己的服务
消费者发现从注册中心发现服务
消费者从注册中心获取服务,注册中心返回服务
拿到服务路径后,消费者调用服务生产者
监控中心监控服务生产者和消费者的调用次数和调用时间
使用Zookper作为注册中心
在官网http://zookeeper.apache.org/下载zookeeper安装包.
conf
目录下,备份zoo_example.cfg
并 将zoo_example.cfg
重命名为zoo.cfg
引入依赖
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-spring-boot-starterartifactId>
<version>2.7.8version>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-registry-zookeeperartifactId>
<version>2.7.8version>
dependency>
配置Dubbo
server:
port: 8081
dubbo:
registry:
address: zookeeper://127.0.0.1:2181
application:
name: dubbo-provider
protocol:
port: 20880
scan:
base-packages: com.example.dubboprovider.service
创建Service层
ProviderUser
public interface ProviderUserService {
String getName();
}
ProviderUserServiceImpl
@DubboService
public class ProviderUserServiceImpl implements ProviderUserService {
@Override
public String getName() {
System.out.println("======dubbo接口被调用了======");
return "DubboTest";
}
}
DubooConsumerApplication配置运行类
@SpringBootApplication
@EnableDubbo //开启Dubbo
public class DubooConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DubooConsumerApplication.class, args);
}
}
引入依赖
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-spring-boot-starterartifactId>
<version>2.7.8version>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-registry-zookeeperartifactId>
<version>2.7.8version>
dependency>
<dependency>
<groupId>com.examplegroupId>
<artifactId>Dubbo--providerartifactId>
<version>0.0.1-SNAPSHOTversion>
、 dependency>
配置yml文件
server:
port: 8082
dubbo:
registry:
address: zookeeper://127.0.0.1:2181
application:
name: dubbo-consumer
protocol:
port: 20881
# 协议名字好像为dubbo
name: dubbo
scan:
base-packages: com.example.dubooconsumer.service
Service层
ConsumerUserService
public interface ConsumerUserService {
String userName();
}
ConsumerUserServiceImpl
@DubboReference
远程注入
- 从zookeeper注册中心获取userService的访问url
- 进行远程调用RPC
- 将结果封装为一个代理对象,给变量赋值
@DubboService
public class ConsumerUserServiceImpl implements ConsumerUserService {
@DubboReference
private ProviderUserService providerUserService;
@Override
public String userName() {
return providerUserService.getName();
}
}
编写 UserController
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private ConsumerUserService consumerUserService;
@GetMapping("/user_name")
public String userName(){
return consumerUserService.userName();
}
}
IDEA 启动服务提供者
IDEA 启动服务消费者
dubbo-admin管理平台,是图形化的服务管理页面。
从注册中心中获取到所有的提供者/消费者进行配置管理
路由规则、动态配置、服务降级、访问控制、权重调整、负载均衡等管理功能
dubbo-admin是一个前后端分离的项目。前端使用vue,后端使用springboot
安装dubbo-admin其实就是部署该项目
进入github,搜索dubbo-admin (https://github.com/apache/dubbo-admin)
mvn clean package
切换到目录
dubbo-Admin-develop\dubbo-admin-distribution\target>
执行
java -jar .\dubbo-admin-0.5.0-SNAPSHOT.jar
dubbo-admin-ui 目录下
执行命令
npm run dev
地址栏输入 http://localhost:38082/
*
代表查询所有服务
点击详情界面,主要分为3个区域
两个资源/网络之间传递数据,需要通过流的管道(二进制)的方式来传递
dubbo内部已经将序列化和反序列化的过程内部封装了
我们只需要在定义model类时实现serializable接口即可
一般会定义一个model模块,让生产者消费者都依赖该模块
不继承
Serializable
接口
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
}
<dependency>
<groupId>com.example.dubbo_modelgroupId>
<artifactId>Dubbo--modelartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
ProviderUserService
public User getUserById(int user_id);
ProviderUserServiceImpl
@Override
public User getUserById(int user_id) {
return new User(1,"xiaowang","123456");
}
ConsumerUserService
public User getUserById(int user_id);
ConsumerUserServiceImpl
@Override
public User getUserById(int user_id) {
return providerUserService.getUserById(user_id);
}
@GetMapping("/getUserById")
public User getUserById(int user_id) {
return consumerUserService.getUserById(user_id);
}
报错
java.lang.IllegalStateException: Serialized class com.dubbo.model.User must implement java.io.Serializable
给model-user实现序列化接口
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Integer id;
private String username;
private String password;
}
成功
前端页面得到User对象
{"id":1,"username":"xiaowang","password":"123456"}
注册中心挂了,服务是否可以正常访问?
服务消费者调用服务生产者时候发生了堵塞,等待情形,服务消费者会一直等待下去
在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩。
dubbo使用超时机制,设置一个超时时间,若超过该时间,还无法完成服务访问,会自动断开该访问
dubbo通过属性timeout
设置超时时间,默认为1000,单位为毫秒
该属性可在配置文件中配置,也可以在@DubboService
和@DubboReference
中设置
如果出现网络抖动,则这一次请求就会失败。
网络抖动:因为某些原因网络,断开了一下
当这个断开时间大于超时时间,就会造成用户无法请求的影响。
dubbo使用重试机制,当发生抖动,会重新发送该次请求;
dubbo通过属性retries
来设置重试次数,默认为2
version
属性来设置和调用同一个接口的不同版本当有一个服务消费者去访问服务,此时有多个服务提供者,该访问哪个?
dubbo有负载均衡策略
Dubbo负载均衡策略(4种)
①Random:按权重随机,默认值,
dubbo通过weight
属性设置权重
② RoundRobin:按权重轮询
③ LeastActive:最少活跃调用数,相同活跃度随机
④ ConsistentHash:一致性hash,相同参数请求总是访问同一服务
服务消费者访问服务,若某个服务提供者出错,dubbo如何调用?
通过cluster
属性设置容错模式
容错模式:
Failover Cluster:失败重试。默认值。当出现失败,重试其它服务器,默认重试2次,使用retries
配置。一般用于读操作
Failfast Cluster:快速失败,只发送一次调用,失败立即报错。通常用于写操作
Failsafe Cluster:失败安全,出现异常时,直接忽略,返回一个空结果
Failback Cluster:失败自动恢复,后台记录失败请求,定时重发
某个服务必须调用成功,失败之后后台记录失败,定时重新调用,直至调用成功
Forking Cluster:并行调用多个服务器,只要成功一个即返回
Broadcast Cluster:广播调用所有提供者,逐个报错,任意一台报错则报错。
用于服务消费者要同步更新多个服务的数据,数据要保持同步
服务消费者有三个服务:
例如:广告服务,日志服务,支付服务(比如支付服务比较重要),当cpu资源快满了,我们就需要把不太重要的资源释放掉,保证核心(支付服务)服务的正常运行。
服务降级方式
mock=force:return null
表示消费方该服务的方法调用都直接返回null,不发起远程调用。用来屏蔽不重要服务不可用时对方调用的影响mock=fail:return null
表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。