Java进阶:Dubbo相关

Dubbo
Dubbo是一款高性能的Java RPC(远程过程调用)框架。

====================================================
<架构发展流程>

单体架构
单体架构所有模块和功能都集中在一个项目中,部署时也是将项目所有功能都整体部署到服务器中。
拉勾网V1.0:
模块:登录/注册、C端业务、B端业务、搜索业务(站内搜索)、admin后台、活动业务(线上短期活动、业务推广等)
MVC结构,SSM框架,所有的业务都放在一个tomcat里。
优点:
小项目开发快,成本低
架构简单
易于测试
易于部署

缺点:
●大项目模块耦合严重,不易开发,维护,沟通成本高
●新增业务困难
●核心业务与边缘业务混合在一块,出现问题相互影响

---------------------------

垂直架构:
按照业务拆分模块,一个主要的功能一个模块。(一个模块部署在一个服务器上)
核心目标:
1.为了业务之间互不影响
2.在研发团队壮大后为了提高效率,减少相互依赖。

优点:
1.系统拆分实现了流量分担,解决了并发问题。
2.可以针对不同系统进行优化。
3.方便水平扩展,负载均衡,容错率提高
4.系统间相互独立,互不影响,新的业务迭代时更加高效

缺点:
1.服务系统之间接口调用硬编码(修改接口不方便)
2.搭建集群后,实现负载均衡比较复杂(如果有服务迁移到另外的机器,那么该服务的ip会变更,会影响线上业务)
3.服务系统接口调用监控不到位,调用方式不统一(设计问题)
4.服务监控不到位(设计问题)
5.数据库资源浪费,充斥慢查询,主从同步延迟大(由于所有服务连接的都是一个数据库,所以会有问题。可以对数据库部署方面进行优化)

---------------------------------------

分布式-SOA架构
SOA全称为Service Oriented Architecture,即面向服务的架构。它是在垂直划分的基础上,将每个项目拆分出多个具备松耦合的服务,一个服务通常以独立的形式存在于操作系统进程中。各个服务之间通过网络调用,这使得构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。
分层思想:将整个项目分为应用层、业务逻辑层、基础业务层、基础服务层、存储层,每层有每个功能不同的模块;
允许上层调用下层,或者上层跨级调用下层;但是不允许下层调用上层,不允许上层直接调用存储层(数据库)。

拉勾v3.0采用了SOA,并且用了Dubbo。
Dubbo:是阿里巴巴开发的一款高性能、轻量级的Java RPC框架,提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务的自动注册和发现。

SOA特点:按照业务性质分层,每一层要求简单,容易维护。

SOA优点:
服务以接口为粒度,为开发者屏蔽远程调用底层细节,使用Dubbo面向接口远程方法调用 屏蔽了底层调用细节
业务分层以后架构更加清晰,并且每个业务模块职责单一,扩展性更强
数据隔离,权限回收,数据访问都通过接口,让系统更加稳定安全
服务应用本身无状态变化,这里的无状态指的是应用本身不做内存级缓存,而是把数据存入db
服务责任易确定,每个服务可以确定责任人,这样更容易保证服务质量和稳定。

SOA缺点:
粒度控制复杂,如果没有控制好服务粒度,服务的模块就会越来越多,就会引发超时、分布式事务等问题。
服务接口数量不宜控制。
版本升级兼容困难。尽量不要删除方法、字段;枚举类型的新增字段也可能不兼容。
调用链路长,服务质量不可监控。


------------------------------------

微服务架构
微服务架构是一种将单个应用程序作为一套小型服务开发的方法,每种应用程序都在其自己的进程中独立运行,并使用轻量级机制(通常是HTTP资源的API)进行通信。这些服务是围绕业务功能构建的,可以通过全自动部署机制进行独立部署。(docker)

微服务强调的一个重点是:业务需要彻底的组件化和服务化。

======================
<Dubbo相关>


Dubbo:
Apache Dubbo是一款高性能的java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开源java RPC框架,可以和Spring框架无缝集成。

2018.2阿里巴巴将Dubbo2.6捐献给了Apache。

Dubbo特性:
面向接口代理的高性能RPC调用;
智能负载均衡;
服务自动注册与发现;(需要服务注册中心,Dubbo推荐用zookeeper做为注册中心)
高度可扩展能力;
运行期流量调度;(灰度发布,将一批服务分批进行发布,稳定后再发布其余的)
可视化的服务治理与运维。

Dubbo处理流程中的节点:
Provider:暴露服务的服务提供方
Consumer:调用远程服务的服务消费方
Registry:服务注册与发现的注册中心
Monitor:统计服务的调用次数和调用时间的监控中心

----------------------

Dubbo开发过程:
服务端编写过程:
1.引入Dubbo相关依赖
2.创建一个service接口,准备给服务端与客户端使用
3.服务端创建一个serviceImpl类,实现service接口,是实际执行的方法。
4.创建一个properties,里面存放dubbo的配置信息,例如dubbo-provider.properties
dubbo.application.name=service-provider
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880

