一、目标架构图
其中,nacos,nginx,mysql,mq,redis,gateway,服务均为集群模式。使用docker模拟集群分布。
- Spring Boot 2.3.9.RELEASE
- Spring Cloud H版
- Cloud Alibaba 2.2.5.RELEASE
- RabbitMq 3.7.14
- Redis 5.0
- mysql 5.7.*
- Docker 18.09.0
- JWT 0.9.0
- Lombok 1.18.6
- Maven 5.1
二、环境部署
所有的环境都是在服务器上用docker模拟分布式集群的方式搭建的
1.docker安装
curl -sSL https://get.daocloud.io/docker | sh
在服务器终端中运行该指令
2.数据库
2.1docker安装mysql数据库5.7
2.1docker安装mysql数据库5.7
2.1.1搭建单体数据库
1. 拉取 MySQL 镜像
docker pull mysql:5.7
2. 设置 MySQL 配置文件
将全部的配置文件和关联的文件夹统一放到 /opt/docker/mysql 中
创建 MySQL 配置文件文件夹
mkdir -p /opt/docker/mysql/conf.d
增加并修改配置文件 config-file.cnf
vim /opt/docker/mysql/conf.d/config-file.cnf
输入如下内容:
- [mysqld]
- # 设置表名不区分大小写 linux下默认是区分的,windows下默认不区分
- lower_case_table_names=1
- #server-id=1
- datadir=/var/lib/mysql
- #socket=/var/lib/mysql/mysqlx.sock
- #symbolic-links=0
- # sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
- [mysqld_safe]
- log-error=/var/log/mysqld.log
- pid-file=/var/run/mysqld/mysqld.pid
3. 启动
创建 MySQL 数据文件夹
mkdir -p /opt/docker/mysql/var/lib/mysql
启动,设置默认密码 root,TZ 设置容器的默认时区
docker run —name mysql
—restart=always
-p 3306:3306
-v /opt/docker/mysql/conf.d:/etc/mysql/conf.d
-v /opt/docker/mysql/var/lib/mysql:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=root
-e TZ=Asia/Shanghai
-d mysql:5.7
4. 修改密码
- docker exec -it mysql bash
- 进入 MySQL
- mysql -uroot -p
- 输入刚才我们设置的密码 root
- 授权
- mysql> GRANT ALL ON *.* TO 'root'@'%';
- 刷新权限
- mysql> flush privileges;
- 更新加密规则
- mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'root' PASSWORD EXPIRE NEVER;
- 更新 root 密码
- mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
- 刷新权限
- mysql> flush privileges;
- 查看用户
- mysql> use mysql;mysql> select user,host from user;
- 退出容器
- exit
有此条记录即成功
navicat链接数据库测试,成功。
2.1.2搭建主从mysql数据库,且读写分离
直接docker启动两个mysql容器,分别叫mysql-master和mysql-slave;从数据库映射到3302端口。
进入主数据库,安装vim,编辑my.cnf文件如下
- [mysqld]
- log-bin=/var/log/mysql/mysql-bin
- server-id=1
- gtid_mode=ON
- enforce_gtid_consistency=1 # 强制执行GTID一致性。
如果省略server-id(或将其显式设置为默认值0),则主服务器拒绝来自从服务器的任何连接。如果省略server-id(或将其显式设置为默认值0),则主服务器拒绝来自从服务器的任何连接。
创建日志目录并赋予权限
- mkdir /var/log/mysql
- chown mysql.mysql /var/log/mysql
重启服务:systemctl restart mysqld
创建一个专门用于复制数据的用户
每个从服务器需要使用MySQL 主服务器上的用户名和密码连接到主站。计划使用用户 repl 可以从任何主机上连接到 master 上进行复制操作, 并且用户 repl 仅可以使用复制的权限。
创建repl用户
CREATE USER 'repl'@'%' IDENTIFIED BY '123456789';
用户名:repl
主机:使用通配符%,允许任意远程主机登陆
密码:123456789
对repl用户进行授权
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
在从库测试用户有效性
mysql -urepl -p'123456789' -h192.168.0.101
之后再配置从库的my.cnf
vim /etc/my.cnf
- [mysqld]
- server-id=2
- gtid_mode=ON
- enforce_gtid_consistency=1
- # 可选项, 把连接到 master 的信息存到数据库中的表中
- master-info-repository=TABLE
- relay-log-info-repository=TABLE
- read_only=1#可以设置只读
重启从数据库服务
systemctl restart mysqld
开启Master-Slave主从复制
进入Master库mysql客户端:输入show master status查看Master状态:
- change master to master_host='172.18.0.3',
- master_user='slave',
- master_password='123456',
- master_port=3306,
- master_log_file='master-bin.000001',
- master_log_pos=617,
- master_connect_retry=30;
在从数据库中执行start slave;开启主从
show slave status G查看主从状态。
2.2执行nacos数据库的脚本
新建数据库nacos
之后运行sql脚本
脚本地址:nacos/nacos-mysql.sql at develop · alibaba/nacos · GitHub
3.nacos集群搭建
- docker拉取nacos镜像:docker pull nacos/nacos-server:2.0.3
- 依次启动三个nacos服务,分别以8846,8847,8848端口启动
下面是docker compose脚本
- version: "3"
- services:
- nacos1:
- container_name: nacos-server01
- hostname: nacos-server01
- image: nacos/nacos-server:2.0.3
- environment:
- - MODE=cluster
- - PREFER_HOST_MODE=hostname
- - NACOS_SERVERS=nacos-server01:8848 nacos-server02:8848 nacos-server03:8848
- - SPRING_DATASOURCE_PLATFORM=mysql
- - MYSQL_SERVICE_HOST=你的mysql 地址
- - MYSQL_SERVICE_PORT=3306
- - MYSQL_SERVICE_USER=root
- - MYSQL_SERVICE_PASSWORD=123456
- - MYSQL_SERVICE_DB_NAME=nacos
- - JVM_XMS=256m
- - JVM_XMX=256m
- - JVM_XMN=256m
- volumes:
- - /home/nacos/cluster-logs/nacos-server01:/home/nacos/logs
- - /home/nacos/init.d:/home/nacos/init.d
- ports:
- - 8846:8848
- - 9555:9555
- - 9847:9849
- restart: on-failure
- nacos2:
- container_name: nacos-server02
- hostname: nacos-server02
- image: nacos/nacos-server:2.0.3
- environment:
- - MODE=cluster
- - PREFER_HOST_MODE=hostname
- - NACOS_SERVERS=nacos-server01:8848 nacos-server02:8848 nacos-server03:8848
- - SPRING_DATASOURCE_PLATFORM=mysql
- - MYSQL_SERVICE_HOST=你的mysql地址
- - MYSQL_SERVICE_PORT=3306
- - MYSQL_SERVICE_USER=root
- - MYSQL_SERVICE_PASSWORD=123456
- - MYSQL_SERVICE_DB_NAME=nacos
- - JVM_XMS=256m
- - JVM_XMX=256m
- - JVM_XMN=256m
- volumes:
- - /home/nacos/cluster-logs/nacos-server02:/home/nacos/logs
- - /home/nacos/init.d:/home/nacos/init.d
- ports:
- - 8847:8848
- - 9848:9849
- restart: on-failure
- nacos3:
- container_name: nacos-server03
- hostname: nacos-server03
- image: nacos/nacos-server:2.0.3
- environment:
- - MODE=cluster
- - PREFER_HOST_MODE=hostname
- - NACOS_SERVERS=nacos-server01:8848 nacos-server02:8848 nacos-server03:8848
- - SPRING_DATASOURCE_PLATFORM=mysql
- - MYSQL_SERVICE_HOST=你的mysql地址
- - MYSQL_SERVICE_PORT=3306
- - MYSQL_SERVICE_USER=root
- - MYSQL_SERVICE_PASSWORD=123456
- - MYSQL_SERVICE_DB_NAME=nacos
- - JVM_XMS=128m
- - JVM_XMX=128m
- - JVM_XMN=128m
- volumes:
- - /home/nacos/cluster-logs/nacos-server03:/home/nacos/logs
- - /home/nacos/init.d:/home/nacos/init.d
- ports:
- - 8848:8848
- - 9849:9849
- restart: on-failure
8848端口是nacos后台管理界面的端口,9849端口是nacos集群之间互相通信需要的端口。 为了三个nacos的通信,必须映射到宿主机。
下面是docker compose脚本
8848端口是nacos后台管理界面的端口,9849端口是nacos集群之间互相通信需要的端口。 为了三个nacos的通信,必须映射到宿主机。
运行上面的docker文件,创建docker容器
docker-compose -f cluster-hostname.yaml up -d
访问三个nacos服务,查看是否配置成功。
还要使用nignx来做nacos集群的负载均衡
Nginx 的部署与其他服务部署略有不同,我们需要先启动一个 Nginx 容器实例,然后从容器事例中拷贝出 Nginx 的配置文件到指定目录,之后我们将复制出的配置文件与 Nginx 容器的数据卷进行挂载,从而达到可以在容器外部修改配置文件的目的。这么做是因为,如果直接挂载,那么容器实例中的的目录将会被外部的挂载所覆盖。这是官方 Nginx 镜像的一个小缺陷,注意一下就行了。
- 运行 Nginx 容器
- $ docker run --name temp-nginx -p 8080:8080 -d nginx:latest
- 在宿主机创建 Nginx 的挂载目录
- # 实际创建时以自己的机器环境为准
- $ mkdir -p <宿主机挂载目录>
- 拷贝容器中的配置到宿主机的挂载目录
- $ docker cp
:/etc/nginx/ <宿主机挂载目录> - 停止并删除容器实例
- $ docker stop
- $ docker rm
修改 Nginx 配置文件
位置:<宿主机挂载目录>/conf.d/default.conf
配置文件主要修改两个部分,一个是新增 upstream,通过负载均衡来配置 Nacos 服务的节点;第二个是修改 server 下的 location,在其中添加反向代理配置。另外,如果你的 Nginx 没有配置过 server_name,那么还需要修改 server 下的 server_name 配置。
完整配置文件如下:
- # 添加负载均衡配置
- upstream nacos {
- server 服务器地址:8846 weight=2 max_fails=2 fail_timeout=10s;
- server 服务器地址:8847 weight=2 max_fails=2 fail_timeout=10s;
- server 服务器地址:8848 weight=1 max_fails=2 fail_timeout=10s;
- }
- server {
- listen 80;
- listen [::]:80;
- # 修改为宿主机的 IP地址
- server_name 服务器地址;
- #access_log /var/log/nginx/host.access.log main;
- location / {
- # 添加代理配置
- proxy_pass http://nacos;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header REMOTE-HOST $remote_addr;
- add_header X-Cache $upstream_cache_status;
- add_header Cache-Control no-cache;
- #root /usr/share/nginx/html;
- #index index.html index.htm;
- }
- #error_page 404 /404.html;
- # redirect server error pages to the static page /50x.html
- #
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root /usr/share/nginx/html;
- }
- # proxy the PHP scripts to Apache listening on 127.0.0.1:80
- #
- #location ~ .php$ {
- # proxy_pass http://127.0.0.1;
- #}
- # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
- #
- #location ~ .php$ {
- # root html;
- # fastcgi_pass 127.0.0.1:9000;
- # fastcgi_index index.php;
- # fastcgi_param script_FILENAME /scripts$fastcgi_script_name;
- # include fastcgi_params;
- #}
- # deny access to .htaccess files, if Apache's document root
- # concurs with nginx's one
- #
- #location ~ /.ht {
- # deny all;
- #}
- }
编排 Nginx启动文件
- version: "3"
- services:
- nacos-nginx:
- container_name: nacos-nginx
- image: nginx:latest
- volumes:
- - /home/naocs-nginx:/etc/nginx
- ##注意这里容器挂在的位置
- ports:
- - 18848:80
- restart: on-failure
访问http://服务器ip:18848/nacos/ 查看效果
4.构造生产者消费者服务测试
4.1父工程创建
在本机上下载安装idea2021(具体方法baidu)
新建父工程cloud-demo
打开pom文件,在properties中控制整个项目的版本
UTF-8 UTF-8 1.8 Hoxton.SR8 5.1.47 2.1.1
依赖管理
org.springframework.cloud - spring-cloud-dependencies
${spring-cloud.version} pom import com.alibaba.cloud - spring-cloud-alibaba-dependencies
2.2.5.RELEASE pom import mysql - mysql-connector-java
${mysql.version} org.mybatis.spring.boot - mybatis-spring-boot-starter
${mybatis.version} org.projectlombok - lombok
4.2生产者服务集群配置
新建module:service-provider1
修改pom文件,在resources中新建application.yml文件。新建启动类。写一个简单的接口,如下。
- server:
- port: 9001
- spring:
- datasource:
- url: jdbc:mysql://10.245.153.168:3306/cloud_order?useSSL=false
- username: root
- password: 123456
- driver-class-name: com.mysql.jdbc.Driver
- application:
- name: service-provider
- cloud:
- nacos:
- server-addr: 10.245.153.168:18848 # nacos服务地址
- @SpringBootApplication
- @EnableDiscoveryClient
- public class TestServiceMain {
- public static void main(String[] args) {
- SpringApplication.run(TestServiceMain.class,args);
- }
- }
- @RestController
- public class TestController {
- @GetMapping(value = "/test/gethello")
- public String getHello(){
- return "hello,service provider 1";
- }
- }
再仿照service-provider1创造项目service-provider2。记得修改端口为9002
4.3消费者服务配置
很简单就是用openfeign同步调用生产者的接口。不要忘记也将消费者注册进nacos。
4.4上传到服务器
使用的docker来运行springboot程序
maven clear;
maven install;
将jar包命名为service-provider1,service-provider2,上传到服务器,用指令sudo rz。
之后拉取一个有java运行环境的镜像。
- docker run -d --name service-provider1 -p 9001:9001 -p 19001:19001
- -v /mydata/service-provider1.jar:/usr/app.jar java:8
- java -jar -Xms256m -Xmx256m /usr/app.jar
- docker run -d --name service-provider2 -p 9002:9002 -p 19002:19002
- -v /mydata/service-provider2.jar:/usr/app.jar java:8
- java -jar -Xms256m -Xmx256m /usr/app.jar
5.GateWay网关集群
由于是测试,就先搭建一个集群,里面运行两个网关服务
5.1新建项目
module名:gateway
选择本机的jdk1.8,创建一个空白的maven项目。设置项目坐标gav,其中groupid为父工程groupid
在pom文件中导入依赖
com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud - spring-cloud-starter-gateway
编写application.yml文件,启动的端口为10010
- server:
- port: 10010
- logging:
- level:
- cn.itcast: debug
- pattern:
- dateformat: MM-dd HH:mm:ss:SSS
- spring:
- application:
- name: gateway
- cloud:
- nacos:
- server-addr: 10.245.153.168:18848 # nacos地址
- gateway:
- routes:
- default-filters:
- - AddRequestHeader=Truth,Itcast is freaking awesome!
- - AddRequestHeader=origin,gateway
创建主启动类
写一个权限过滤器组件
- @Component
- public class AuthorizeFilter implements GlobalFilter, Ordered {
- @Override
- public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) { - // 1.获取请求参数
- ServerHttpRequest request = exchange.getRequest();
- MultiValueMap
params = request.getQueryParams(); - // 2.获取参数中的 authorization 参数
- String auth = params.getFirst("authorization");
- // 3.判断参数值是否等于 admin
- if ("admin".equals(auth)) {
- // 4.是,放行
- return chain.filter(exchange);
- }
- // 5.否,拦截
- // 5.1.设置状态码
- exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
- // 5.2.拦截请求
- return exchange.getResponse().setComplete();
- }
- @Override
- public int getOrder() {
- return -1;
- }
- }
在创建一个几乎完全相同的子项目gateway2,但是启动端口为10011,服务名不要改动
在两个网关服务中的yml文件里新增路由配置:
5.2启动测试
启动编写的网关集群,查看nacos服务列表
通过网关访问下我们的服务提供者
可见服务调用默认为轮询策略
5.3上传jar包到服务器测试
将gateway与gateway2进行一些maven install来生成jar包,然后用rz指令上传的服务器
我们都知道jar是运行在java环境中,所以只要容器中有java环境就可以运行jar包,镜像方式运行的原理也是如此。因此我们基于java镜像就可以实现jar包运行。
拉取java镜像
docker pull java:8
之后使用docker运行jar包
- docker run -d --name gateway1 -p 10010:10010
- -v /mydata/gateway1.jar:/usr/app.jar java:8
- java -jar -Xms256m -Xmx256m /usr/app.jar
- docker run -d --name gateway2 -p 10011:10011
- -v /mydata/gateway2.jar:/usr/app.jar java:8
- java -jar -Xms256m -Xmx256m /usr/app.jar
运行完后查看下效果
可见,gateway网关运行在的docker上时,显示的ip为docker中的虚拟ip,可以在application.yml文件中添加属性:
spring.cloud.nacos.discovery.ip:外网ip来修改。
5.4用nginx做负载均衡
类比做nacos集群的负载均衡,方法是一样的。
需要注意的是nginx配置文件要挂在到gateway-nginx文件夹下,防止产生冲突。
6.sentinel服务降级,流量控制
6.1安装
拉取镜像
docker pull bladex/sentinel-dashboard
运行docker file
- docker run -dit
- --name sentinel-nacos
- -p 18858:8858
- --restart=always
- -e NACOS_SERVER_ADDR=10.245.153.168:18848
- -e NACOS_USERNAME=nacos
- -e NACOS_PASSWORD=nacos
- -e NACOS_NAMESPACE=public
- -e NACOS_GROUP_ID=SENTINEL_GROUP
- bladex/sentinel-dashboard
访问http://你的ip:18858/ , 输入用户名密码都是sentinel
看看后台页面
将之前的service-provider1项目进行sentinel流控,修改yml文件
注意,由于我们的sentinel运行在服务器里的docker中,故要添加spring.cloud.sentinel.transport.client-ip属性,该属性为你的电脑的公网ip,也就是service-provider1项目运行在的主机的ip
运行起项目,访问几次gethello接口
添加一个流控规则,在看看访问接口的反应
6.2持久化规则
当我们一旦重启sentinel应用,sentinel写的规则消失,生产环境需要将配置规则进行持久化。
在我们之前建立的service-provider1项目中的pom文件里 ,添加依赖
yml文件中,添加
在nacos配置中心新增配置
注意属性的一一对应
运行下sentinel,访问刚才添加配置的接口,规则成功
再重启sentinel,发现规则还在。
只能通过Nacos修改规则配置,通过Dashboard修改规则配置不自动刷新Nacos配置,重启Dashboard后只保留Nacos中数据!!!
6.4到目前为止的项目架构
7.redis
7.1redis集群方式
1.主从复制
2.哨兵集群
3.redis-cluster集群
我们本次使用redis主从复制的形式搭建redis集群
什么是主从复制?
答:就是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点。默认情况下,每台Redis服务器都是主节点,且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。给大家个图来理解下:
主从复制有什么作用?
答:①:数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
②:故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。换句话说就是主服务器挂掉了,从服务器顶上去。
③:负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
7.2开始搭建
目标:一主,一从,测试用
先拉取镜像
docker run —name redis-master -d -p 16379:6379 redis:latest
docker run —name redis-master -d -p 16380:6379 redis:latest
使用指令docker exec 和redis-cli
分别进入两个redis数据库,查看ip信息输入info
- 172.17.0.4
- 172.17.0.5
我们把172.17.0.5作为随从数据库,在其reids终端中输入
SLAVEOF 主ip 主端口(均是前面的ip与端口)
之后再用info指令查看是否修改成功。
7.3测试
我们在主节点设置一个属性 set name : why
我们在从随从节点获取 get name : why
成功
7.4进一步扩展
可以在部署哨兵模式或者分片集群模式。
8.rabbitMQ消息队列
8.1RabbitMQ安装(单机版)
在线拉取镜像
- docker pull rabbitmq:3-management
执行下面的命令来运行MQ容器
- docker run
- -e RABBITMQ_DEFAULT_USER=admin
- -e RABBITMQ_DEFAULT_PASS=123456
- --name mq
- --hostname mq1
- -p 15672:15672
- -p 5672:5672
- -d
- rabbitmq:3-management
启动成功后访问地址:http://服务器ip:15672
按照上面的用户名密码登录
8.2RabbitMQ安装(集群版)
在RabbitMQ的官方文档中,讲述了两种集群的配置方式:
- 普通模式:普通模式集群不进行数据同步,每个MQ都有自己的队列、数据信息(其它元数据信息如交换机等会同步)。例如我们有2个MQ:mq1,和mq2,如果你的消息在mq1,而你连接到了mq2,那么mq2会去mq1拉取消息,然后返回给你。如果mq1宕机,消息就会丢失。
- 镜像模式:与普通模式不同,队列会在各个mq的镜像节点之间同步,因此你连接到任何一个镜像节点,均可获取到消息。而且如果一个节点宕机,并不会导致数据丢失。不过,这种方式增加了数据同步的带宽消耗。
我们先来看普通模式集群,我们的计划部署两节点的mq集群:
| mq1 | 15672 —-> 15672 | 5672 —-> 5672 |
| mq2 | 15673 —-> 15672 | 5673 —-> 5672 |
集群中的节点标示默认都是:rabbit@[hostname],因此以上三个节点的名称分别为:
- rabbit@mq1
- rabbit@mq2
获取cookie值
RabbitMQ底层依赖于Erlang,而Erlang虚拟机就是一个面向分布式的语言,默认就支持集群模式。集群模式中的每个RabbitMQ 节点使用 cookie 来确定它们是否被允许相互通信。
要使两个节点能够通信,它们必须具有相同的共享秘密,称为Erlang cookie。cookie 只是一串最多 255 个字符的字母数字字符。
每个集群节点必须具有相同的 cookie。实例之间也需要它来相互通信。
我们先在之前启动的mq容器中获取一个cookie值,作为集群的cookie。执行下面的命令:
- docker exec -it mq cat /var/lib/rabbitmq/.erlang.cookie
可以看到cookie值如下:
HGANYJSVWWMCPJXVSYHG
接下来,停止并删除当前的mq容器,我们重新搭建集群。
在/tmp目录新建一个配置文件 rabbitmq.conf:
- cd /tmp
- # 创建文件
- touch rabbitmq.conf
文件内容如下:
- loopback_users.guest = false
- listeners.tcp.default = 5672
- cluster_formation.peer_discovery_backend = rabbit_peer_discovery_classic_config
- cluster_formation.classic_config.nodes.1 = rabbit@mq1
- cluster_formation.classic_config.nodes.2 = rabbit@mq2
再创建一个文件,记录cookie
- # 创建cookie文件
- touch .erlang.cookie
- # 写入cookie
- echo "HGANYJSVWWMCPJXVSYHG" > .erlang.cookie
- # 修改cookie文件的权限
- chmod 600 .erlang.cookie
准备目录,mq1、mq2:
- cd /tmp
- # 创建目录
- mkdir mq1 mq2
然后拷贝rabbitmq.conf、cookie文件到mq1、mq2:
- # 进入/tmp
- cd /tmp
- # 拷贝
- cp rabbitmq.conf mq1
- cp rabbitmq.conf mq2
- cp .erlang.cookie mq1
- cp .erlang.cookie mq2
创建一个网络:
- docker network create mq-net
运行命令
- docker run -d --net mq-net
- -v ${PWD}/mq1/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
- -v ${PWD}/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie
- -e RABBITMQ_DEFAULT_USER=whycast
- -e RABBITMQ_DEFAULT_PASS=123456
- --name mq1
- --hostname mq1
- -p 5672:5672
- -p 15672:15672
- rabbitmq:3-management
- docker run -d --net mq-net
- -v ${PWD}/mq2/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
- -v ${PWD}/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie
- -e RABBITMQ_DEFAULT_USER=whycast
- -e RABBITMQ_DEFAULT_PASS=123456
- --name mq2
- --hostname mq2
- -p 5673:5672
- -p 15673:15672
- rabbitmq:3-management
测试
在mq1这个节点上添加一个队列:
如图,在mq2控制台也都能看到:
到此为止,普通版集群已经部署成功,但是普通模式集群不进行数据同步,每个MQ都有自己的队列、数据信息(其它元数据信息如交换机等会同步)。例如我们有2个MQ:mq1,和mq2,如果你的消息在mq1,而你连接到了mq2,那么mq2会去mq1拉取消息,然后返回给你。如果mq1宕机,消息就会丢失。
8.3仲裁队列
从RabbitMQ 3.8版本开始,引入了新的仲裁队列,他具备与镜像队里类似的功能,但使用更加方便。
在任意控制台添加一个队列,一定要选择队列类型为Quorum类型。
因为仲裁队列默认的镜像数为5。如果你的集群有7个节点,那么镜像数肯定是5;而我们集群只有2个节点,因此镜像数量就是2.
此时停掉mq1,mq2中还存在该队列。
9.Oauth2.0鉴权
待续
10.nginx 通过 keepalived 实现高可用
10.1体系架构
在Keepalived + Nginx高可用负载均衡架构中,keepalived负责实现High-availability (HA) 功能控制前端机VIP(虚拟网络地址),当有设备发生故障时,热备服务器可以瞬间将VIP自动切换过来,实际运行中体验只有2秒钟切换时间,DNS服务可以负责前端VIP的负载均衡。
nginx负责控制后端web服务器的负载均衡,将客户端的请求按照一定的算法转发给后端处理,而Real Server将响应直接返回给客户端。
10.2简单原理
nginx-master、nginx-slave两台服务器均通过keepalived软件把你的网卡绑上一个虚拟IP(VIP)地址192.168.200.199,此VIP当前由谁承载着,服务就绑定在谁的网卡上,当nginx-master发生故障时,nginx-slave会通过keepalived配置文件中设置的心跳时间advert_int检查,无法获取nginx-master正常状态的话,keepalived首先会执行脚本来重启nginx-master,重启仍然失败,会切换到备机运行。nginx-slave会瞬间绑定VIP来接替nginx_master的工作,当nginx-master恢复后keepalived会通过priority参数判断优先权将虚拟VIP地址192.168.200.199重新绑定给nginx-master的网卡。
10.3使用此方案的优越性
1.实现了可弹性化的架构,在压力增大的时候可以临时添加web服务器添加到这个架构里面去;
2.upstream具有负载均衡能力,可以自动判断后端的机器,并且自动踢出不能正常提供服务的机器;
3.相对于lvs而言,正则分发和重定向更为灵活。而Keepalvied可保证单个nginx负载均衡器的有效性,避免单点故障;
4.用nginx做负载均衡,无需对后端的机器做任何改动。
5.nginx部署在docker容器里,即大量地节约开发、测试、部署的时间,又可以在出现故障时通过镜像快速恢复业务。
10.4部署
1.准备两台服务器,都安装好docker
2.docker pull nginx #这里获取的是最新的 nginx
3.创建文件夹用于使用自己定义的配置文件以及日志文件
- mkdir -p /mydata/docker/nginx # 配置文件
- #docker 起一个nginx来获取配置文件
- docker run --name temp-nginx -p 80:80 -d nginx:latest
- #拷贝配置文件
- $ docker cp temp-nginx:/etc/nginx/ /mydata/docker/
- 之后再删除刚才的容器
4.在 /mydata/docker/nginx 目录下修改配置文件: vi nginx.conf,再修改conf.d下的default.conf文件
- user root;
- worker_processes auto;
- error_log /var/log/nginx/error.log notice;
- pid /var/run/nginx.pid;
- events {
- worker_connections 1024;
- }
- http {
- include /etc/nginx/mime.types;
- default_type application/octet-stream;
- log_format main '$remote_addr - $remote_user [$time_local] "$request" '
- '$status $body_bytes_sent "$http_referer" '
- '"$http_user_agent" "$http_x_forwarded_for"';
- access_log /var/log/nginx/access.log main;
- sendfile on;
- #tcp_nopush on;
- keepalive_timeout 65;
- #gzip on;
- include /etc/nginx/conf.d/*.conf;
- }
- upstream gateway {
- server 10.245.153.169:10010 weight=1 max_fails=2 fail_timeout=5s;
- server 10.245.153.169:10011 weight=1 max_fails=2 fail_timeout=5s;
- }
- server {
- listen 80;
- listen [::]:80;
- # 修改为宿主机的 IP地址
- server_name 10.245.153.169;
- #access_log /var/log/nginx/host.access.log main;
- location / {
- # 添加代理配置
- proxy_pass http://gateway;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header REMOTE-HOST $remote_addr;
- add_header X-Cache $upstream_cache_status;
- add_header Cache-Control no-cache;
- #root /usr/share/nginx/html;
- #index index.html index.htm;
- }
- #error_page 404 /404.html;
- # redirect server error pages to the static page /50x.html
- #
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {docker
- root /usr/share/nginx/html;
- }
- # proxy the PHP scripts to Apache listening on 127.0.0.1:80
- #
- #location ~ .php$ {
- # proxy_pass http://127.0.0.1;
- #}
- # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
- #
- #location ~ .php$ {
- # root html;
- # fastcgi_pass 127.0.0.1:9000;
- # fastcgi_index index.php;
- # fastcgi_param script_FILENAME /scripts$fastcgi_script_name;
- # include fastcgi_params;
- #}
- # deny access to .htaccess files, if Apache's document root
- # concurs with nginx's one
- #
- #location ~ /.ht {
- # deny all;
- #}
- }
5.在 /mydata/docker/nginx/html 目录下创建首页(仅仅是后面用来判断请求落在了哪个机器上,主机和备机能区分开就行): vi index.html
Master machine
6.启动nginx
- docker run --name nginx-master --privileged=true --restart=always -p 80:80
- -v /mydata/docker/nginx:/etc/nginx
- -v /mydata/docker/nginx/html:/usr/share/nginx/html
- -d nginx:latest
- docker run --name nginx-slave --privileged=true --restart=always -p 80:80
- -v /mydata/docker/nginx:/etc/nginx
- -v /mydata/docker/nginx/html:/usr/share/nginx/html
- -d nginx:latest
由于都是启动的80端口,故可以直接用ip+接口名来访问
可见,成功代理。
下面就要引入keepalived进行高可用
7.安装keepalived插件
这里不用docker,直接在服务器终端里输入以下指令
yum install keepalived -y
进入/etc/keepalived/下 vi keepalived.conf
下面是运行着nginx-master容器的服务器的配置
- global_defs {
- notification_email {
- acassen@firewall.loc
- failover@firewall.loc
- sysadmin@firewall.loc
- }
- notification_email_from Alexandre.Cassen@firewall.loc #定义利用什么邮箱发送邮件
- smtp_server smtp.163.com #定义邮件服务器信息
- smtp_connect_timeout 30 #定义邮件发送超时时间
- router_id 10.245.153.168 #(重点参数)局域网keppalived主机身份标识信息(每台唯一)
- script_user root #添加运行健康检查脚本的用户
- enable_script_security #添加运行健康检查脚本的组
- }
- vrrp_script chk_http_port {
- script "/usr/local/src/nginx_check.sh" #表示将一个脚本信息赋值给变量check_web,down机后就运行这个文件
- interval 5 #检测脚本执行的间隔
- weight -20 #监测失败,则相应的vrrp_instance的优先级会减少20个点,这样主服务器会切换
- }
- vrrp_instance VI_1 {
- state MASTER #keepalived角色描述信息,备份服务器上将 MASTER 改为 BACKUP
- interface ens192 #将虚拟ip用于那块网卡
- virtual_router_id 51 #主、备机的 virtual_router_id 必须相同
- priority 100 #主、备机取不同的优先级,主机值较大,备份机值较小取90
- advert_int 1 #主服务器组播包发送间隔时间
- authentication { # 主备主机之间的认证表示信息
- auth_type PASS #采用明文认证机制
- auth_pass 1111 #编写明文密码
- }
- virtual_ipaddress {
- 服务器所在网段未分配的ip地址 #设置虚拟ip地址信息,此参数备节点设置和主节点相同
- }
- track_script {
- chk_http_port #调用执行脚本
- }
- }
添加检查nginx状态的脚本vim /usr/local/src/nginx_check.sh
- #!/bin/bash
- # 传入容器名称
- containerName=nginx-slave
- currTime=`date +"%Y-%m-%d %H:%M:%S"`
- # 查看进程是否存在
- exist=`docker inspect --format '{{.State.Running}}' ${containerName}`
- if [ "${exist}" != "true" ]; then
- pkill keepalived #杀死所有keepalived服务进程
- # 记录
- echo "${currTime} docker容器宕机,容器名称:${containerName}" >> /mnt/xvde1/ms_ctynyd/scripts/wbwf_monitor.log
- fi
一定要给这个脚本文件可执行权限(看到变成可执行的颜色),执行命令:chmod u+x /usr/local/src/nginx_check.sh
之后,在两台服务器上分别执行systemctl restart keepalived.service命令。开启keepalived插件。
访问我们之前设置的虚拟ip发现可以访问成功
之后shutdown掉一个nginx,看看keepalived插件能否进行vip的迁移。还能够访问到我们的服务,成功。
11.jmeter进行压力测试
11.1测试最外层nginx转发能力
压力配置均以上图所示进行。
访问虚拟ip,两个nginx+keepalived,来进行转发请求。
5000个线程的请求有14个超时未连接
直接通过网关访问请求
请求异常率大幅降低,但是响应时间最大值非常高
从上面两组测试对比可以知道,处理请求并发量受到nginx集群转发速度的影响。
上网查阅资料找到,可以在nginx.conf中修改nginx处理并发请求的能力
图中worker_connection值本来是1024,修改成为8192,再次测试查看结果。
异常率降低到零。说明1s内5000线程量的请求完全可以接受。
提高到两万
提高到三万
这是异常率变高,且请求响应时间大幅增加。
11.2测试mq集群抗压能力



