深入理解Dubbo-2.Dubbo功能之高级特性分析

news2024/11/19 5:33:42
  • 👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家
  • 📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理
  • 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
  • 🍂博主正在努力完成2023计划中:源码溯源,一探究竟
  • 📝联系方式:nhs19990716,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬👀

文章目录

  • Dubbo
    • 多配置中心
    • 多协议支持
    • Dubbo的负载均衡
      • Random(默认)
      • roundrobin (轮询)
      • 一致性hash 负载均衡
      • 最小活跃度
      • shortestreponse loadbalance
    • Dubbo常见的配置讲解
      • 启动时检查
      • 主机绑定的问题
      • 配置优先级问题
    • 集群容错
      • Failover(默认)
      • failfast cluster
      • failsafe cluster
      • failback cluster
      • forking cluster
      • broadcast cluster
    • Dubbo 泛化
    • 服务降级

Dubbo

多配置中心

spring-boot-dubbo-sample-consumer

dubbo.registries.hunan.address=nacos://192.168.216.128:8848

dubbo.registries.shanghai.address=zookeeper://192.168.216.128:2181
dubbo.registries.shanghai.timeout=10000

spring-boot-dubbo-sample-provider

dubbo.registries.hunan.address=nacos://192.168.216.128:8848

dubbo.registries.shanghai.address=zookeeper://192.168.216.128:2181
dubbo.registries.shanghai.timeout=10000
@DubboService(registry = {"shanghai","hunan"})
public class SayHelloServiceImpl implements ISayHelloService {

    @Override
    public String sayHello(String msg) {
        return "Hello,"+msg+" GuPaoEdu.cn";
    }
}

此时我们的服务会注册在两个地方,这也就意味着,不仅可以在zk上看到我们的服务,还可以在nacos上看到我们的服务。

如果我们的消费者也配置了两个注册中心,那么应该调用哪个注册中心呢?

@RestController
public class SayController {

    @DubboReference(registry = {"shanghai","hunan"},)
    ISayHelloService sayHelloService;

    @GetMapping("/say")
    public String say(){
        return sayHelloService.sayHello("Mic");
    }

}

在这里插入图片描述

实际上也是针对多个注册中心做负载均衡。

可以通过设置权重的方式,或者设置默认优先选择

dubbo.registries.shanghai.address=zookeeper://192.168.216.128:2181
dubbo.registries.shanghai.timeout=10000

dubbo.registries.shanghai.zone=shanghai
dubbo.registries.shanghai.weight=100

dubbo.registries.hunan.address=nacos://192.168.216.128:8848
dubbo.registries.hunan.weight=10
dubbo.registries.hunan.preferred=true

还有就是版本路由,由生产者@DubboService()中设置了版本,然后消费者@DubboRederence中选择对应版本即可。

多协议支持

Dubbo的多协议支持是指它可以同时支持多种不同的通信协议,例如dubbo协议、HTTP协议、WebService协议等。这意味着Dubbo可以在不同的场景下灵活地选择最合适的通信协议,以满足不同服务之间的通信需求。

Dubbo的多协议支持使得它可以适用于各种不同的应用场景,无论是内部服务调用还是与外部系统交互,都能够选择最合适的通信协议来进行通信。这种灵活性和可扩展性使得Dubbo成为一个非常强大的分布式服务框架。

添加jar包依赖

<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-jaxrs</artifactId>
	<version>3.13.0.Final</version>
</dependency>
<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-client</artifactId>
	<version>3.13.0.Final</version>
</dependency>
<dependency>
	<groupId>org.eclipse.jetty</groupId>
	<artifactId>jetty-server</artifactId>
	<version>9.4.19.v20190610</version>
</dependency>
<dependency>
	<groupId>org.eclipse.jetty</groupId>
	<artifactId>jetty-servlet</artifactId>
	<version>9.4.19.v20190610</version>
</dependency>

修改配置文件

dubbo.protocol.name=dubbo
dubbo.protocol.port=-1

# Netty ->
dubbo.protocols.dubbo.name=dubbo
dubbo.protocols.dubbo.port=-1 
# 设置为-1 会基于20880 这个端口往上加

# jetty (配置了Rest协议)
dubbo.protocols.rest.name=rest
dubbo.protocols.rest.port=-1
dubbo.protocols.rest.server=jetty
@DubboService(protocol = {"dubbo","rest"})

如果想按照rest风格发布

@Path("/")
public interface ISayHelloService {