5.创建一个配置类,用于加载dubbo的配置信息,例如:
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableDubbo(scanBasePackages="com.test.service.impl")
@PropertySource("classpath:/dubbo-provider.properties")
public Class ProviderConfiguration{
  @Bean
  public RegistryConfig registryConfig(){
    RegistryConfig registryConfig = new RegistryConfig();
    registryConfig.setAddress("zookeeper://127.0.0.1:2181");
    return registryConfig;
  }

}

6.启动spring项目,Dubbo的生产者(服务器端)就开发完了。

----------------------------------------
Dubbo客户端
1.导入Dubbo依赖,并导入service依赖(供客户端与服务器端使用的service接口所在的项目的依赖)
2.编写一个java类,使用@Reference注解,(调用服务器端的方法并获取返回值,)例如ConsumerComponet.java:

import com.test.service.HelloService;
import org.apache.dubbo.config.annotation.Reference;
public class ComsumerComponet{
  @Reference
  private HelloService helloService;
  public String sayHello(String name){
    return helloService.sayHello(name);
  }
}

3.编写一个配置文件properties,包含dubbo的配置信息,例如dubbo-consumer.properties:
dubbo.application.name=service-consumer
dubbo.registry.address=zookeeper://127.0.0.1:2181

4.创建一个配置类,用于加载dubbo的配置信息,例如AnnotationConsumerMain.java:
public class AnnotationConsumerMain {
  public static void main(String[] args){
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
    context.start();
    //获取消费者组件
    ComsumerComponet service = context.getBean(ComsumerComponet.class);
    //从spring拿出来的是这个service的代理对象,因为标注了注解,所以已经实现了RPC
    while(true){
      System.in.read();
      String hello = service.sayHello("world");
      System.out.println("result:" + hello);
    }
  }

  @Configuration
  @PropertySource("classpath:/dubbo-consumer.properties")
  @ComponentScan(backPackages = "com.test.bean")
  @EnableDubbo
  static class ConsumerConfiguration{
    
  }
}

--------------------
总结:使用dubbo,需要引入依赖jar包,编写客户端与服务器端,定义service,然后创建dubbo配置类与配置信息,使用dubbo的注解,再使用zookeeper做为注册中心,即可实现RPC。

============================
Dubbo配置方式(三种):
1.注解:基于注解可以快速的将程序配置,无需多余的配置信息,包含提供者和消费者。
2.xml:一般这种方式会与spring做结合,相关的service和reference均使用spring集成后的。
3.基于代码方式:基于代码方式进行配置。这个使用的比较少,这种方式更适用于自己公司对其框架与Dubbo做深度集成时才会使用。(使用set值的方式)


------------------------------

Dubbo管理控制台:
1.可以从git上下载,https://github.com/apache/dubbo-admin
2.修改dubbo.properties文件
3.启动项目
4.使用localhost:7001,就可以登录管理控制台,默认用户名与密码都是root
5.之后启动自己之前写的服务提供者项目,就可以在控制台中发现服务了。
6.启动消费者后,也可以在控制台中发现该消费者。

----------------------------------

dubbo的消费者的配置文件中,可以配置
<dubbo:cosumer timeout="2000"></dubbo-consumer>
意思是,如果调用方法2秒后仍没有结果,则超时报错。(防止一直等待,浪费时间)

可以使用mock="true"配置,
<dubbo:reference id="helloService" interface="com.lagou.service.HelloService" mock="true" />

然后写一个本地实现类,例如:
com.test.service.HelloServiceMock.java;
public class HelloServiceMock implements HelloService {
  @Override
  public String sayHello(String name) {
    return "hello mock";
  }
}

当timeout时,就可以调用mock方法,代替远程方法。(当远程方法挂了时,不能一直等待了,就用自己的mock方法当结果)


*注意,客户端配置中,以<dubbo:consumer>中的timeout为主,也就是说会让<dubbo:reference>中的timeout配置失效。

----------------------------------

对应的,dubbo服务端也可以增加timeout配置,用于指定当前方法或接口中所有方法的超时时间,一般会根据提供者的时长来具体规定。

-----------------------

retries:用于指定重试次数。
1.注意提供者是否有幂等,否则可能出现数据一致性问题。
2.注意提供者是否有类似缓存机制,如出现大面积错误时,可能因为不停重试导致雪崩。

可以看dubbo官网的配置说明。

----------------------

dubbo配置了异步调用后,调用方法后不会等待结果返回,而是继续执行代码,可能导致问题。
因此需要异步调用、也需要返回结果时,可以使用Future对象。

//这个是dubbo异步调用的方法(rpc)
String hello = service.sayHello("world");
//这个会输出null,有问题,因为是异步,结果还没有返回。
System.out.println(hello);
//所以要用future
Future<Object> future = RpcContext.getContext().getFuture();
//这样就有值了,就是service.sayHello()返回的值
System.out.println(future.get());


--------------------------------

Dubbo的线程池:

