Tomcat + Nginx 实现负载均衡
Tomcat 简介
Tomcat 是一个免费的开源的 Serlvet 容器,它是 Apache 基金会的 Jakarta 项目中的一个核心项目;
由 Apache,Sun 和其它一些公司及个人共同开发而成。
与传统的桌面应用程序不同,Tomcat 中的应用程序是一个 WAR(Web Archive)文件。
WAR 是 Sun 提出的一种 Web 应用程序格式,与 JAR 类似,也是许多文件的一个压缩包。
安装 Tomcat 服务准备工作:
主机名
操作系统
IP地址
Tomcat-A
CentOS 7.x
192.168.1.1
安装配置 Tomcat
安装 JDK:下载地址(需要创建 Oracle 账号)
[root@Tomcat-A ~]# lsanaconda-ks.cfg apache-tomcat-8.5.16.tar.gz jdk-8u91-linux-x64.tar.gz[root@Tomcat-A ~]# tar zxf jdk-8u91-linux-x64.tar.gz[root@Tomcat-A ~]# mv jdk1.8.0_91/ /us ...
线程数据交换、工作窃取算法,你懂吗?
最近栈长面试了一个 5 年经验的 Java 程序员,简历和个人介绍都提到了精通 Java 多线程,于是我就问了几个多线程方面的问题:
实现多线程有哪几种方式,如何返回结果?
多个线程如何实现顺序访问?
两个线程如何进行数据交换?
如何统计 N 个线程的运行总耗时?
如何将任务拆分成多个子任务执行,最后合并结果?
大概问了他这几个问题,答的并不是太好,3、4、5 题都没有真正答上来,其实这几个问题在 JDK 包中都有答案,但他给的是他个人临时思考的方案,而且我个人觉得可能行不通。
工作 5 年了,这几个题都答不好,有点说不过去,我真是醉了。。
实现多线程有哪几种方式,如何返回结果?
继承Thread类
看jdk源码可以发现,Thread类其实是实现了Runnable接口的一个实例,继承Thread类后需要重写run方法并通过start方法启动线程。
继承Thread类耦合性太强了,因为java只能单继承,所以不利于扩展。
实现Runnable接口
通过实现Runnable接口并重写run方法,并把Runnable实例传给Thread对象`,Thread的st ...
Spring-Retry 循环重试框架
简介在日常的一些场景中,很多需要进行重试的操作。而spring-retry是spring提供的一个基于spring的重试框架,非常简单好用。
Spring应用导入maven坐标<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId></dependency>
调用类@Slf4jpublic class RetryDemo { public static boolean retryMethod(Integer param) { int i = new Random().nextInt(param); log.info("随机生成的数:{}", i); if (1 == i) { log.info("为1,返回true." ...
Java线程池ThreadPoolExecutor类使用详解
在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。
下面我们就对ThreadPoolExecutor的使用方法进行一个详细的概述。
首先看下ThreadPoolExecutor的构造函数
public ThreadPoolExecutor(int corePoolSize, ...
优惠券系统设计思想
场景电商大厂常见促销手段:
优惠券
拼团
砍价
老带新
优惠券的种类
满减券
直减券
折扣券
优惠券系统的核心流程发券
发券的方式:同步发送 or 异步发送
领券
谁能领?
所有用户 or 指定的用户
领取上限
一个优惠券最多能领取多少张?
领取方式
用户主动领取 or 自动发放被动领取
用券
作用范围
商品、商户、类目
计算方式
是否互斥、是否达到门槛等
需求拆解商家侧
创建优惠券
发送优惠券
用户侧
领取优惠券
下单
使用优惠券
支付
服务服务结构设计
优惠券系统设计技术难点
券的分布式事务,使用券的过程会出现的分布式问题分析?
如何防止超发?
如何大批量给用户发券?
如何限制券的使用条件?
如何防止用户重复领券?
存储表单设计券批次(券模板)指一批优惠券的抽象、模板,包含优惠券的大部分属性。
如商家创建了一批优惠券,共1000张,使用时间为2022-11-11 00:00:00 ~ 2022-11-11 23:59:59,规定只有数码类目商品才能使用,满100减50。
券发放到用户的一个实体,已与用户绑定。
...
如何优雅的自定义 ThreadPoolExecutor 线程池
概述java 中经常需要用到多线程来处理一些业务,非常不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的线程也可能引发资源耗尽的风险,这个时候引入线程池比较合理,方便线程任务的管理。
java中涉及到线程池的相关类均在 jdk 1.5 开始的java.util.concurrent包中,涉及到的几个核心类及接口包括:Executor、Executors、ExecutorService、ThreadPoolExecutor、FutureTask、Callable、Runnable等。
JDK 自动创建线程池的几种方式都封装在Executors工具类中:
newFixedThreadPool
使用的构造方式为
new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())
设置了corePoolSize=maxPoolSize,keepAliveTime=0(此时该参数没作用 ...
通用Service + 多线程完美解决批处理问题
前言在对数据量大的情况下,进行批量操作的时候,效率直接拉跨,同时还要考虑事务机制问题。那是否有既简单又通用的批处理思路呢?当然,多线程执行批量任务就是一种十分重要的操作思路
步骤
获取数据库连接,控制事务机制
对大集合进行拆分成N个小集合。
开启线程池,对小集合进行批量更新操作,并返回执行结果。
线程批量提交,返回Future对象,进而判断事务是否需要提交或回滚
实战Servicepackage cn.goitman.service;import com.google.common.collect.Lists;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.sql.Connection;import java ...
SpringBoot同时支持 form 表单、form-data、json 的优雅写法
在 Java 中,一个接口只支持一种 content-type,json 就用 @RequestBody,form 表单就用 @RequestParam 或不写,form-data 就用 MultipartFile。
兼容版本如果要把在一个接口中同时兼容三种,比较笨的办法就是获取 HttpServletRequest,然后自己再写方法解析。类似如下:
private Map<String, Object> getParams(HttpServletRequest request) { String contentType = request.getContentType(); if (contentType.contains("application/json")) { // json 解析... return null; } else if (contentType.contains("application/x-www-form-urlencoded")) ...
一键部署Redis任意版本
今天给大家分享一个超级实用的脚本,Linux环境下一键自动安装部署Redis的任意版本,记住是任意版本哦!
脚本用法:chmod 755 redis-install.sh && sh redis-install.sh 4.0.10 (后面跟的是你需要的版本号,需要什么版本就写什么版本),我这里安装的4.0.10
执行脚本#! /usr/bin/bash##redis任何版本全程自动化源码编译安装##用法: sh redis-install.sh 4.0.10 (后面跟的是你需要的版本号,需要什么版本就写什么版本),我这里安装的4.0.10version=$1usage(){echo "usage: $0 version"}if [ $# -ne 1 ]thenusageexit -1fi#Redis安装包下载cd /usr/local/srcif [ ! -f redis-${version}.tar.gz ]thencurl -o /usr/local/src/redis-${version ...
Redis分布式锁的8大坑
在分布式系统中,由于Redis分布式锁相对于更简单和高效,成为了分布式锁的首先,被用到了很多实际业务场景当中。
但不是说用了Redis分布式锁,就可以高枕无忧了,如果没有用好或者用对,也会引来一些意想不到的问题。
今天一起聊聊Redis分布式锁的一些坑,给有需要的朋友一个参考。
非原子操作使用Redis的分布式锁,首先想到的可能是setNx命令。
if (jedis.setnx(lockKey, val) == 1) { jedis.expire(lockKey, timeout);}
容易,三下五除二就可以把代码写好。
这段代码确实可以加锁成功,但有没有发现什么问题?
加锁操作和后面的设置超时时间是分开的,并非原子操作。
假如加锁成功,但是设置超时时间失败了,该lockKey就变成永不失效。假如在高并发场景中,有大量的lockKey加锁成功了,但不会失效,有可能直接导致redis内存空间不足。
那么,有没有保证原子性的加锁命令呢?
答案是:有,请看下面。
忘了释放锁上面说到使用setNx命令加锁操作和设置超时时间是分开的,并非原子操作。
而在Redis ...