    @GET
    @Path("/say")
    String sayHello(String msg);
}

当Dubbo配置了多协议支持时,会根据请求的协议来选择相应的协议进行处理。如果请求使用的是dubbo协议,那么Dubbo会选择dubbo协议进行处理;如果请求使用的是rest协议,那么Dubbo会选择rest协议进行处理。这样可以根据不同的需求选择合适的协议进行通信。

假设我们有一个Dubbo服务提供者,配置了同时支持dubbo和rest协议,如下所示:

@DubboService(protocol = {"dubbo","rest"})
public class HelloServiceImpl implements HelloService {
    public String sayHello(String name) {
        return "Hello, " + name;
    }
}

在这个例子中,HelloServiceImpl类使用@DubboService注解标记为Dubbo服务,并配置了同时支持dubbo和rest协议。

现在假设有一个消费者通过dubbo协议调用HelloServiceImpl的sayHello方法:

HelloService helloService = // 获取HelloService代理对象
String result = helloService.sayHello("Alice");

在这种情况下,Dubbo会选择dubbo协议进行处理,因为消费者使用的是dubbo协议进行调用。

而如果有另一个消费者通过rest协议调用HelloServiceImpl的sayHello方法:

RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject("http://localhost:8080/sayHello?name=Alice", String.class);

在这种情况下,Dubbo会选择rest协议进行处理,因为消费者使用的是rest协议进行调用。

因此,根据不同的请求协议,Dubbo会选择相应的协议进行处理。

Dubbo的负载均衡

在这里插入图片描述

在Dubbo的整个架构图里面,服务注册是里面很核心的一个环节,服务提供者可以有多个注册进来,那么服务消费者处就会拿到多个地址,那么这个情况喜爱,consumer通过invoke去调用的时候,应该调用哪个地址呢?这是这里面必然要考虑的问题。

测试

spring-boot-dubbo-sample-provider

@DubboService(registry = {"shanghai","hunan"},
        protocol = {"dubbo","rest"},
        loadbalance = "random")
public class SayHelloServiceImpl implements ISayHelloService {

    @Value("${dubbo.protocols.dubbo.port}")
    private Integer port;

    @Override
    public String sayHello(String msg) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Msg:"+System.currentTimeMillis());
        return "[version1.0]-"+port+"Hello,"+msg+" GuPaoEdu.cn";
    }
}
spring.application.name=spring-boot-dubbo-sample-provider



dubbo.protocol.name=dubbo
dubbo.protocol.port=-1

# Netty ->
dubbo.protocols.dubbo.name=dubbo
dubbo.protocols.dubbo.port=-1 
# 设置为-1 会基于20880 这个端口往上加

# jetty 
dubbo.protocols.rest.name=rest
dubbo.protocols.rest.port=-1
dubbo.protocols.rest.server=jetty

同时启动两个生产者服务,因为 dubbo.protocols.dubbo.port=-1 设置为了 -1,所以会基于20880 这个端口往上加。

然后进行测试,就能检测到时间戳数据打印在不同的生产者实例上。

Random(默认)

它的算法思想很简单。假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3,2],权重总和为10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上。比如数字3会落到服务器 A 对应的区间上,此时返回服务器 A即可。权重越大的机器,在坐标轴上对应的区间范围就越大,因此随机数生成器生成的数字就会有更大的概率落到此区间内。只要随机数生成器产生的随机数分布性很好,在经过多次选择后,每个服务器被选中的次数比例接近其权重比例。

这种思想可以应用到抽奖算法中。

roundrobin (轮询)

所谓轮询是指将请求轮流分配给每台服务器。举个例子,我们有三台服务器 A、B、C。我们将第一个请求分配给服务器 A,第二个请求分配给服务器 B,第三个请求分配给服务器 C,第四个请求再次分配给服务器 A。这个过程就叫做轮询。轮询是一种无状态负载均衡算法,实现简单,适用于每台服务器性能相近的场景下。但现实情况下,我们并不能保证每台服务器性能均相近。如果我们将等量的请求分配给性能较差的服务器,这显然是不合理的。因此,这个时候我们需要对轮询过程进行加权,以调控每台服务器的负载。经过加权后,每台服务器能够得到的请求数比例,接近或等于他们的权重比。比如服务器A、B、C 权重比为 5:2:1。那么在8次请求中,服务器 A 将收到其中的5次请求,服务器 B 会收到其中的2次请求,服务器 C 则收到其中的1次请求