Dubbo中,可以创建2种线程池:
fix:表示创建固定大小的线程池。也是Dubbo默认的使用方式,默认创建的执行线程池为200,并且没有任何等待队列。
cache:创建非固定大小的线程池。当线程不足时,会自动创建新的线程。但是需要注意,如果选择这种方式,当有高TPS的请求过来,方法没有及时完成,则会造成大量线程被创建,对系统的CPU和负载造成压力,拖慢整个系统。


*在真实的使用过程中,通常会用fix线程池,可能会导致某些业务场景中,由于线程池满而产生错误,并且业务研发是无感知的,只有出现错误才能得知。
此时,可以使用自定义线程池,增加线程池监控的相应方法,例如定时打印线程池容量,快满时调用公司邮件系统或短信平台或告警系统,通知相关人员想办法处理。(而不是等待出现错误后才想办法处理)

----------------------------------

Dubbo路由规则:
可以创建一个规则来决定一个请求交给哪个服务器处理。
使用java中的Registry对象的register()方法可以实现,本质上是在zookeeper中保存一个节点数据,来记录路由规则。消费者会通过监听这个服务的路径,来感知整个服务的路由规则配置,然后进行适配。

----------------------------------

Dubbo的路由与上线系统结合:
为了防止某台服务器重启下线时造成发往该服务的请求失败的情况,可以把该机器从机器列表中移除,并且等待一定的时间,让其把现有的请求处理完成之后再关闭服务。
在服务上线时,同样需要等待一定的时间,以免因为尚未重启结束,就已经注册上去。等启动到达一定时间之后,再注册并接收请求。

可以使用Dubbo的Router、RouterFactory实现。(org.apache.dubbo.rpc.cluster.Router)

1.利用zookeeper的路径感知能力,在服务准备进行重启之前将当前机器的IP地址和应用名写入 zookeeper。 
2.服务消费者监听该目录,读取其中需要进行关闭的应用名和机器IP列表并且保存到内存中。 
3.当前请求过来时,判断是否是请求该应用,如果是请求重启应用,则将该提供者从服务列表中移除。

---------------------------------

Dubbo服务动态降级

什么是服务降级?
当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务有策略的降低服务级别,以释放服务器资源,保证核心任务的正常运行。


为什么需要服务降级?
防止分布式服务发生雪崩效应。当一个请求发生超时,一直等待着服务响应,那么在高并发情况下,很多请求都会像这样一直等着响应,直到服务资源耗尽产生宕机,而宕机之后会导致分布式其他服务调用该宕机的服务也会出现资源耗尽宕机,这样下去将导致整个分布式服务都瘫痪。

Dubbo实现服务降级的几种方式:

1.在Dubbo管理控制台配置服务降级
登录控制台->服务治理->消费者->点击"屏蔽"按钮
表示消费方对服务的调用都直接返回null值,不进行远程调用。用来屏蔽不重要服务不可调用时对调用方的影响。

登录控制台->服务治理->消费者->点击"容错"按钮
表示消费方对该服务的方法在调用失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

2.在xml或注解中指定返回简单值或null
<dubbo:reference id="xxService2" check="false" interface="com.xx.XxService2" timeout="3000" mock="return 1234" />
@Reference(mock="force:return null")

3.使用java代码动态写入配置中心

4.整合hystrix

------------------------------

Dubbo粘包和拆包问题:
Dubbo协议采用固定长度的消息头(16字节)和不定长度的消息体来进行数据传输。(也就是说Dubbo有自己的数据包格式)
由于Dubbo是基于TCP的,当TCP封装数据包时,可能会出现以下情况:
1.TCP包中只包含一个dubbo数据包的一部分 
2.TCP包中正好包含一个dubbo数据包
3.TCP包中包含一个dubbo数据包与另一个dubbo数据包的一部分

处理方式:
1.TCP包中只包含一个dubbo数据包的一部分时,程序会继续读取下一个TCP包,直到拼成一个完整的dubbo数据包。(TCP拆了包,Dubbo要粘好包)
2.TCP包中正好包含一个dubbo数据包,程序可以读取并解析。
3.TCP包中包含一个dubbo数据包与另一个dubbo数据包的一部分,程序要进行拆包,处理完整的dubbo数据包;对于不完整的dubbo数据包,则继续读取、拼完整后处理。(TCP粘包,Dubbo要拆包)


==================================
==================================
==================================

总结:

使用Dubbo,需要开发一个服务提供者(provider),开发一个服务调用者(consumer),并给它们配置好注册中心(例如zookeeper)的地址。
启动provider,它会将自己提供的服务注册到zookeeper上。
启动consumer,它会也将自己注册到zookeeper上。

在consumer中调用服务时,实际上是先从zookeeper上获取provider注册的真实服务的url,然后通过rpc方式向provider发起请求,provider执行真实服务后返回给consumer结果。

还可以从git上下载Dubbo管理控制台,它实际上是连接了zookeeper,获取并展示注册了的provider与consumer,并可以进行一些控制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追逐梦想永不停

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值