写在前面
服务器有个定时任务,需要进行大批量的接口请求和数据操作,最大线程数拉满了,仍不能满足要求,因为服务器硬件核心数就摆在那。
最多能并发的线程就 内核个数*2,即所谓的核心线程数,其他的线程会被放到线程数中等待执行,看似开了 200个线程,其实大多是心理安慰😂
代码逻辑已经优化的不能再优化了,只好考虑横向扩展了,即增加一台机器执行,分散服务器的压力。两台服务器执行同一个任务,那么在相同的时间范围内,能传输的数据 肯定比在单台服务器上要多。
遍观各项技术架构,dubbo 似乎是不可或缺的组件,它可以让不同服务器之间的程序进行远程RPC调用,且消耗资源要比 RESTful小。同时搭配nacos的注册中心,简直是绿茶配青梅,天生是一对。
说干就干,于是,这无数的坑就来了...
那,dubbo和nacos是什么呢?下面是个比喻
当你去餐厅吃饭,Dubbo 就像服务员,Nacos 就像菜单和餐厅的接待台。
- Dubbo(服务员):Dubbo 就像服务员,它帮助你点菜,把你的点餐信息传递给厨房,并把菜端到你的桌子上。它协调不同的服务,确保你的请求被满足。
- Nacos(菜单和接待台):Nacos 就像菜单,上面列出了餐厅提供的各种菜肴,以及它们的价格和描述。同时,Nacos也是接待台,你可以在那里获取餐厅的地址、联系信息,以及了解特别优惠和促销信息。
将Dubbo和Nacos结合起来,就像在餐厅里有一个聪明的服务员(Dubbo)拿着菜单(Nacos)帮助你点菜、协调厨房和为你提供更多关于餐厅的信息。这使你能够轻松享受美食而不必亲自处理所有细节。
步骤
我的目标是是这样的 让部署在 服务器A上的消费者C1 能同时调用 服务器A 上的提供者 P1 ,和服务器B上的提供者 P2。
网上的攻略,看似很难,实则不简单...
需要一台开发机(我的是windwos)用于部署 消费者1(简称 C1)和提供者1(简称 P1),以及nacos,一台linux测试机,用来部署提供者2(简称 P2)。由于我要模拟跨服务调用,windwos上的nacos需要内网穿透,将注册中心的地址暴露给linux中的P2 供C1来调用。
一:nacos
nacos 是 SpringCloudAlibaba的一个注册和配置中心组件
Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos 致力于帮助您发现、配置和管理微服务。
Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。
Nacos 是构建以"服务"为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
不多逼逼,直接下载运行。
下载链接:github.com/alibaba/nac...
下载zip压缩包,解压,找到 bin目录下的startup.cmd,编辑,把下图的地方改为 standalone,
双击 startup.cmd ,nacos会以单机模式启动。(与之对应的是集群模式,我以后用到了再回来修改)
启动成功 会弹出一些命令行,如下图所示。程序运行的过程中要保持这个窗口,不要随手关掉了。(也可以创建个服务 后台运行)
二:内网穿透
上面的nacos在我本地启动后,可以通过命令行中的网址10.239.20.202:8848/nacos/index.html
访问到 nacos控制台页面。
同时我的代码内也可以通过配置 10.239.20.202:8848
这个ip端口访问nacos程序。
但是,上面的 10.239.20.202是我本地内网的ip,如果另一台机器上的程序跟当前机器不处于同一局域网,那么就访问不到 部署在我本地的 nacos注册中心了。
(注:实际上这也是nacos组件的原意,它不希望注册中心对外开放,它推荐在内网即同一局域网内使用,各服务通过内网ip注册调用)
但我们就是头铁,偏要逆水行舟。所以我们需要做内网穿透,将本地nacos注册中心的地址暴露出来。内网穿透大家都会使用,我推荐使用NATAPP,不推荐花生壳。
这一步也是挺坑的一步,最初因为这一步卡壳了很久。springboot+dubbo 的配置文件中的注册中心 ip:port
格式,所以我下意识的认为 我应该用tcp 协议的方式穿透,因为tcp协议穿透出来的网址就是ip:port
格式。配置上去后 要么是消费者找不到提供者方法,要么是服务列表找不到服务,要么是双双掉线。一大串儿问题。
正确的做法是,使用web协议穿透,然后我们在配置文中的port中手动添加端口号为80,得到一个 ip:80的可供外网调用的ip端口。
三:dubbo
dubbo 也是 SpringCloudAlibaba的一个组件,用于rpc调用的。
调用方 称之为 消费者,被调用方 称之为 提供者。
讲到dubbo,就涉及到代码了,我们先来看看项目结构。
项目模块从上往下 依次 是 公共类、消费者、提供者。
公共类中存放一些 消费者和提供者都可能用到的类,比如entity,公共参数等等。
接口类 interface也会定义在公共类中,由消费者调用,由提供者实现。
具体一点就是:
在公共类定义 doSomeThingService
在提供者实现这个service,doSomeThingImpl上添加注解 @DubboService
在消费者注入这个service,不过不用@Autowired,而是用@DubboReference
如下:
公共类:
提供者:
消费者:
通过dubbo框架,可以让部署在A服务器上的消费者直接调用部署在B服务上的提供者方法。
四:springboot集成
公共类
一个接口类,平平无奇,无甚可讲
提供者
1、pom文件
xml
<dubbo.version>2.7.13</dubbo.version>
<nacos.version>1.4.1</nacos.version>
xml
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
</dependency>
<!-- 解决dubbo2.7.13jar包冲突问题-->
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
<version>1.0.11</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
除了导入上面这4个包外,还需要依赖公共模块,公共模块是自定义的,上面就不展示了
2、配置文件 application.properties
ini
server.port=8901
spring.application.name=tongcheng-provider
dubbo.registry.address=nacos://ujx58f.natappfree.cc:80
dubbo.registry.parameters.namespace=8deefd1b-0a2f-432a-b44b-195d5d3c7664
dubbo.protocol.name=dubbo
dubbo.protocol.port=20881
dubbo.provider.timeout=36000000
参数一一介绍
- port 是springboot程序的启动端口
- name 是模块的名字,也会展示在nacos的服务列表中
- address 是注册中心的地址,可以看到我使用的是nacos的注册中心,后面接的是内网穿透的地址
- namespace是命名空间,用于隔离不同的服务消费,可以理解成分组的功能。里面的值怎么来的可以看下图
- name=dubbo是nacos列表的配置分组
- port是注册nacos的端口号,干啥用的呢,就是供其他服务调用的时候用的,具体的调用及分配策略,是在nacos控制台设置的
- timeout是服务调用超时时间
nacos 控制台操作:1
创建一个命名空间,他会自动生成一串id,配到上面的namespace处。
3、启动类:
在启动类上添加一个注解 @EnableDubbo,如下图所示
同时再添加一个 EntityScan注解,用于扫描公共类中实体的位置,不然可能会报错。同时实体类需要序列化,即 implements Serializable,不然可能也会报错。
4、实现类
消费者
1、pom文件(与提供者相同)
xml
<dubbo.version>2.7.13</dubbo.version>
<nacos.version>1.4.1</nacos.version>
xml
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
</dependency>
<!-- 解决dubbo2.7.13jar包冲突问题-->
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
<version>1.0.11</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
2、配置文件 application.properties
ini
server.port=8080
spring.application.name=manage-system
dubbo.registry.address=nacos://ujx58f.natappfree.cc:80
dubbo.registry.parameters.namespace=8deefd1b-0a2f-432a-b44b-195d5d3c7664
dubbo.protocol.name=dubbo
dubbo.protocol.port=-1
dubbo.provider.timeout=36000000
配置文件跟提供者也差不多,就两个port要变化,springboot程序的端口号要变,注册nacos的端口号要改成-1.
当你的dubbo.protocol.port
配置为-1时,Dubbo将在运行时动态选择一个可用的端口,并在注册中心(如ZooKeeper或Nacos)中注册服务时使用这个端口信息。这有助于避免端口冲突,特别是在多个Dubbo服务运行在同一台机器上或在不同的开发/测试环境中时。
其他的配置文件就于提供者一样了
3、启动类
启动类同上,添加@EnableDubbo注解,表示支持dubbo的注释。
4、调用
在需要远程调用的类,使用注解 @DubboReference 引入公共接口类。
然后在方法中,直接用调用就公共接口类中的方法就OK了,感觉就像 @Autowired引入的方法一样,很丝滑。
控制台
经过上面的代码,此时提供者和消费者都有了,为了模拟分布式操作,启动两份提供者代码。把提供者copy1份,改一下端口号,并修改程序名为tongcheng-provider2,然后先启动提供者,再启动消费者。
等三个程序都启动成功后,打开nacos控制台(http://内网ip:8848/nacos/index.html)
可以看到菜单=》服务管理=》服务列表中有 消费者和提供者了。消费者1个,提供者2个,如下。
点击 提供者操作栏的详情,可以看到 提供者下有两个ip,第一个是部署在我windwos本机的提供者1的内网ip,第二个是部署在linux服务器的提供者2的外网ip(马赛克了)。
部署在我windows本机的消费者现在可以同时调用到 提供者1和提供者2,默认按1:1的权重轮询调用,权重也可以在后面的编辑中配比。
当点击其中一台提供者后面的下线按钮后,消费者会默认访问另外在线的一台提供者。
此时nacos+dubbo的远程调用的基本功能就已经实现了。
写在后面
上面的操作只解决了调用问题。其实文中可以看到,消费者是一个定时任务,那前方还有很多坑在等着我,比如:redis分布式锁的问题,分布式定时任务的并发的问题等等,后面会再持续更新...
特此记录,已备后用。