Java spike high concurrency optimization

High concurrency optimization analysis

  1. High concurrency occurs where the
    red areas are highly concurrent occurrence of point
    Here Insert Picture Description

  2. Why should we get the system time alone
    because his detail page and static resources on the CDN, so when access is no longer requests that our server, it can not get the system time, so there must be an interface to return the system time
    Here Insert Picture Description
    What is CDN
    Here Insert Picture Description

  3. Get address of the interface spike analyzing
    the CDN can not use, because the CDN corresponding resource is not changed, acquires spike which returns data interface (start time, end time) change

He cache used for services such as redis
Here Insert Picture Description

  1. Spike operation optimization analysis
    ① can not use the CDN
    ② backside cache difficulty: inventory problems, to use Mysql ensure transaction
    ③ row of data competition: hot commodity operations

Why not deal with Mysql
as Mysql ineffective, inefficient Here's why java client performs these operations when communication and database have network latency and GC, and update threads of different users of these operations is performed serially, will wait

Here Insert Picture Description
Here Insert Picture Description

Row-level locking is not released in the commit or rollback, we have optimized row-level locking is to reduce hold time, which means you can put logic on the client MySql server, network latency and avoid affecting GC

Here Insert Picture Description

Concurrent Optimization

Here Insert Picture Description
Here you can change the order of insert and update, to achieve the purpose of row-level locking hold time is short (insert and update still composed of two transactions, if the update will be unsuccessful rollback)

 @Override
    @Transactional
    public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5) throws SeckillException, RepeatKillException, SeckillCloseException {
        if(md5 == null || !md5.equals(getMD5(seckillId))){
            throw new SeckillException("seckill data rewrite");
        }
        //执行秒杀逻辑:减库存+记录购买记录
        Date nowTime = new Date();
        try {
            int insertCount = successKilledDao.insertSuccessKilled(seckillId,userPhone);
            //userPhone和seckillId作为联合主键避免重复秒杀
            if(insertCount<=0){
                throw new RepeatKillException("seckill repeated");
            }else {
                //减库存
                int updateCount = seckillDao.reduceNumber(seckillId,nowTime);
                if(updateCount <= 0){//没有更新到记录则秒杀结束
                    throw new SeckillCloseException("seckill is closed");
                }else {//秒杀成功
                    SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);
                    return new SeckillExecution(seckillId, SeckillStaEnum.SUCCESS,successKilled);
                }
            }
            
        }catch (SeckillCloseException e1){
            throw e1;
        } catch (RepeatKillException e2){
            throw e2;
        }catch (Exception e){
            logger.error(e.getMessage(),e);
            throw new SeckillException("seckill inner error:"+e.getMessage());
        }
    }

redis backside cache optimization

Because to get frequent access back-end spike expose interfaces, you can put him up redis cache

  1. Introducing java client access redis
<!--    redis客户端:jedis-->
      <dependency>
          <groupId>redis.clients</groupId>
          <artifactId>jedis</artifactId>
          <version>2.7.3</version>
      </dependency>
  1. Cache control should not be placed in the service layer, and the layer should be placed dao, dao data access object is to put the packet and other data stored in database access

  2. We want ① object access a cached by redis, ② no cache when put inside a

  3. We want to achieve serialized because redis does not implement internal sequence of operations, read out from the inside redis binary array, we want to transform an object by deserializing
    for serialization, the direct implements Serializable, but this is high concurrency optimization, more efficient use of protostuff using custom serialization

  4. Introducing the corresponding dependent

<!--prostuff序列化依赖-->
      <dependency>
          <groupId>com.dyuproject.protostuff</groupId>
          <artifactId>protostuff-core</artifactId>
          <version>1.0.8</version>
      </dependency>
      <dependency>
          <groupId>com.dyuproject.protostuff</groupId>
          <artifactId>protostuff-runtime</artifactId>
          <version>1.0.8</version>
      </dependency>
  1. Is taken from the byte array fetch redis, the deserialized into objects java

  2. The target sequence is put into a java byte [] array, into

package org.seckill.dao.cache;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import org.seckill.entity.Seckill;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.concurrent.ExecutionException;

public class RedisDao {
    private final JedisPool jedisPool;

    public RedisDao(String ip, int port){
        jedisPool = new JedisPool(ip,port);
    }

    private RuntimeSchema<Seckill> schema = RuntimeSchema.createFrom(Seckill.class);

    public Seckill getSeckill(long seckillId){
        try{
            Jedis jedis = jedisPool.getResource();
            try{
                String key = "sckill:"+seckillId;
                //并没有实现哪部序列化操作
                //采用自定义序列化
                //protostuff: pojo.
                byte[] bytes =jedis.get(key.getBytes());
                //获取到
                if(bytes!=null){
                    //反序列化
                    Seckill seckill = schema.newMessage();
                    ProtostuffIOUtil.mergeFrom(bytes,seckill,schema);
                    return seckill;
                }
            }finally {
                jedis.close();
            }
        }catch (Exception e){

        }
        return null;
    }

    public String putSeckill(Seckill seckill){
        try{
            Jedis jedis = jedisPool.getResource();
            try{
                String key = "seckill:"+seckill.getSeckillId();
                byte[] bytes = ProtostuffIOUtil.toByteArray(seckill,schema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
                //超时缓存
                int timeout = 60*60;//1小时
                String result = jedis.setex(key.getBytes(),timeout,bytes);
                return result;
            }finally {
                jedis.close();
            }
        }catch(Exception e){

        }
        return null;
    }

}

  1. injection
<!--redisDao-->
    <bean id="redisDao" class="org.seckill.dao.cache.RedisDao">
        <constructor-arg index="0" value="localhost"/>
        <constructor-arg index="1" value="6379"/>
    </bean>
  1. service use
@Override
    public Exposer exportSeckillUrl(long seckillId) {
        Seckill seckill = redisDao.getSeckill(seckillId);
        if(seckill == null){
            seckill = seckillDao.queryById(seckillId);
            if(seckill == null){
                return new Exposer(false,seckillId);
            }else {
                redisDao.putSeckill(seckill);
            }
        }
        if(seckill == null){//差不到秒杀记录
            return new Exposer(false,seckillId);
        }
        Date startTime = seckill.getStartTime();//秒杀开始时间
        Date endTime = seckill.getEndTime();//结束时间
        Date nowTime = new Date();//系统当前时间
        //判断在不在秒杀时间
        if(nowTime.getTime() < startTime.getTime() || nowTime.getTime() > endTime.getTime()){
            //不在
            return new Exposer(false,seckillId,nowTime.getTime(),startTime.getTime(), endTime.getTime());
        }
        //秒杀开始
        String md5 = getMD5(seckillId);//加密,转化特定的字符串,不可逆
        return new Exposer(true,md5,seckillId);
    }

SQL transactions executed at the end MySql

Stored Procedures optimization Transaction row-level locking hold time

Published 62 original articles · won praise 0 · Views 1162

Guess you like

Origin blog.csdn.net/weixin_43907800/article/details/104011816