一致性hash 负载均衡

一致性哈希负载均衡是一种在分布式系统中实现负载均衡的算法,它通过将请求映射到一致性哈希环上的节点来实现负载均衡。在Dubbo中,一致性哈希负载均衡的实现可以通过以下步骤来实现:

  1. 建立一致性哈希环:首先,需要将所有的服务提供者节点映射到一致性哈希环上,可以使用一致性哈希算法将节点的IP地址或者其他标识映射到一个固定的哈希环上。
  2. 根据请求的哈希值选择节点:当有请求到来时,需要计算请求的哈希值,并根据哈希值在一致性哈希环上选择对应的节点作为服务提供者。
  3. 负载均衡:一致性哈希负载均衡算法会选择离请求哈希值最近的节点作为服务提供者,这样可以保证相同的请求会被映射到同一个节点上,从而实现负载均衡。

在Dubbo中,一致性哈希负载均衡算法可以通过自定义路由规则或者使用Dubbo内置的一致性哈希负载均衡策略来实现。通过配置相应的路由规则或者使用内置的一致性哈希负载均衡策略,可以实现一致性哈希负载均衡算法来均衡分布式系统中的请求负载。

这样设计的好处是,{hash(parameter) % 3} =0,1,2 变化到 {hash(parameter) % 6} =0,1,2,3,4,5 可能会产生数据震荡,所以采用环来设计,都去取余 2^32 - 1

在这里插入图片描述

这样做以后无论增加 还是 删减节点,其本身都能去找最近的点。

但是也会存在一种情况,就是数据分布的问题,因为数据不一定分布的很均匀,比如只有两个节点,只占用了整个哈希环的四分之一。

在这里插入图片描述

此时就可以增加虚拟节点,将B节点再分发一些节点出来即可,去保证数据分布的均匀性。

在这里插入图片描述

而Dubbo中 一致性hash负载均衡是基于 参数进行hash取模,默认根据第一个参数。

最小活跃度

根据目标集群服务器列表,处理性能最高的,权重也越高。处理性能较低的,权重也比较低,主要是根据服务器的性能,动态去提升负载均衡的均衡性。

在Dubbo的负载均衡中,最小活跃度是通过统计每个服务提供者的活跃调用数来实现的。活跃调用数指的是当前服务提供者正在处理的调用数,通过统计活跃调用数可以了解每个服务提供者的负载情况。最小活跃度负载均衡策略会选择活跃调用数最小的服务提供者来处理请求,以实现负载均衡。这样可以确保请求被分配到负载较低的服务提供者上,从而提高系统的性能和稳定性。

具体的实现是:根据请求处理的吞吐量 -> 发起一次请求(开始),计数器+1、 一次请求处理完成,计数器-1

shortestreponse loadbalance

在Dubbo中,ShortestResponse负载均衡策略是通过选择平均响应时间最短的服务提供者来处理请求的。该负载均衡策略会根据服务提供者的平均响应时间来进行选择,以确保请求被分配给响应速度最快的服务提供者,从而提高系统的性能和用户体验。

实现ShortestResponse负载均衡策略的关键在于收集并统计每个服务提供者的响应时间,然后根据这些数据来选择最佳的服务提供者。Dubbo框架会在运行时收集服务提供者的响应时间,并根据这些数据进行动态调整和选择,以实现ShortestResponse负载均衡策略。这样可以确保请求被分配到响应速度最快的服务提供者上,从而提高系统的性能和稳定性。

Dubbo常见的配置讲解

启动时检查

服务提供者

dubbo.registries.shanghai.address=zookeeper://192.168.216.128:2181
dubbo.registries.shanghai.timeout=10000
dubbo.registries.shanghai.default=true
# 服务启动的时候,如果注册中心有问题,那么服务就启动失败
dubbo.registries.shanghai.check=true
# 如果为false,即使注册中心不可用,还是能启动成功,但是服务不可用而已

服务消费者

@DubboReference(registry = {"shanghai","hunan"},
            protocol = "dubbo",
            loadbalance = "consistenthash",
           check = false)

比如说项目中存在服务依赖的情况,如果开启了检查,那么注定会启动失败,可以先关闭检查,然后就可以启动成功,等到都注册到注册中心了,就可以去使用了。核心就是可以解决循环依赖的问题。

主机绑定的问题

