java高并发高可用高性能介绍(JAVA高并发秒杀系统构建之高并发优化分析)
java高并发高可用高性能介绍(JAVA高并发秒杀系统构建之高并发优化分析)接下来,通过redis获得缓存中的Seckill对象,以及一些protostuff的反序列化操作?这里生成protostuff的一个schem 其原理是将Seckill.class的字符码传过去,然后利用反射的原理,获得Seckill中的属性值等。?那一个事务具体要干什么东西呢?或者说高并发的瓶颈在哪里,看下图?这里需要声明一下,如果从redis中获得数据,是获得byte的数组,而不是具体的类,因为redis无法帮你反序列化,因此,反序列化的操作应该由你自己完成。因为java内置的序列化接口Serializable,效率没有protostuff自定义序列化高,protostuff的反序列化效率比Serializable高了很多倍,而且压缩后的空间比Serializable小了10倍左右,因此,使用protostuff进行自定义反序列化操作。
JAVA高并发秒杀系统构建之高并发优化分析
前言:本文章是《JAVA高并发秒杀系统构建之——业务分析和Web层》下一篇,主要讲解系统高并发优化分析
先来分析一下java 控制事务行为
如下图可知,java事务是串联发生的,即当一个事务还没有执行完,其他事务都是要等待而被阻塞。?
那一个事务具体要干什么东西呢?或者说高并发的瓶颈在哪里,看下图?
这里需要声明一下,如果从redis中获得数据,是获得byte的数组,而不是具体的类,因为redis无法帮你反序列化,因此,反序列化的操作应该由你自己完成。
因为java内置的序列化接口Serializable,效率没有protostuff自定义序列化高,protostuff的反序列化效率比Serializable高了很多倍,而且压缩后的空间比Serializable小了10倍左右,因此,使用protostuff进行自定义反序列化操作。
这里生成protostuff的一个schem 其原理是将Seckill.class的字符码传过去,然后利用反射的原理,获得Seckill中的属性值等。?
接下来,通过redis获得缓存中的Seckill对象,以及一些protostuff的反序列化操作?
接下来是将Seckill对象放进redis缓存中,这里同样利用protostuff来序列化Seckill,LinkedfBuffer为缓冲器,保证在大型类序列化时能够起到缓冲的作用,timeout设置缓存时间,这里设置一小时之后redis中的Seckill数据就会消失。result为redis返回的结果,可以依据此判断缓存是否成功。?
这两个方法写好后,我们回到SeckillServiceImpl中,将之前Seckill直接从数据库中获取的流程,改成先判断redis里面有没有Seckill缓存,如果有,直接从redis中获取,如果没有,从数据库中取出Seckill,将其放入redis中。这里运用在超时的基础上维护redis数据的一致性,是最基础的维护一致性的方式。?
以上就是通过redis来缓存信息,下面我们来看执行秒杀操作时的并发优化
上面我们总结过,行级锁的主要发生地,主要是库存update操作这里,之前的业务逻辑如下图?
由下图可知,无论这个商品是否可以被秒杀,都会执行update语句,获得行级锁,再返回是否update成功的结果,并通过这个update操作结果,来插入购买明细,这是非常错误的。?
我们知道,insert操作也可以判断是否插入成功(返回值0代表失败,1代表成功),但是,insert操作是不用通过行级锁来阻塞其他事务的,因此,我们可以将update语句和insert语句调换位置(先过滤不符合update操作条件的事务,即挡住一部分重复秒杀),通过insert语句的结果,来判断是否需要update操作,这样,阻塞时间将会大大减少,增加了系统的性能。?
下图是调换位置后的事务执行?
下面来看看具体代码的修改?
接下来是深度优化,即将事务SQL在Mysql端进行(存储过程),减少网络延迟和GC带来的时间消耗
下面将插入购买明细和更新库存操作,放在存储过程里面执行?
这里简单说明一下存储过程:?
1.存储过程主要优化事务行级锁持有时间?
2.不要过度依赖存储过程?
3.简单的逻辑可以应用存储过程?
4.一秒可以接受4000个请求,这是基本足够的。
下面说说在java客户端是如何调用存储过程的
在SeckillDao中,使用存储过程执行秒杀?
然后在seckillDao.xml中实现它?
在SeckillService接口中定义一个方法,作为利用存储过程来实现事务的方法,其参数和executeSeckill方法一样?
然后编写其实现类?
以上,就是高并发优化分析的全部内容了。