本帖最后由 孤尽 于 2020-3-26 14:28 编辑
关于Java并发的一些解决方案
前言:面试中,很多小伙伴会被问到一个问题,你们项目的并发有多少呢?对于高并发,你有什么解决方案?一般遇到这样的问题,可能很多小伙伴就比较迷茫了,因为我们做的项目中很多可能没有接触过并发,或者并发很小,没有解决过相关的问题,对这一块是个空白,被问到这种问题时就懵了,对于面试很不好。
1.缓存
对于JavaWeb系统而言,大部分的数据都需要持久化到数据库中,我们知道数据库的抗压能力是十分有限的,基本mysql单机每秒能承受2000的并发已经是极限了,所以在高并发的场景下,首先要解决的就是DB的问题,对于查询比较多的高并发来说,使用缓存是一种非常好的解决方案。
目前市场上常用的缓存基本都是以redis为主,以前会有使用Mamcached的,现在基本没有了,Redis作为优秀的内存型数据库,官网数据单机每秒可以承受10万的并发,并且支持主从备份和集群模式,可以无限横向扩容。 使用redis的架构之后,我们使用数据,就不仅仅是单从数据库中获取,当我们请求数据的时候,先去缓存中查询数据是否存在,如果存在即直接返回,如果不存在,则去数据库查询,查询到之后存储到缓存中,然后下次访问的时候可以直接从缓存中读取数据
Redis是C语言开发的高性能的内存型数据库,可以用作数据库,缓存,消息中间件等,是一种NOSQL数据库。 - 性能优秀,数据在内存中,读写速度非常快,支持并发10WQPS
- 单进程单线程,是线程安全的,采用IO多路复用机制
- 丰富的数据类型:支持String,Hash,List,Set,Zset
- 支持数据持久化,可以将内存数据存储到硬盘上,启动时加载
- 支持复制,哨兵,高可用
- 可以作为分布式锁
- 可以作为消息中间件使用,支持发布订阅
2.异步
在高并发的场景下,对于时效性要求不太高的业务,可以采用异步的方式来完成,比如mq,线程池。
简单说一下线程池的底层工作原理:
线程池可以通过Executor.newFixedThreadPool(3)来创建,其中参数中的数字为核心线程数量,也就是corePoolSize,首先当我们在线程池中执行任务的时候,他会检查当前线程池中的数量是否小于corePoolSize,因为线程池刚创建,肯定为true,所以首先会在线程池中创建线程来执行任务,当任务执行完之后,不会销毁线程,而是阻塞在线程池的队列中,等待新的任务,第二次执行任务时,也会检查线程池中的线程数量是否小于corePoolSize,小于的话,先创建线程在执行任务,执行完之后继续阻塞在队列等待任务,直到线程池中线程数等于corePoolSize,新的任务才会放到队列中,等待线程池中的线程来执行, 对于FixedThreadPool而言,使用的是LinkedBlockingQueue,无界阻塞队列,队列没有大小。
3.页面静态化
有一些数据基本不会变动的页面,如果每次刷新都重复加载数据,对后端压力过大,所以例如商品详情页之类的页面,我们可以做成静态页面,使用nginx之类的静态服务器去代理,效率非常之高
总结:对于这类问题,小伙伴们可以依照自己项目的一个情况,合理预估一个最大的并发QPS,假如项目真的刚完成,没有多少人使用,可以把目前的并发扩大10倍对面试官来讲,切记不要太过,举个例子,一般的项目,能有个几百上千的并发就已经很厉害了,小伙伴们切勿随随便便张口就二三百万并发噢,恐怕只有国内一线大厂能达到这个数字
|