查找 环境变量中是否存在启动参数 [DUBBO_IP_TO_BIND] = 服务注册的ip

读取配置文件 dubbo.protocols.dubbo.host= 服务注册的ip

如果这两个都没有

或通过 InetAddress.getLocalHost().getHostAddress() 获得本机ip地址

但是如果通过验证发现该ip地址不对,通过Socket去连接注册中心,从而获取本机IP

如果还不对,会轮询本机的网卡,直到找到合适的IP地址

上面获取到的ip地址是bindip,如果需要作为服务注册中心的ip, DUBBO_IP_TO_REGISTRY -dDUBBO_IP_TO_REGISTRY=ip

配置优先级问题

服务端和客户端的配置都可以生效,但是存在一个优先级的问题。

dubbo是基于url驱动的。

在这里插入图片描述

服务端配置的信息,都会装载到ulr上

dubbo%3A%2F%2F192.168.1.104%3A20880%2Fcom.gupaoedu.springboot.dubbo.ISayHelloSer
vice%3Fanyhost%3Dtrue%26application%3Dspring-boot-dubbo-sampleprovider%26cluster%3Dfailover%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dt
rue%26generic%3Dfalse%26interface%3Dcom.gupaoedu.springboot.dubbo.ISayHelloServi
ce%26metadatatype%3Dremote%26methods%3DsayHello%26pid%3D16488%26release%3D2.7.7%26side%3Dprov
ider%26timestamp%3D1596895175686

那么这些信息是不是客户端会拿到,消费者调用的时候,是从zk上拿到这个地址,然后再去解析这个配置。

此时要分为两种情况:

客户端没有配置:以服务端配置为主

客户端有配置:

  • 方法层面的配置要优先于接口层面的配置, 接口层面的配置要优先于全局配置
  • 如果级别一样,以客户端的配置优先,服务端次之
@RestController
public class SayController {

    @DubboReference(registry = {"shanghai","hunan"},
            protocol = "dubbo",
            loadbalance = "consistenthash",
            mock = "com.gupaoedu.springboot.dubbo.springbootdubbosampleconsumer.MockSayHelloService",
            timeout = 500,
            cluster = "failfast",check = false,methods = {
            @Method(loadbalance = "",name ="" )
    },retries = 5)
    ISayHelloService sayHelloService;

    @GetMapping("/say")
    public String say(){
        return sayHelloService.sayHello("Mic");
    }

}

在这里插入图片描述

集群容错

Dubbo的集群容错是指在分布式系统中,当某个服务节点出现故障或不可用时,Dubbo能够通过一定的机制保证系统的稳定性和可用性。

Failover(默认)

失败自动重试(重试其他服务器), 失败自动切换

@DubboService(cluster="failover",retires=2)

failfast cluster

快速失败,立马报错。

failsafe cluster

安全失败,出现了异常,直接吞掉(比如日志,出现了些许日常,也不怎么影响)

failback cluster

失败自动恢复,记录失败请求,定时重发(可以在保证最终一致性的时候借鉴,先记录到失败记录,到时候定时重新执行就可)

forking cluster

并行调用多个服务节点,只要其中一个成功返回,那么就直接返回结果

broadcast cluster

广播调用。一个请求调用所有的服务提供者。只要其中一个节点报错,那么就认为这个请求失败

Dubbo 泛化

在前面的演示案例中,我们每次去发布一个服务,必然会先定义一个接口,并且把这个接口放在一个api的jar包中,给到服务调用方来使用。本质上,对于开发者来说仍然是面向接口编程,而且对于使用者来说,可以不需要关心甚至不需要知道这个接口到底是怎么触发调用的。
而泛化调用就是说服务消费者和服务提供者之间并没有这样的公共服务接口。

public interface IDemoService {

    String getTxt();
}


@DubboService(protocol = {"dubbo"})
public class DemoService implements IDemoService{

    @Override
    public String getTxt() {
        return "Hello Gupaoedu.cn/8.8";
    }
}

@RestController
public class DemoController {

    @DubboReference(interfaceName = "com.gupaoedu.springboot.dubbo.springbootdubbosampleprovider.services.IDemoService",generic = true,check = false)
    GenericService genericService; // 在这里Dubbo提供了一个泛化接口

    @GetMapping("/demo")
    public String demo(){
        Map<String,Object> user=new HashMap<>();
        user.put("",""); //key表达user对象中的属性,value表达属性的值
        return genericService.$invoke("getTxt",new String[0],null).toString();
    }
}

