本内容仅用于个人学习笔记,如有侵扰,联系删除
再搭建集群项目前,请先学习相关技术的知识:
我们知道软件架构的演化过程,从单体架构,到垂直架构,再到SOA架构,最后到现在较流行的微服务架构。每个架构都有各自的优缺点,随着架构体系的演化和现如今软件整体架构的需求在不断的提高,微服务之所以比较流行就是因为它将系统服务层完全独立出来,抽取为一个一个的服务;微服务架构采用去中心化思想,服务之间采用restful等轻量协议通信,相比ESB更轻量。因为创建一个系统要考虑到全面服务,总体来说要能做到软件架构的三要素:高可用、高性能、高并发。如果一个系统做不到这三个要素,那就不能称为一个好的软件系。
本文我们着重讲解,使用SpringBoot
项目整合Zookeeper
注册中心,Nginx
反向代理和Dubbo
远程代理分布式托管,最后实现系统的高可用、高并发和高性能,其核心就是使所有服务器面对海量访问能够实现负载均衡。
SpringBoot
是当前比较流行的框架,其底层集成了Spring、mybatis、hibernate
等多种优秀框架,这个框架的好用程度就不多说了,用起来可以说是朗朗上手,带劲。Nginx
是一 个轻量级/高性能的反向代理Web服务器,而且Nginx
支持跨平台、配置简单、高并发连接:处理2-3万并发连接数,官方监测能支持5万并发,内存消耗小:开启10个nginx
才占150M内存 ,nginx
处理静态文件好,耗费内存少,它能够实现非常高效的反向代理和负载平衡。Dubbo
是一款微服务开发框架,它提供了RPC通信与微服务治理两大关键能力。这意味着,使用Dubbo
开发的微服务,将具备相互之间的远程发现与通信能力,同时利用Dubbo提供的丰富服务治理能力,可以实现诸如服务实现、负载均衡、流量调度等服务治理诉求。同时Dubbo是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。Zookeeper
是Apache Hadoop的子项目,是一个树型的目录服务,支持变更推送,适合作为Dubbo
服务的注册中心,工业强度较高,可用于生产环境,并推荐使用。Dubbo
分布式中的服务器全部使用集群,实现负载均衡):因为本次测试是在一台电脑上做测试,所以暂不使用Linux虚拟机启动Zookeeper集群服务了,怕到时候电脑啊承受不住,挂掉。我们就先在Windows下使用Zookeeper测试即可。
修改zoo.cfg配置文件信息:
修改里面的配置
这三行代码(不要修改)依次粘到后两台zookeeper配置文件中,别忘了更改端口号依次为2182、2183:
server.1=127.0.0.1:2801:3801
server.2=127.0.0.1:2802:3802
server.3=127.0.0.1:2803:3803
在启动过程中,发现第一台有报错,莫要慌,不要紧,因为在第一台启动的时候会自动寻找灵台两台zokkeeper,找不到你说急不急,所以就报错了,等三台zookeeper都启动成功了,就不会报错了!
如果实在不放心,可以连接zookeeper自带的客户端,查看下当前节点是否已创建!
出现上述节点就说明zookeeper集群此时已经启动成功了,最后一个客户端窗口可以关闭,但是上述仨窗口放着,可千万别关哈!!!
我们人如果想要知道服务提供者和消费者是是否成功注册和订阅到zookeeper
注册中心,Dubbo
官方为我们提供了一个Dubbo
管理控制台可视化界面。
启动Dubbo
控制台界面有两种方式,详情可以查看分布式微服务系列 - Dubbo
在打开的DOS命令窗口中执行命令mvn clean package,先清除一下,然后打包项目,第一次执行可能会有点慢,大概一分钟左右,稍安勿躁:
打包完成出现target目录:
首先你要确保你的此jar包所在的路径没有中文,你就可以直接在打开DOS命令窗口,切换到此路径下,执行命令java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
即可运行;如果有中文,将此jar包直接拷贝到另外一个没有中文的目录下,再执行命令:
如果觉得每次启动打开DOS窗口比较麻烦,那就jar包所在目录下创建一个批处理:
如果你得jar包运行出现错误,那就是你上述的配置或路径写错了,仔细检查一遍按照我上述的步骤重新打包很快的。
启动成功,然后我们就可以在浏览器地址栏输入localhost:7001
直接访问了
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.wtsgroupId>
<artifactId>springboot_dubbo_providerartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springboot_dubbo_providername>
<description>dubbo服务提供者聚合服务description>
<packaging>pompackaging>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<java.version>1.8java.version>
properties>
<modules>
<module>dubbo_provider_apimodule>
<module>dubbo_provider_servicemodule>
modules>
project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.6version>
<relativePath/>
parent>
<groupId>com.wtsgroupId>
<artifactId>dubbo_provider_apiartifactId>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<java.version>1.8java.version>
properties>
<dependencies>
dependencies>
project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.6version>
<relativePath/>
parent>
<groupId>com.wtsgroupId>
<artifactId>dubbo_provider_serviceartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>dubbo_provider_servicename>
<description>dubbo_provider_servicedescription>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-spring-boot-starterartifactId>
<version>2.7.6version>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-registry-zookeeperartifactId>
<version>2.7.6version>
<exclusions>
<exclusion>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-recipesartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-recipesartifactId>
<version>4.2.0version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
dubbo_provider_api
模块新建包com.wts.service在这里插入代码片
,在此包下新建HelloService
接口package com.wts.service;
/**
* @Description: HelloService
* @Author: wts
* @Date: 2022/12/23 10:37
* @Version 1.0
*/
public interface HelloService {
public String sayHello(String name);
}
dubbo_provider_service
模块新建包com.wts.service.impl
,在此包下新建接口HelloServiceImpl
实现类com.wts.impl.HelloServiceImpl
package com.wts.impl;
import com.wts.service.HelloService;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Value;
/**
* @Description: HelloServiceImpl
* @Author: wts
* @Date: 2022/12/23 10:38
* @Version 1.0
*/
@Service
public class HelloServiceImpl implements HelloService {
@Value("${server.port}")
private String port;
@Override
public String sayHello(String name) {
return "hello--" + port + "--" + name;
}
}
注意:
@Service
注解是org.apache.dubbo.config.annotation.Service
包下的,不是spring
包下的。
server:
port: 8081 #服务器端口号
dubbo:
application:
name: springboot_dubbo_provider #提供者应用名
registry:
address: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183 #连接注册中心集群
protocol: zookeeper #dubbo采用的注册中心协议
protocol: #连接注册中心协议
port: 20881 #dubbo端口号为20880,此处我们一会为了做集群区分,先改成20881
name: dubbo #dubbo协议名
monitor:
address: 127.0.0.1:7070 #dubbo监控中心地址
config-center: #配置中心
timeout: 25000 #最大超时时间
scan:
base-packages: com.wts.impl #扫描哪个包下提供的服务
在maven webapps
项目下,可以直接使用tomcat7
插件,只需修改端口号,就可以启动多台服务,在SpringBoot
项目下,当然也可以启动多台服务,如下所示:
进入配置中心:
启动之前,确认服务器端口号和dubbo端口号,以及提供服务方法的返回值:
修改application.yml配置文件中的端口号,两处port:
修改application.yml配置文件中的端口号,两处port:
此时三台服务提供者已经全部启动,但是是否成功注册到zookeeper中心了,我们可以通过上述dubbo-admin管理控制台,查看:
到这,我们就可以很安心的往下接着走下去了,三个服务者已经注册到registory服务中心了。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.6version>
<relativePath/>
parent>
<groupId>com.wtsgroupId>
<artifactId>springboot_dubbo_consumerartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springboot_dubbo_consumername>
<description>dubbo服务消费者description>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>com.wtsgroupId>
<artifactId>dubbo_provider_apiartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-spring-boot-starterartifactId>
<version>2.7.6version>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-registry-zookeeperartifactId>
<version>2.7.6version>
<exclusions>
<exclusion>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-recipesartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-recipesartifactId>
<version>4.2.0version>
dependency>
<dependency>
<groupId>org.springframework.sessiongroupId>
<artifactId>spring-session-data-redisartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
<exclusions>
<exclusion>
<groupId>io.lettucegroupId>
<artifactId>lettuce-coreartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
com.wts.controller
,在此包下新建HelloController
类package com.wts.controller;
import com.wts.service.HelloService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description: HelloController
* @Author: wts
* @Date: 2022/12/23 11:15
* @Version 1.0
*/
@RestController
@RequestMapping("/demo")
public class HelloController {
@Reference
private HelloService helloService;
@Value("${server.port}")
private int port;
@RequestMapping("/hello")
public String getName(String name){
//远程调用,获取响应结果
String result = helloService.sayHello(name);
System.out.println("consumer-" + port + "\t" + result);
return result;
}
}
注意:
@Reference
HelloService helloService;
此处的HelloService
访问的是远程的Provider
所提供的服务,所有使用@Autowire
注解是加载不到的,要使用@Reference
注解调用远程提供者发布的@Service
注解标注的服务注册接口。
server:
port: 2011 #服务器端口号
dubbo:
application:
name: springboot_dubbo_consumer #消费者服务名称
registry: #注册中心
address: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183 #连接注册中心集群
protocol: zookeeper #dubbo采用zookeeper注册中心协议
consumer: #消费者节点(配置当前消费者的统一规则,每个@Reference不需要每个都配置)
check: false #启动时不用检测提供者是否已经注册
config-center:
timeout: 25000 #超时时间 单位秒
monitor:
protocol: registry #dubbo监控中心协议,自己去监控中心找
在启动消费者前,要注意一点,因为SpringBoot
内部机制会自动加载DataSource
数据源和Redis
相关配置,即使你没有配任何置数据库相关配置信息,它内部也会默认加载,这个时候我们启动消费者服务就会出现如下错误:
Error creating bean with name ‘enableRedisKeyspaceNotificationsInitializer‘
这个时候如果你配置了数据库和redis相关配置,暂时先全部注释掉,然后在消费者主入口类的@SpringBootApplication
排除运行期间不包括的服务,如下:
package com.wts;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, RedisAutoConfiguration.class})
public class SpringbootDubboConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDubboConsumerApplication.class, args);
}
}
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, RedisAutoConfiguration.class})
,exclude
就代表不包括,排除的意思,这个时候再去逐个启动消费者服务就可以了。
上述我们开启了四台消费者服务,那么我们怎么知道每次访问的是哪一台服务消费者,既然我们配置了四台就要实现集群的机制,那么怎么实现?
这个时候Nginx
作用就来了,Nginx
反向代理可以实现负载均衡,也即是我们只需在Nginx
的配置文件中配置需要通过的消费者服务,nginx内部机制算法会自动帮我们实现负载均衡,配置如下:
nginx启动之后,此时我们就可以通过www.ebuy.com域名进行测试访问了!直接访问应该会进入nginx的内置默认页面。
在地址栏输入http://www.ebuy.com/demo/hello?name=jason
查看控制台,请求到的是哪一台消费者:
由上述测试可以看出,nginx反向代理在我们第一次请求会随机帮我们选一台消费者,然后后续请求就会轮询访问消费者,这样我们就实现了服务器的负载均衡,避免了当访问量巨大时导致某一台服务器超负载的情况。