SpringBoot+Redis集群构建分布式“高”并发扣库存

学习技术是枯燥的,更是有趣和满心欢喜的。

1,前言

首先为什么【高】加了双引号?

因为我没有多节点(3个以上)或者上云测试过,也没有部署前端Nginx+Tomcat集群,算不上真正完整的能抗住高并发的系统,文章内容只给大家提供一个基本实现和部署细节,大家可以指摘出其中的问题,或有更好的建议意见也欢迎告诉我。

2,CentOS部署Redis主从集群

概要:5个CentOS虚拟机节点,分别部署在两台物理主机的虚拟机上。

IP地址为:192.168.2.5/192.168.2.6/192.168.2.8/192.168.2.9/192.168.2.10/192.168.2.11

2.1,安装CentOS的问题

过程可以百度,分享一下安装完成后的一些问题。

Q:安装完成后不可以上网的原因?

A:是因为没有配置IP地址,Centos默认是以DHCP方式上网,我们通过修改/etc/sysconfig/network-scripts/ifcfg-ens33文件中的onboot=yes,并且改变该虚拟机的网络连接方式为桥接模式。设定完成后在root用户下,用 ***service network restart***命令重启网络服务后即可上网了。

配置网络yum源:

# 1.备份原始yum源:
	cd /etc/yum.repos.d
	mv CentOS-Base.repo CentOS-Base.repo.bak
# 2.配置CentOS的DNS:
	vim /etc/resolv.conf
	nameserver 114.114.114.114         # 国内dns
	nameserver 8.8.8.8                 # 国外dns
# 3.下载yum文件替代原始yum源:
  # (1)网易yum源:
	wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo
	yum clean   all            # 清除缓存
	yumakecache       		# 生成缓存
	解析:wget -o,使用“-o”参数来指定一个文件名

  # (2)阿里云yum源:
	wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
	yum clean  all
	yum makecache

Centos 7之后,无法使用iptables控制Linux的端口

原因:Centos 7使用firewalld代替了原来的iptables

(1)、firewalld的基本使用

启动: systemctl start firewalld
关闭: systemctl stop firewalld
查看状态: systemctl status firewalld 
开机禁用 : systemctl disable firewalld
开机启用 : systemctl enable firewalld

(2)、systemctl是CentOS7的服务管理工具中主要的工具,它融合之前service和chkconfig的功能于一体。

启动一个服务:systemctl start firewalld.service
关闭一个服务:systemctl stop firewalld.service
重启一个服务:systemctl restart firewalld.service
显示一个服务的状态:systemctl status firewalld.service
在开机时启用一个服务:systemctl enable firewalld.service
在开机时禁用一个服务:systemctl disable firewalld.service
查看服务是否开机启动:systemctl is-enabled firewalld.service
查看已启动的服务列表:systemctl list-unit-files|grep enabled
查看启动失败的服务列表:systemctl --failed
# 1.先查看防火墙状态
	firewall-cmd --state
# 2.停止防火墙
	systemctl stop firewalld.service
# 3.禁止firewall开机启动
	systemctl disable firewalld.service

# 防火墙的基本使用
# CentOS7使用firewalld打开关闭防火墙与端口
# 1、firewalld的基本使用
启动: 	systemctl start firewalld
关闭: 	systemctl stop firewalld
查看状态: 	systemctl status firewalld
开机禁用 : 	systemctl disable firewalld
开机启用 : 	systemctl enable firewalld

(3)、配置firewalld-cmd

查看版本: firewall-cmd --version
查看帮助: firewall-cmd --help
显示状态: firewall-cmd --state
查看所有打开的端口: firewall-cmd --zone=public --list-ports
更新防火墙规则: firewall-cmd --reload
查看区域信息:  firewall-cmd --get-active-zones
查看指定接口所属区域: firewall-cmd --get-zone-of-interface=eth0
拒绝所有包:firewall-cmd --panic-on
取消拒绝状态: firewall-cmd --panic-off
查看是否拒绝: firewall-cmd --query-panic

2.2,安装JDK

​ (1),首先我们需要下载Linux版本的JDK。

​ (2),将下载好的jdkxxx-xx.tar.gz包拷贝到Linux系统桌面。

​ (3),用 cp jdkxxx-xx.tar.gz /opt 拷贝至 /opt 路径下,用tar -xzvf jdkxxx-xx.tar.gz 解压。

​ (4),用 vim /etc/profile 命令添加JDK配置信息:

export JAVA_HOME="/opt/jdkxxx-xx"
export PATH="$JAVA_HOME/bin:$PATH"

​ (5),用 source /etc/profile :wq命令刷新一下上述的修改配置。

​ (6),用 echo $JAVA_HOME命令可以查看JDK版本信息。

2.3,安装Redis集群

2.3.1,Redis单机安装

(1),首先需要下载Linux版的Redis,用cp redis-x.x.x.tar.gz /usr/local 命令拷贝至 /usr/local路径下,用tar -xzvf redis-x.x.x.tar.gz 解压。解压之后会生成名为 redis-x.x.x 的文件夹。

(4),安装C语言环境【redis是用c语言开发的,所以需要该环境】

yum install gcc-c++

(5),进入redis-x.x.x 的文件夹使用 make 命令编译Redis源码

make

(6),安装Redis到指定的目录

make install PREFIX=/usr/local/redis # 如果不指定PREFIX参数的话,会默认安装到当前路径下

(7),安装完成后会在 /usr/local/redis 下生成一个 bin 文件夹【如果没有生成的话,可以使用 make test命令查看一下是否缺少依赖包,一般这里会缺少 tcl 包,我们只需用 yum install tcl 安装一下就可以了】