服务降级

public class MockSayHelloService implements ISayHelloService{

    @Override
    public String sayHello(String msg) {
        return "触发服务降级";
    }
}

@RestController
public class SayController {

    @DubboReference(registry = {"shanghai","hunan"},
            protocol = "dubbo",
            loadbalance = "consistenthash",
            mock = "com.gupaoedu.springboot.dubbo.springbootdubbosampleconsumer.MockSayHelloService",
            timeout = 500,
            cluster = "failfast",check = false,methods = {
            @Method(loadbalance = "",name ="" )
    },retries = 5)
    ISayHelloService sayHelloService;

    @GetMapping("/say")
    public String say(){
        return sayHelloService.sayHello("Mic");
    }

}500ms没有返回,则快速失败,失败后调用mock

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1294651.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用虚拟信用卡绑定直接支付 (Google play账号绑定教程)

虚拟信用卡的用途十分广泛&#xff0c;可用于购买应用&#xff0c;游戏内购、谷歌商店以及自己账号的充值&#xff0c;对于喜欢外服游戏的小伙伴来说&#xff0c;学会使用谷歌商店绑定虚拟信用卡是十分重要的。谷歌账号如何绑定信用卡呢&#xff1f;谷歌商店如何充值&#xff1…

各大厂商证书申请遇到的问题

证书作用&#xff1a; 确保数据传输过程中不被篡改、拦截 遭受中间件攻击、确保数据完整性、保密性 申请方式&#xff1a; 文件验证、cname验证&#xff08;需要在域名平台上添加cname记录&#xff09; 本次采用文本验证 添加需要申请的域名 将tx生成的txt文件放在 IIS站点…

空中“千里眼” 复亚环保监测无人机助力生态保护

生态环境保护是全球共同关注的重要议题&#xff0c;为了持续改善环境、加强执法效能&#xff0c;复亚智能环保监测无人机在环保领域大显身手。该智能系统为环境执法人员提供了全新的工具&#xff0c;使其能够在无人机的“千里眼”下&#xff0c;及时发现和制止环境违法行为&…

表单小程序作用体现在哪

表单的用途非常广泛&#xff0c;它是线上收集信息或用户预约/需求服务的重要方式&#xff0c;对商家来说如今线上平台非常多&#xff0c;生意开展的形式也越来越多&#xff0c;比如常见的预约、报名、收款、产品支付等都可以通过表单实现。 接下来啊让我们看看通过【雨科】平台…

一文详解大模型归因机制,幻觉问题有救了!

作者 | 谢年年、python 大模型的幻觉问题一直是一个亟待解决的挑战。由于大模型的训练语料来源广泛&#xff0c;且都是未经筛选的现实世界文本&#xff0c;预训练的目标也仅在于预测下一个单词&#xff0c;并未对生成内容的真实性进行建模和验证&#xff0c;这导致了大模型幻觉…

基于SuperMap iObjects Java生成地图瓦片

作者&#xff1a;dongyx 前言 在GIS领域&#xff0c;地图瓦片技术作为GIS领域的关键技术&#xff0c;是提高地图服务性能的关键手段之一。通过预先生成地图的瓦片数据&#xff0c;可以显著提升用户访问地图时的响应速度和体验。SuperMap iObjects for Java作为一款强大的GIS开…

浏览器渲染页面的过程以及原理

什么是浏览器渲染 简单来说&#xff0c;就是将HTML字符串 —> 像素信息 渲染时间点 浏览器什么时候开始渲染&#xff1f; 网络线程发送请求&#xff0c;取回HTML封装为渲染任务并将其传递给渲染主线程的消息队列。 问题&#xff1a;只取回HTML吗&#xff1f;那CSS和JS呢&am…

帆软认证FCRP第二题

【题目要求】 数据库中有一张地区数据统计表&#xff0c;但是并不规则 &#xff0c;记录类似于&#xff0c;225100:02:3:20160725是一串代码&#xff0c;以&#xff1a;分割&#xff0c;第1位为地区代码&#xff0c;第2位为分类代码&#xff0c;第3位为数量&#xff0c;第4位为…

Leetcode—901.股票价格跨度【中等】

2023每日刷题&#xff08;五十二&#xff09; Leetcode—901.股票价格跨度 算法思想 实现代码 class StockSpanner { public:stack<pair<int, int>> st;int curday -1;StockSpanner() {st.emplace(-1, INT_MAX);}int next(int price) {while(price > st.top(…

