-
Dubbo
2019-08-07 20:15:59Dubbo什么是Dubbo为什么要用Dubbo什么是分布式?为什么要分布式? 什么是Dubbo Apache Dubbo是一款高性能、轻量级的开源Java RPC 框架,它提供了三大核心能力: 面向接口的远程方法调用 智能容错和负载均衡 服务自动...什么是Dubbo
Apache Dubbo是一款高性能、轻量级的开源Java RPC 框架,它提供了三大核心能力:
- 面向接口的远程方法调用
- 智能容错和负载均衡
- 服务自动注册和发现
简单来说Dubbo就是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
Dubbo 目前已经有接近30k的 Star ,Dubbo的Github 地址:https://github.com/apache/incubator-dubbo 。
Dubbo 是由阿里开源,后来加入了 Apache 。正式由于 Dubbo 的出现,才使得越来越多的公司开始使用以及接受分布式架构。
为什么要用Dubbo
Dubbo的诞生和SOA分布式架构的流行有着莫大的关系。SOA 面向服务的架构(Service Oriented Architecture),也就是把工程按照业务逻辑拆分成服务层和表现层。服务层中包含业务逻辑,只需要对外提供服务即可。表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。
SOA架构中有两个主要角色:服务提供者(Provider)和服务使用者(Consumer)。
如果要开发分布式程序,也可以直接基于 HTTP 接口进行通信,那为什么要用Dubbo呢?
我认为主要可以从Dubbo提供的下面四点特性来说明:- 负载均衡——同一个服务部署在不同的机器时该调用那一台机器上的服务
- 服务调用链路生成——随着系统的发展,服务越来越多,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。Dubbo可以为我们解决服务之间互相是如何调用的
- 服务访问压力以及时长统计、资源调度和治理——基于访问压力实时管理集群容量,提高集群利用率
- 服务降级——某个服务挂掉之后调用备用服务
另外,Dubbo 除了能够应用在分布式系统中,也可以应用在现在比较火的微服务系统中。不过,由于Spring Cloud在微服务中应用更加广泛,所以,一般我们提 Dubbo 的话,大部分是分布式系统的情况。
我们刚刚提到了分布式这个概念,下面再给大家介绍一下什么是分布式?为什么要分布式?
什么是分布式?
分布式重要的就是面向服务,或者说简单的分布式就是我们把整个系统拆分成不同的服务然后将这些服务放在不同的服务器上减轻单体服务的压力提高并发量和性能。比如电商系统可以简单地拆分成订单系统、商品系统、登录系统等等,拆分之后的每个服务可以部署在不同的机器上,如果某一个服务的访问量比较大的话也可以将这个服务同时部署在多台机器上。
为什么要分布式?
从开发角度来讲单体应用的代码都集中在一起,而分布式系统的代码根据业务被拆分。所以,每个团队可以负责一个服务的开发,这样提升了开发效率。
此外,代码根据业务拆分之后更加便于维护和扩展。
还有,将系统拆分成分布式之后不光便于系统扩展和维护,更能提高整个系统的性能。 -
dubbo
2018-09-01 22:10:48dubbo是什么? dubbo的架构 节点角色说明 调用关系说明 连通性 健壮性 伸缩性 dubbo默认使用什么通信协议? Dubbo超时重试机制带来的数据重复问题 dubbo连接注册中心和直连的区别 Dubbo在安全机制方面是...目录
dubbo是什么?
dubbo是一个分布式框架,远程服务调用的分布式框架
dubbo能做什么?
- 透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
- 软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
- 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
dubbo的架构
节点角色说明
- Provider: 暴露服务的服务提供方。
- Consumer: 调用远程服务的服务消费方。
- Registry: 服务注册与发现的注册中心。
- Monitor: 统计服务的调用次调和调用时间的监控中心。
- Container: 服务运行容器。
调用关系说明
0.服务容器负责启动,加载,运行服务提供者。
1.服务提供者在启动时,向注册中心注册自己提供的服务。
2.服务消费者在启动时,向注册中心订阅自己所需的服务。
3.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
4.服务消费者,从提供者地址列表中,基于软负载均衡算法(负载均衡算法包括轮询法、随机法、最少活跃调用数、一致性Hash等),选一台提供者进行调用,如果调用失败,再选另一台调用。
5.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。
连通性
- 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
- 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
- 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
- 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
- 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
- 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
- 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
- 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者
健壮性
- 监控中心宕掉不影响使用,只是丢失部分采样数据
- 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
- 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
- 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
- 服务提供者无状态,任意一台宕掉后,不影响使用
- 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
伸缩性
- 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
- 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者
dubbo默认使用什么通信协议?
dubbo共支持如下几种通信协议:
- dubbo: 单一长连接和NIO异步通讯,适合大并发小数据量的服务调用,以及消费者远大于提供者。传输协议TCP,异步,Hessian序列化;
- rmi: 采用JDK标准的rmi协议实现,传输参数和返回参数对象需要实现Serializable接口,使用java标准序列化机制,使用阻塞式短连接,传输数据包大小混合,消费者和提供者个数差不多,可传文件,传输协议TCP。 多个短连接,TCP协议传输,同步传输,适用常规的远程服务调用和rmi互操作。在依赖低版本的Common-Collections包,java序列化存在安全漏洞;
- webservice: 基于WebService的远程调用协议,集成CXF实现,提供和原生WebService的互操作。多个短连接,基于HTTP传输,同步传输,适用系统集成和跨语言调用;
- http: 基于Http表单提交的远程调用协议,使用Spring的HttpInvoke实现。多个短连接,传输协议HTTP,传入参数大小混合,提供者个数多于消费者,需要给应用程序和浏览器JS调用;
- hessian: 集成Hessian服务,基于HTTP通讯,采用Servlet暴露服务,Dubbo内嵌Jetty作为服务器时默认实现,提供与Hession服务互操作。多个短连接,同步HTTP传输,Hessian序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件;
- memcache: 基于memcached实现的RPC协议
- redis: 基于redis实现的RPC协议
Dubbo超时重试机制带来的数据重复问题
Dubbo的超时重试机制为服务容错、服务稳定提供了比较好的框架支持,但是在一些比较特殊的网络环境下(网络传输慢,并发多)可能由于服务响应慢,Dubbo自身的超时重试机制(服务端的处理时间超过了设定的超时时间时,就会有重复请求)可能会带来一些麻烦。
常见的应用场景故障: 1、发送邮件(重复) ;2、账户注册(重复)。解决方案:
1.对于核心的服务中心,去除dubbo超时重试机制,并重新评估设置超时时间。(1)、去掉超时重试机制
<dubbo:provider delay="-1" timeout="6000" retries="0"/>
(2)、重新评估设置超时时间
<dubbo:service interface="*.*" ref="*" timeout="延长服务时间"/>
2.业务处理代码必须放在服务端,客户端只做参数验证和服务调用,不涉及业务流程处理。
dubbo连接注册中心和直连的区别
1)直连方式
在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连, 点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表
2)注册中心方式
而服务注册中心,动态的注册和发现服务,使服务的位置透明,并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover, 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
Dubbo在安全机制方面是如何解决的
Dubbo通过Token令牌防止用户绕过注册中心直连,然后在注册中心上管理授权。Dubbo还提供服务黑白名单,来控制服务所允许的调用方
一般使用什么注册中心,还有其他的选择吗?
Multicast注册中心 Zookeeper注册中心 Redis注册中心 Simple注册中心
1、当服务提供者启动时,Zookeeper向/dubbo/com.foo.BarService/providers目录下写入服务提供者的URL地址。
2、当服务消费者启动时,这时候有两个动作:
订阅/dubbo/com.foo.BarService/providers目录下的服务提供者URL地址。 并向/dubbo/com.foo.BarService/consumers目录下写入服务消费者的URL地址。
3、当监控中心启动时,订阅/dubbo/com.foo.BarService目录下的所有提供者和消费者URL地址。
服务提供者能实现失效踢出的原理
服务失效踢出是基于Zookeeper的临时节点原理。
zookeeper中节点是有生命周期的.具体的生命周期取决于节点的类型.节点主要分为
持久节点(Persistent)
和临时节点(Ephemeral)
,但是更详细的话还可以加上时序节点(Sequential)
,创建节点中往往组合使用,因此也就是4种.- 持久节点
- 持久顺序节点
- 临时节点
- 临时顺序节点
其实不要纠结于分为几种,这就和语文的断句一样,你断句的方法不同,断出来的结果也不同.那么我们主要讲讲
持久节点
和临时节点
的区别持久节点
所谓持久节点,是指在节点创建后,就一直存在,直到有删除操作来主动清除这个节点,也就是说不会因为创建该节点的客户端会话失效而消失
临时节点
临时节点的生命周期和客户端会话绑定,也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉
应用场景
在分布式系统中,我们常常需要知道某个机器是否可用,传统的开发中,可以通过Ping某个主机来实现,Ping得通说明对方是可用的,相反是不可用的,ZK 中我们让所有的机器都注册一个临时节点,我们判断一个机器是否可用,我们只需要判断这个节点在ZK中是否存在就可以了,不需要直接去连接需要检查的机器,降低系统的复杂度
服务上线怎么不影响旧版本(多版本支持)
dubbo的文档中说到:
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。 在低压力时间段,先升级一半提供者为新版本,再将所有消费者升级为新版本,然后将剩下的一半提供者升级为新版本 <dubbo:service interface="com.foo.BarService" version="1.0.0" /> <dubbo:service interface="com.foo.BarService" version="2.0.0" /> <dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" /> <dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" /> 不区分版本:(2.2.0以上版本支持) <dubbo:reference id="barService" interface="com.foo.BarService" version="*" />
dubbo协议下的单一长连接与多线程并发如何协同工作
底层采用netty。
集群容错怎么做
当我们的系统中用到Dubbo的集群环境,因为各种原因在集群调用失败时,Dubbo提供了多种容错方案,缺省为failover重试。
集群容错模式:
1、Failover Cluster
失败自动切换,当出现失败,重试其它服务器。(缺省)
通常用于读操作,但重试会带来更长延迟。
可通过retries="2"来设置重试次数(不含第一次)。正是文章刚开始说的那种情况.
2、Failfast Cluster
快速失败,只发起一次调用,失败立即报错。
通常用于非幂等性的写操作,比如新增记录。
3、Failsafe Cluster
失败安全,出现异常时,直接忽略。
通常用于写入审计日志等操作。
4、Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。
通常用于消息通知操作。
5、Forking Cluster
并行调用多个服务器,只要一个成功即返回。
通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
可通过forks="2"来设置最大并行数。
6、Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0开始支持)
通常用于通知所有提供者更新缓存或日志等本地资源信息。
重试次数配置如:(failover集群模式生效)<dubbo:service retries="2"/> 或: <dubbo:reference retries="2"/> 或: <dubbo:reference> <dubbo:methodname="findFoo"retries="2"/> </dubbo:reference>
集群模式配置如:
<dubbo:servicecluster="failsafe"/> 或:<dubbo:referencecluster="failsafe"/>
dubbo是如何实现负载均衡
dubbo负载均衡策略:
在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用。
1、Random LoadBalance
随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
2、RoundRobin LoadBalance
轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
3、LeastActive LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
4、ConsistentHash LoadBalance
一致性Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
Dubbo的集群容错和负载均衡同样也是Dubbo本身的高级特性。正如我们在说自定义扩展的时候一样,这两个特征同样也可以进行自定义扩展,用户可以根据自己实际的需求来扩展他们从而满足项目的实际需求.遇到的问题
场景描述:客户端远程异步调用ServiceA,ServiceA在处理客户端请求的过程中需要远程同步调用ServiceB,ServiceA从ServiceB的响应中取数据时,得到的是null。
对于上面的问题,解决办法有三个:
1.方法调用两次ServiceA调用ServiceB的地方写两次一样的调用,这个方法原理就像ServiceB调用ServiceC一样,即清除attachements。
这个方法最简单,但是可能对不了解的人来说,这块业务代码写重复了,会不小心删除掉,而且从写代码的角度来说,这个很鸡肋,所以不推荐。
2.修改Dubbo源码
修改AbstractInvoker第137行,改成每次都对async进行实际赋值,
boolean isAsync = getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false);
invocation.setAttachment(Constants.ASYNC_KEY, String.valueOf(isAsync));
3.自定义Filter
实现com.alibaba.dubbo.rpc.Filter,在RpcContext中清除这个async, @Activate(group = {Constants.PROVIDER}) public class AsyncFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { RpcContext.getContext().getAttachments().remove(Constants.ASYNC_KEY); return invoker.invoke(invocation); } } 同时在src/main/resources/META-INF/dubbo/下添加com.alibaba.dubbo.rpc.Filter文件,内容文件如下: asyncFilter=com.abc.filter.AsyncFilter
根据n多的博客整理出来的一些,以后有其他东西再加进去
-
DUBBO
2019-09-02 11:30:12最近研究了一下阿里开源的分布式RPC框架dubbo,楼主写了一个 demo,体验了一下dubbo的功能。 快速开始 实际上,dubbo的官方文档已经提供了如何使用这个RPC框架example代码,基于 Netty 的长连接。楼主看这个框架主要...最近研究了一下阿里开源的分布式RPC框架dubbo,楼主写了一个 demo,体验了一下dubbo的功能。
快速开始
实际上,dubbo的官方文档已经提供了如何使用这个RPC框架example代码,基于 Netty 的长连接。楼主看这个框架主要是为了在微服务,service mesh大火的今天做一些技术储备以及了解一下分布式 RPC 框架的设计。当然即便是写一个dubbo的demo也不能随便写写就好了,要认真对待说不定哪一天可以派上用场呢,下面是楼主写的代码的目录结构:
下面我来一一说明一下每个model的作用,micro-service-dubbo-common是通用工具模块其他的model都需要依赖它 。
micro-service-dubbo-dal是整个项目的dao模块,有关数据库操作的相关代码都放在这里。
micro-service-dubbo-interface 是通用接口模块,专门用来声明接口,被consumer与provider同时依赖,这么做是为了项目的可拆分与分布式部署。
micro-service-dubbo-model是公用的实体类模块,不限于数据库对应的model,也可以放DTO,VO等。
micro-service-dubbo-provider项目的服务提供者。
micro-service-dubbo-web 项目的消费者,也是直接跟前端交互的controller层。
另外需要在pom文件中添加相关依赖<!--dubbo--> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>${zkclient_version}</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>${zookeeper_version}</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>${curator_version}</version> </dependency>
接口创建
既然是 RPC 服务,那就需要一个接口,再有一个实现类。在这里的接口定义是在我们的micro-service-dubbo-interface,具体实现是在provider这里创建,在楼主的项目中就是在micro-service-dubbo-provider中创建DemoService 的实现。public interface DemoService { String sayHello(String name); public List getUsers(); }
@Service("demoService") public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext .getContext().getRemoteAddress()); return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } @Override public List getUsers() { List list = new ArrayList(); User u1 = new User(); u1.setName("hejingyuan"); u1.setAge(20); u1.setSex("f"); User u2 = new User(); u2.setName("xvshu"); u2.setAge(21); u2.setSex("m"); list.add(u1); list.add(u2); return list; } }
然后consumer的 pom.xml 添加对这个接口的依赖,在这里的接口定义是在我们的consumer就是micro-service-dubbo-web。
<dependency> <groupId>com.whforever</groupId> <artifactId>micro-service-dubbo-provider</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.whforever</groupId> <artifactId>micro-service-dubbo-interface</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
有了接口,就需要配置一下。
接口配置
首先在提供方这里发布接口。创建一个 xml 文件,名为:dubbo-provider.xml。文件内容:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- provider's application name, used for tracing dependency relationship --> <dubbo:application name="demo-provider"/> <!-- use multicast registry center to export service --> <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181" /> <!-- use dubbo protocol to export service on port 20880 --> <dubbo:protocol name="dubbo" port="20880"/> <!-- service implementation, as same as regular local bean --> <bean id="demoProviderService" class="com.whforever.service.impl.DemoServiceImpl"/> <!-- declare the service interface to be exported --> <dubbo:service interface="com.whforever.service.DemoService" ref="demoProviderService"/> </beans>
很简单,发布了一个接口,类似 Spring 的一个 bean。
同样的,在consumer即micro-service-dubbo-web的 resource 文件下,也创建一个dubbo-consumer.xml文件。内容稍有不同。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- consumer's application name, used for tracing dependency relationship (not a matching criterion), don't set it same as provider --> <dubbo:application name="demo-consumer"/> <!-- use multicast registry center to discover service --> <!--<dubbo:registry address="multicast://224.5.6.7:1234"/>--> <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181" /> <!-- generate proxy for the remote service, then demoService can be used in the same way as the local regular interface --> <dubbo:reference id="demoConsumerService" check="false" interface="com.whforever.service.DemoService"/> </beans>
从上面可以看出这两个文件的注册发现协议是zookeeper,因此在服务启动之前需要启动zookeeper,具体移步Zookeeper 注册中心安装启动
准备测试
测试之前还要做点点工作。在启动provider事需要一部分引导程序,请看如下代码:
public class ProviderMain { public static void main(String[] args) throws IOException { System.setProperty("java.net.preferIPv4Stack", "true"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dubbo-provider.xml"); context.start(); System.in.read(); // press any key to exit } }
consumer代码
@Controller @RequestMapping("/") public class IndexController { @Autowired DemoService demoService; @RequestMapping("/echo") @ResponseBody public String echo() { System.out.println(">>>>>>echo"); return JSON.toJSONString(demoService.getUsers()); } }
运行
先运行provider:[06/06/18 11:56:29:029 CST] main INFO config.AbstractConfig: [DUBBO] The service ready on spring started. service: com.whforever.service.DemoService, dubbo version: 2.6.1, current host: 192.168.1.120 [06/06/18 11:56:30:030 CST] main INFO config.AbstractConfig: [DUBBO] Export dubbo service com.whforever.service.DemoService to local registry, dubbo version: 2.6.1, current host: 192.168.1.120 [06/06/18 11:56:30:030 CST] main INFO config.AbstractConfig: [DUBBO] Export dubbo service com.whforever.service.DemoService to url dubbo://192.168.1.120:20880/com.whforever.service.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.1.120&bind.port=20880&dubbo=2.6.1&generic=false&interface=com.whforever.service.DemoService&methods=sayHello,getUsers&pid=13992&side=provider×tamp=1528300589682, dubbo version: 2.6.1, current host: 192.168.1.120 [06/06/18 11:56:30:030 CST] main INFO config.AbstractConfig: [DUBBO] Register dubbo service com.whforever.service.DemoService url dubbo://192.168.1.120:20880/com.whforever.service.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.1.120&bind.port=20880&dubbo=2.6.1&generic=false&interface=com.whforever.service.DemoService&methods=sayHello,getUsers&pid=13992&side=provider×tamp=1528300589682 to registry registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.6.1&pid=13992®istry=zookeeper×tamp=1528300589673, dubbo version: 2.6.1, current host: 192.168.1.120 [06/06/18 11:56:30:030 CST] main INFO transport.AbstractServer: [DUBBO] Start NettyServer bind /0.0.0.0:20880, export /192.168.1.120:20880, dubbo version: 2.6.1, current host: 192.168.1.120
再运行sonsumer:
通过查看dubbo监控中心,可以看到如下所示的情况,具体dubbo监控中心如何安装部署请移步Simple 监控中心安装
小结
对于dubbo听其大名已久,直到最近才动手写了一些demo,总体来看上手还是比较简单,官方也提供了比较详细的文档,社区也比较活跃。 -
Dubbo入门---搭建一个最简单的Demo框架
2017-04-17 19:10:44Dubbo背景和简介Dubbo开始于电商系统,因此在这里先从电商系统的演变讲起。 单一应用框架(ORM) 当网站流量很小时,只需一个应用,将所有功能如下单支付等都部署在一起,以减少部署节点和成本。 缺点:单一的系统...Dubbo背景和简介
Dubbo开始于电商系统,因此在这里先从电商系统的演变讲起。
单一应用框架(ORM)
当网站流量很小时,只需一个应用,将所有功能如下单支付等都部署在一起,以减少部署节点和成本。
缺点:单一的系统架构,使得在开发过程中,占用的资源越来越多,而且随着流量的增加越来越难以维护
垂直应用框架(MVC)
垂直应用架构解决了单一应用架构所面临的扩容问题,流量能够分散到各个子系统当中,且系统的体积可控,一定程度上降低了开发人员之间协同以及维护的成本,提升了开发效率。
缺点:但是在垂直架构中相同逻辑代码需要不断的复制,不能复用。
分布式应用架构(RPC)
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心
流动计算架构(SOA)
随着服务化的进一步发展,服务越来越多,服务之间的调用和依赖关系也越来越复杂,诞生了面向服务的架构体系(SOA),也因此衍生出了一系列相应的技术,如对服务提供、服务调用、连接处理、通信协议、序列化方式、服务发现、服务路由、日志输出等行为进行封装的服务框架
从以上是电商系统的演变可以看出架构演变的过程:
单一应用架构
- 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。
- 此时,用于简化增删改查工作量的 数据访问框架(ORM) 是关键。
垂直应用架构
- 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。
- 此时,用于加速前端页面开发的 Web框架(MVC) 是关键。
- 分布式服务架构
- 当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。
- 此时,用于提高业务复用及整合的 分布式服务框架(RPC) 是关键。
- 流动计算架构
- 当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。
- 此时,用于提高机器利用率的 资源调度和治理中心(SOA) 是关键。
在这里插播一条关于RPC的简介:
RPC(Remote Procedure Call Protocol):远程过程调用:
两台服务器A、B,分别部署不同的应用a,b。当A服务器想要调用B服务器上应用b提供的函数或方法的时候,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义传达调用的数据。
说白了,就是你在你的机器上写了一个程序,我这边是无法直接调用的,这个时候就出现了一个远程服务调用的概念。RPC是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。RPC需要解决的问题:
(可以稍作了解,详情可查看别的博文)- 通讯问题 : 主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
- 寻址问题 : A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
- 序列化 与 反序列化 : 当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。
同理,B服务器接收参数要将参数反序列化。B服务器应用调用自己的方法处理后返回的结果也要序列化给A服务器,A服务器接收也要经过反序列化的过程。
Dubbo是什么
Dubbo是:
- 一款分布式服务框架
- 高性能和透明化的RPC远程服务调用方案
- SOA服务治理方案
每天为2千多个服务提供大于30亿次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点以及别的公司的业务中。
Dubbo架构
Provider: 暴露服务的服务提供方。
Consumer: 调用远程服务的服务消费方。
Registry: 服务注册与发现的注册中心。
Monitor: 统计服务的调用次数和调用时间的监控中心。调用流程
0.服务容器负责启动,加载,运行服务提供者。
1.服务提供者在启动时,向注册中心注册自己提供的服务。
2.服务消费者在启动时,向注册中心订阅自己所需的服务。
3.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
4.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
5.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
Dubbo注册中心
对于服务提供方,它需要发布服务,而且由于应用系统的复杂性,服务的数量、类型也不断膨胀;
对于服务消费方,它最关心如何获取到它所需要的服务,而面对复杂的应用系统,需要管理大量的服务调用。
而且,对于服务提供方和服务消费方来说,他们还有可能兼具这两种角色,即既需要提供服务,有需要消费服务。通过将服务统一管理起来,可以有效地优化内部应用对服务发布/使用的流程和管理。服务注册中心可以通过特定协议来完成服务对外的统一。
Dubbo提供的注册中心有如下几种类型可供选择:
- Multicast注册中心
- Zookeeper注册中心
- Redis注册中心
- Simple注册中心
Dubbo优缺点
优点:
- 透明化的远程方法调用
- 像调用本地方法一样调用远程方法;只需简单配置,没有任何API侵入。 - 软负载均衡及容错机制
- 可在内网替代nginx lvs等硬件负载均衡器。
- 服务注册中心自动注册 & 配置管理
-不需要写死服务提供者地址,注册中心基于接口名自动查询提供者ip。
使用类似zookeeper等分布式协调服务作为服务注册中心,可以将绝大部分项目配置移入zookeeper集群。 - 服务接口监控与治理
-Dubbo-admin与Dubbo-monitor提供了完善的服务接口管理与监控功能,针对不同应用的不同接口,可以进行 多版本,多协议,多注册中心管理。
缺点:
- 只支持JAVA语言
Dubbo入门Demo
了解了Dubbo以后,自然要搭建一个简单的Demo实现。本文采用Dubbo与Zookeeper、Spring框架的整合。
主要是以下几个步骤:
1. 安装Zookeeper,启动;
2. 创建MAVEN项目,构建Dubbo+Zookeeper+Spring实现的简单Demo;
3. 安装Dubbo-admin,实现监控。1 Zookeeper介绍与安装
本Demo中的Dubbo注册中心采用的是Zookeeper。为什么采用Zookeeper呢?
Zookeeper是一个分布式的服务框架,是树型的目录服务的数据存储,能做到集群管理数据 ,这里能很好的作为Dubbo服务的注册中心。
Dubbo能与Zookeeper做到集群部署,当提供者出现断电等异常停机时,Zookeeper注册中心能自动删除提供者信息,当提供者重启时,能自动恢复注册数据,以及订阅请求
具体的安装方法在此不一一叙述,可参考博文:
http://blog.csdn.net/tlk20071/article/details/52028945安装完成后,进入到bin目录,并且启动zkServer.cmd,这个脚本中会启动一个java进程:
(注:需要先启动zookeeper后,后续dubbo demo代码运行才能使用zookeeper注册中心的功能)
2 创建MAVEN项目
项目结构:
主要分三大模块:
dubbo-api : 存放公共接口;
dubbo-consumer : 调用远程服务;
dubbo-provider : 提供远程服务。
下面将详细叙述代码构建过程。
1) 首先构建MAVEN项目,导入所需要的jar包依赖。
需要导入的有spring, dubbo, zookeeper等jar包。
(详情参看后面提供的项目代码)2)创建dubbo-api的MAVEN项目(有独立的pom.xml,用来打包供提供者消费者使用)。
在项目中定义服务接口:该接口需单独打包,在服务提供方和消费方共享。
package com.alibaba.dubbo.demo; import java.util.List; public interface DemoService { List<String> getPermissions(Long id); }
3)创建dubbo-provider的MAVEN项目(有独立的pom.xml,用来打包供消费者使用)。
实现公共接口,此实现对消费者隐藏:package com.alibaba.dubbo.demo.impl; import com.alibaba.dubbo.demo.DemoService; import java.util.ArrayList; import java.util.List; public class DemoServiceImpl implements DemoService { public List<String> getPermissions(Long id) { List<String> demo = new ArrayList<String>(); demo.add(String.format("Permission_%d", id - 1)); demo.add(String.format("Permission_%d", id)); demo.add(String.format("Permission_%d", id + 1)); return demo; } }
需加入公共接口所在的依赖
用Spring配置声明暴露服务
<?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-admin 或 dubbo-monitor 会显示这个名字,方便辨识--> <dubbo:application name="demotest-provider" owner="programmer" organization="dubbox"/> <!--使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper--> <dubbo:registry address="zookeeper://localhost:2181"/> <!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20880" /> <!--使用 dubbo 协议实现定义好的 api.PermissionService 接口--> <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" protocol="dubbo" /> <!--具体实现该接口的 bean--> <bean id="demoService" class="com.alibaba.dubbo.demo.impl.DemoServiceImpl"/> </beans>
启动远程服务:
package com.alibaba.dubbo.demo.impl; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; public class Provider { public static void main(String[] args) throws IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml"); System.out.println(context.getDisplayName() + ": here"); context.start(); System.out.println("服务已经启动..."); System.in.read(); } }
4)创建dubbo-consumer的MAVEN项目(可以有多个consumer,但是需要配置好)。
调用所需要的远程服务:通过Spring配置引用远程服务:
<?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:application name="demotest-consumer" owner="programmer" organization="dubbox"/> <!--向 zookeeper 订阅 provider 的地址,由 zookeeper 定时推送--> <dubbo:registry address="zookeeper://localhost:2181"/> <!--使用 dubbo 协议调用定义好的 api.PermissionService 接口--> <dubbo:reference id="permissionService" interface="com.alibaba.dubbo.demo.DemoService"/> </beans>
启动Consumer,调用远程服务:
package com.alibaba.dubbo.consumer; import com.alibaba.dubbo.demo.DemoService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Consumer { public static void main(String[] args) { //测试常规服务 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml"); context.start(); System.out.println("consumer start"); DemoService demoService = context.getBean(DemoService.class); System.out.println("consumer"); System.out.println(demoService.getPermissions(1L)); } }
5)运行项目,先确保provider已被运行后再启动consumer模块:
运行提供者:
消费者成功调用提供者所提供的远程服务:
当然,这只是一个模拟的项目,实际中有多提供者多消费者情况,比这要复杂的多,当然只有这样才能体现dubbo的特性。
Dubbo管理控制台介绍
管理控制台功能
路由规则,动态配置,服务降级
访问控制,权重调整
负载均衡
下载dubbo-admin,可自行根据网上介绍安装。大致做法就是将dubbo-admin中 的某个文件夹内容替换到tomcat的conf中,再运行tomcat即可。但我在实际操作中发现JDK8无法运行,后来找到一个JDK8可以实现的dubbo-admin版本,下载地址:http://www.itmayun.com/it/files/226631678709806/resource/901920001882583/1.html。
成功开启输入用户名密码root后,即可进入控制台首页查看消费者提供者情况:
查看提供者:
查看消费者:
目前,阿里又开始更新,有兴趣可以查看:
https://github.com/apache/incubator-dubbo整个项目的代码已经上传到我的github上https://github.com/nomico271/DatatablesDemo.git,欢迎查看。
(github上项目中的图片为博客中内容,可全部删除)。 -
Dubbo介绍
2019-03-19 10:47:13什么是Dubbo dubbo是一个RPC远程调用框架,分布式服务治理框架。 dubbo服务治理:服务与服务之间会有很多个url,依赖关系,负载均衡,容错,自动注册服务。 Dubbo有哪些协议 默认用的dubbo协议,http,RMI,... -
Dubbo 一些你不一定知道但是很好用的功能
2019-01-07 10:13:35dubbo功能非常完善,很多时候我们不需要重复造轮子,下面列举一些你不一定知道,但是很好用的功能; 直连Provider 在开发及测试环境下,可能需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,... -
Dubbo面试题
2020-10-25 15:55:491、dubbo和dubbox之间的区别? Dubbox 和Dubbo本质上没有区别,名字的含义扩展了Dubbo而已,以下扩展出来的功能 支持REST风格远程调用(HTTP + JSON/XML); 支持基于Kryo和FST的Java高效序列化实现; 支持基于... -
开源框架面试之Dubbo面试题
2020-09-28 00:15:422、dubbo服务负载均衡策略?3、Dubbo在安全机制方面是如何解决的4、dubbo连接注册中心和直连的区别 1、Dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,发布 者和订阅者之间还能通信么? 可以通信的,启动... -
java rmi与dubbo
2019-07-31 19:17:07首先得知道什么是分布式,以及和集群的区别? 分布式:一个业务分拆成多个子业务,部署在不同的服务器上,多半是为了业务解耦,不同的业务可以分别部署,互不干扰,只在需要时相互调用,提升效率。... -
dubbo示例+dubbo官方配置文档+dubbo培训ppt
2015-02-25 16:06:31dubbo示例,dubbo官方配置文档,dubbo培训ppt -
【Dubbo】深入理解Apache Dubbo(二):开发第一个Dubbo应用程序
2020-01-31 19:09:07本篇侧重用代码说明Dubbo应用程序的开发及使用,通过一个简单的示例演示Dubbo应用。读者要是对Dubbo框架的基本概念还有模糊,可以先阅读 【Dubbo】深入理解Apache Dubbo(一):带你走近高性能RPC通信框架 另外本篇... -
Dubbo项目实战
2016-06-08 11:01:16本套Dubbo课程结合讲师多年的Dubbo应用实战经验,详细讲解Dubbo分布式服务框架的应用入门基础。 -
Dubbo使用invoke指令来调用dubbo接口
2020-08-26 00:00:57Dubbo使用invoke指令来测试dubbo接口 前言 最近被分配了一个任务,是通过dubbo的方式对外提供服务,dubbo没有我们一般的web项目中的Controller层,所以没有办法通过http的方式进行调用调试。作为萌新的我,确实有点... -
漫谈dubbo分布式服务架构
2017-08-25 23:39:35本课程主要是围绕一个小电商系统为案例,帮小伙伴讲解如何基于dubbo搭建分布式服务集群框架。掌握dubbo底层核心原理。 技术交流QQ群:257206349 (加群后可获取课程资料) -
dubbo调用 Caused by: com.alibaba.dubbo.remoting.RemotingException 异常解决方法
2018-10-30 16:08:55Caused by: com.alibaba.dubbo.remoting.RemotingException: message can not send, because channel is closed . url:dubbo://192.168.199.170:20883/... -
Dubbo学习(三)- Dubbo的管理控制台dubbo-admin
2018-04-09 14:31:57下载dubbo-admin 前往github上下载dubbo-admin:https://github.com/apache/incubator-dubbo/tree/dubbo-2.6.0 注意:dubbo-2.6.1以后的版本不再有dubbo-admin incubator-dubbo-dubbo-2.6.0.zip,右键》解压... -
Dubbo开发文档
2013-08-14 23:17:38包括: 1.《服务框架实践与探索》Service Framework ...4.《Dubbo功能介绍》Dubbo RPC Features.pdf 5.《Dubbo框架扩展》Dubbo Framework Extensions.pdf 6.《Dubbo实现的原理分析》Dubbo实现的原理分析.doc 7. -
dubbo学习之源码创建属于自己的dubbo-demo
2020-08-20 22:27:10谈论了如何本地构建dubbo源码,最近溪源也在努力的学习dubbo相关知识和机制,学习过程也可以称之苦不堪言吧。dubbo官网是入门学习资源重要之一;故溪源先分享中文官网:dubbo中文手册。 上网文章中也清晰地带着大家... -
DUBBO-POSTMAN(dubbo接口测试,dubbo场景测试,dubbo集成测试)
2019-08-01 14:19:54DUBBO-POSTMAN DUBBO-POSTMAN: 一个用于通过web-ui页面访问dubbo接口的工具,灵感源于 postman 介绍 DUBBO-POSTMAN 是一个通过web页面访问dubbo接口的开源工具,包括零代码创建一个dubbo consumer,保存访问用例,构建... -
dubbo的底层原理
2017-12-03 14:01:37Dubbo是一种分布式服务框架。 Webservice也是一种服务框架,但是webservice并不是分布式的服务框架,他需要结合F5实现负载均衡。因此,dubbo除了可以提供服务之外,还可以实现软负载均衡。它还提供了两个功能Monitor... -
Dubbo是什么?能做什么?
2017-07-30 23:01:191. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的... -
Dubbo-Dubbo 动态配置中心
2019-07-14 15:50:43Dubbo 动态配置中心 一、参考文档 http://dubbo.apache.org/zh-cn/docs/user/configuration/config-center.html 三大中心指的:注册中心,元数据中心,配置中心。在 2.7 之前的版本,Dubbo 只配备了注册中心,主流... -
dubbo 知识总结 dubbo配置参考
2016-11-03 21:11:32dubbo官方文档项目的规模越来越大,总得解耦,不能在一个项目里,这时候,公司采用了dubbo作为分布式应用,将多项业务拆分,并做了库存服务统一、价格服务统一等等一些特殊需要统一性的服务。作为dubbo我也接触了快... -
Dubbo之——Dubbo Filter实战
2017-07-06 00:37:35熟悉Dubbo的同学或朋友,都会知道,一般dubbo的service层都是一些通用的,无状态的服务。但是在某些特殊的需求下,我们又需要传递一些上下文环境,打个不恰当的比方,例如需要在每次调用dubbo的服务的时候,记录一下... -
精通Dubbo——Dubbo支持的协议的详解
2017-06-02 22:26:57Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议,但是Dubbo官网是推荐我们使用Dubbo协议的。下面我们就针对Dubbo的每种协议详解讲解,以便我们在实际应用中能够正确取舍。dubbo协议缺省... -
【夯实Dubbo】Dubbo的核心特性
2019-06-04 09:58:07本文属于【夯实Dubbo】系列文章,该系列旨在用通俗易懂的语言,带大家了解和学习 Dubbo 技术,希望能给读者带来一些干货。系列目录如下(可能随着写作的进行,会做一些调整): 【夯实Dubbo】什么是 RPC 框架? ... -
SpringCloud与Dubbo的比较
2019-04-13 16:45:30Dubbo 一、dubbo简介 Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC实现服务的输出和输入功能,可以和Spring框架无缝集成。 Dubbo是一款高性能、轻量级的开源Java RPC框架,它... -
精通Dubbo——Dubbo配置文件详解
2017-06-01 22:44:35依赖的jar理论上Dubbo可以只依赖JDK,不依赖于任何三方库运行,只需配置使用JDK相关实现策略。缺省依赖(系统默认)通过mvn dependency:tree > dep.log命令(Eclipse或Linux命令行)分析,Dubbo缺省依赖以下三方库:... -
dubbo配置scheme文件
2014-10-14 15:43:24dubbo配置scheme文件 -
dubbo调优
2017-08-02 02:21:36dubbo调优 dubbo
-
转行做IT-第1章 计算机基础
-
数据结构例9.设计一个算法,以先进先出的方式 创建一个带头结点的双向链表,并输出 。
-
国家注册信息安全工程师体系课程(CISP-PTE)
-
Java高级特性 - JDBC(上)
-
吹响集结号的银商.doc
-
《前端工具系列》最好用的git可视化工具——SourceTree
-
第三方SDK集成库,授权/分享/支付
-
C#文件传输、Socket通信、大文件断点续传
-
OPPO A83t维修指导
-
STM32-NRF24L01一对一.rar
-
【paper笔记】ESAM: Discriminative Domain Adaptation with Non-Displayed Items to Improve Long-Tail
-
EXCEL2010调用ONENOTE实现OCR图文识别
-
(新)备战2021软考系统集成基础知识套餐
-
攻防世界——Normal_RSA
-
IDEA中的配置与插件
-
node.js常见问题之:解决npm install出错(Cannot find module ‘internal/util/types‘)
-
(新)备战2021软考网络规划设计师培训学习套餐
-
RedHat8.1-RHEL8.1修改yum/dnf源,目标alliyun的yum
-
前端性能优化
-
(新)备战2021软考信息安全工程师基础知识套餐