(8),从 redis的解压缩目录下拷贝 redis.conf配置文件到安装目录 /usr/local/redis/bin里。【一个redis需要一个redis.conf,多个redis的话就需要多个redis.conf配置文件】;其中默认IP地址:127.0.0.1,默认端口号:6379【默认端口号】。

配置文件的地址需要改成redis的服务器IP地址

bind 127.0.0.1【只能自己本地访问redis,一般设定成本机的IP地址】

(9),启动redis:在redis 安装目录用下面命令启动redis,需要指定配置文件才能启动哦

./redis-server ./redis.conf
#如果仅仅使用./redis-server的话就属于前端启动,

(10),关闭redis:

./redis-cli -h 主机IP地址 -p 6379(默认端口号) shutdown
2.3.2,Redis集群安装

(1),配置(或升级)ruby

# 在centos7中默认ruby是2.0.0版本,低于redis4.0.6最低的最低要求的2.2版本,所以需要进行升级。
# 办法是将自带的ruby卸载,在安装可以支持redis的版本。
# 卸载ruby
$ yum remove ruby
# 下载
$ wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.0.tar.gz
# 解压
$ tar -zxvf ruby-2.5.0.tar.gz
# 进入目录
$ cd ruby-2.5.0
#创建安装目录
$ mkdir -p /usr/local/ruby
# 配置并制定安装位置
$ ./configure --prefix=/usr/local/ruby
# 编译与安装,这个过程很慢,你可以去腾云驾雾一下
$ make  && make install 
# 建立软链接  
    使用命令ln -s 文件所在位置 目的位置   
    命令这么写。(ln -s /usr/local/ruby/bin/ruby /usr/local/bin/ruby) 
    是LN 不是in 
# 查看ruby版本
$ ruby -v

(2),配置Redis和ruby接口

$ yum install rubygems
# redis与ruby的接口
$ gem install redis

(3),部署其余五个节点的Redis,对各节点Redis的配置文件==redis.conf==做如下修改

bind 本机IP地址
# 设置为 redis后台运行(守护进程)
daemonize yes
# 开启aof数据备份
appendonly yes
# 开启集群
cluster-enabled yes				   
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000

(4),随便选一台Redis,进入redis-5.0.x目录【Redis解压缩目录】下,开启集群

# 回到Redis安装完成的目录下
./src/redis-trib.rb create --replicas 1 192.168.2.5:6379 192.168.2.6:6379 192.168.2.8:6379 192.168.2.9:6379 192.168.2.10:6379 192.168.2.11:6379
# 或者回到Redis安装完成的目录下按照以下命令启动集群
./bin/redis-cli --cluster create 192.168.2.5:6379 192.168.2.6:6379 192.168.2.8:6379 192.168.2.9:6379 192.168.2.10:6379 192.168.2.11:6379 --cluster-replicas 1

(5),分别启动各个节点的Redis服务【可以写个shell脚本实现】,至此,Redis集群的部署全部完成。

3,SpringBoot实现扣库存的核心代码

废话不多说,直接上核心代码吧

pom.xml中添加以下配置,reids的starter包和目前最成熟的redis操作集合redisson
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.13.0</version>
</dependency>

添加Redisson的配置类,使其能被Spring容器注入进来

@Configuration
public class RedissonConfig {
    @Bean
    public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
        return new RedissonConnectionFactory(redisson);
    }
    @Bean
    public RedissonClient redissonClient() throws IOException {
        /**
         * Java 代码配置
         */
        Config config = new Config();

        /**
         * 192.168.2.5[master]  ----  192.168.2.10[slave]
         * 192.168.2.6[master]  ----  192.168.2.11[slave]
         * 192.168.2.8[master]  ----  192.168.2.9[slave]
         */
        config.useClusterServers()
                .addNodeAddress("redis://192.168.2.5:6379",
                                "redis://192.168.2.6:6379",
                                "redis://192.168.2.8:6379",
                                "redis://192.168.2.9:6379",
                                "redis://192.168.2.10:6379",
                                "redis://192.168.2.11:6379");
        return Redisson.create(config);
    }
}

Controller中通过redisson实现分布式锁的方式扣减Redis中的库存

@PatchMapping("/delete")
    public void deleteById(){

        final String KEY_NUMS = "nums";
        String lockKey = "cy";
        boolean flg = false;

        // 通过redisson自带的RedLock方式实现分布式锁
        // RedLock的lock和unlock是通过Lua脚本实现获得和释放锁的,Lua能保证操作的原子性。【大家可以搜搜看,实现起来还是比较简单】
        RLock lock = redissonClient.getLock(lockKey);

        try{
            // 加锁
            flg = lock.tryLock(1000, TimeUnit.MILLISECONDS);
            if(flg) {
                int count = Integer.parseInt(stringRedisTemplate.opsForValue().get(KEY_NUMS));
                if (count > 0) {
                    int realCount = count - 1;
                    stringRedisTemplate.opsForValue().set(KEY_NUMS, realCount + "");
                    System.out.println("==减库存【成功】,剩余库存为: " + realCount+" ==");
                } else {
                    System.out.println("==减库存【失败】,库存不足!==");
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(flg) {
                lock.unlock();
            }
        }
    }

4,Jmeter并发测试结果

一共20000次请求,吞吐量为12620次/分钟,错误比较多,大概是有很多次接口连不上,原因可能是请求一下子太多Tomcat服务器处理不了,拒绝了很多请求连接。

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值