[网鼎杯 2020 朱雀组]phpweb1

提示 call_user_func()函数先通过php内置函数来进行代码审计绕过system&#xff08;##不止一种方法&#xff09; 拿到题目养成一个好的习惯先抓个包 从抓到的包以及它首页的报错来看&#xff0c;这里死活会post传输两个参数func以及p func传输函数&#xff0c;而p则是传输参数的…

关于前端原生技术-Jsonp的理解与简述

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/134777717 出自【进步*于辰的博客】 在学习了Jsoup这个知识点之后&#xff0c;发觉js的这一特点…

2、Redis变慢原因排查(下)

感觉Redis变慢了&#xff0c;这些可能的原因你查了没 &#xff1f;(下) Redis变慢排查的上一篇【感觉Redis变慢了&#xff0c;这些可能的原因你查了没 &#xff1f;(上)】&#xff0c;我们是基于Redis命令为入口&#xff0c;比如命令使用不得当&#xff0c;bigkey问题&#xf…

Vue3组件使用问题

Vue3组件学习 文章目录 Vue3组件学习一、Message 全局提示组件返回数据换行问题二、DatePicker 日期选择框组件限制选定年份问题 一、Message 全局提示组件返回数据换行问题 问题&#xff1a;使用中发现仅仅通过写入\n或<br/>&#xff0c;无法实现回车显示的结果。 解决…

网站高性能架构设计——web前端与池化

从公众号转载&#xff0c;关注微信公众号掌握更多技术动态 --------------------------------------------------------------- 一、高性能浏览器访问 1.减少HTTP请求 HTTP协议是无状态的应用层协议&#xff0c;也就是说每次HTTP请求都需要建立通信链路、进行数据传输&#xf…

Swagger Array 逐步解密:带你简化开发工作

Swagger 允许开发者定义 API 的路径、请求参数、响应和其他相关信息&#xff0c;以便生成可读性较高的文档和自动生成客户端代码。而 Array &#xff08;数组&#xff09;是一种常见的数据结构&#xff0c;用于存储和组织多个相同类型的数据元素。数组可以有不同的维度和大小&a…

想要高速文件传输?这些Aspera替代方案等你来试

在现如今数字化的时代&#xff0c;文件传输已成为企业、组织以及个人日常工作中必不可少的一部分。但是&#xff0c;面对庞大的数据量和低效的传输速度&#xff0c;很多人会感到头疼和无奈。在这样的情况下&#xff0c;高速文件传输工具成为了一个热门话题。而aspera替代方案则…

React/Vue/Svelte 前端项目中开始使用TailwindCSS

背景 TailwindCSS 近年来在前端圈非常流行&#xff0c;它摆脱了原有的CSS限制&#xff0c;以灵活实用为卖点&#xff0c;用户通过各种class组合即可构建出漂亮的用户界面。对于初学者而言&#xff0c;可能需要一些上手成本&#xff0c;一旦掌握实用技巧后&#xff0c;Tailwind…

JetBrains Rider for Mac/win中文版- 跨平台.NET 开发的终极选择!

在.NET开发世界中&#xff0c;JetBrains Rider凭借卓越的性能和丰富的功能成为了开发者的首选。JetBrains Rider是一款跨平台.NET集成开发环境&#xff08;IDE&#xff09;&#xff0c;可在Windows和macOS上无缝运行&#xff0c;为.NET开发提供了卓越的工作体验。 JetBrains R…

C++新经典模板与泛型编程:用成员函数重载实现std::is_convertible

用成员函数重载实现is_convertible C标准库中提供的可变参类模板std::is_convertible&#xff0c;这个类模板的主要能力是判断能否从某个类型隐式地转换到另一个类型&#xff0c;返回的是一个布尔值true或false。例如&#xff0c;一般的从int转换成float或从float转换成int&am…

相控阵天线(十四):常规大阵列天线分布(椭圆阵列、三角阵列、矩形拼接阵列、栅格拼接阵列)

目录 简介椭圆阵列三角阵列子阵拼接的矩形阵列子阵拼接的圆形阵列圆形子阵拼接阵列子阵栅格拼接阵列 简介 前面的博客已经介绍过常见的平面阵有一些基本类型&#xff0c;本篇博客介绍一些实际工程中可能出现的阵列&#xff0c;包括椭圆阵列、子阵通过矩形拼接形成的矩形大阵列…