提升项目TPS优化手段

背景:项目要求单接口TPS为1w,为了达到这个目标,需要尽量减少请求的响应时间。

1. 合理利用缓存

如果处理每次请求,都需要和数据库进行交互,那么必然会很耗时:

耗时主要发生在:

  1. 与数据库建立连接;
  2. 数据库查询数据;
  3. 数据的网络传输。

而实际上,很多数据都是偏向于读,而非写。即,每次都去数据库拉取数据的操作,实际上是不必须的。我们要做的,只是把数据缓存下来,下次用的时候,直接读取缓存就可以了,从而避免了重复与DB交互。

常用的缓存,分为公共缓存和本地缓存:

  1. 如果key分布均匀的话,可以考虑使用公共缓存,常用的是Redis;
  2. 如果key分布不均匀的话,则需要考虑使用本地缓存了,当然在设计时,要考虑机器的内存。

2. 扩容、增加机器的性能

扩容、或者增加机器的性能,是提高接口TPS最直接的方式。
比如,原本只有1台机器处理来的请求,现在把机器扩到8台,则理想情况下:

扩容前:TPS = 100
扩容后:TPS = 8 x 100

当然,这是理想情况,实际上请求需要经过ngx进行分流,中间按理是有损耗。

当然,这样非常考验ngx分发的能力,ngx也有可能会成为性能瓶颈!

3. 精简接口处理逻辑

如果,一个接口对性能的要求特别高,那么对于那些不必实时处理的逻辑,可以事前先处理好,放在缓存中,需要的时候,直接去取就可以了。

  1. 简化校验:比如参数的校验,只要非空,不校验合法(reason:业务会校验);
  2. 非必要的操作:不保留;
  3. 非实时的操作:提前处理。

4. 集合的类型与循环

  1. 集合优先选择:ArrayList
	ArrayList<Integer> l1 = new ArrayList<>();
  1. 集合的循环方式
	// 推荐
	for (int i = 0; i < l1.size(); i++) {
	
	}
	// 不推荐
    for (Integer integer : l1) {

    }
  1. 集合中元素需要移除

不建议新建一个集合,然后将合法的元素进行赋值,当然,是否也需要考虑对应的场景呢?

	Iterator<Integer> iterator1 = l1.iterator();
    while (iterator1.hasNext()) {
        Integer next = iterator1.next();
        // 移除条件
        if (next.equals(1)) {
            iterator1.remove();
        }
    }

5. 其他操作

5.1. 定时任务

java自带的线程池其实已经有对应的方法了

      logger.info("启动定时任务,查询正在进行的实验,每10秒执行一次,即配置信息最长十秒后生效!");
      Long waitTime = 10 * 1000L;
   	  int availableProcessor = Runtime.getRuntime().availableProcessors();
   	  // 任务执行完成,休眠10s重新执行对应的方法
      ScheduledExecutorService service = Executors.newScheduledThreadPool(availableProcessor);
      service.scheduleWithFixedDelay(new Runnable() {
          @Override
          public void run() {
              process();
          }
      },0,waitTime,TimeUnit.MILLISECONDS);

反面教材:

	while (true) {
        try {
        	// 要执行的业务
        	.....
        	// 执行完,休眠10s
            Thread.sleep(waitTime);
        } catch (Exception e) {
            logger.error("定时任务失败", e);
        }
    }

5.2. 根据名称取对象的值

根据性能看,第三种借助反射的效率最高。

    /**
     * 执行:10000 x 200 耗时:10711
     * 根据属性,获取get方法
     * @param ob 对象
     * @param name 属性名
     * @return
     * @throws Exception
     */
    public static Object getGetMethod(Object ob , String name)throws Exception{
        Method[] m = ob.getClass().getMethods();
        for(int i = 0;i < m.length;i++){
            if(("get"+name).toLowerCase().equals(m[i].getName().toLowerCase())){
                return m[i].invoke(ob);
            }
        }
        return null;
    }

    /**
     * 执行 10000 x 200 耗时:5015
     * @param ob
     * @param name
     * @return
     */
    public static Object getGetMethod2(Object ob , String name) {
        try{
            // 获取字段
            Field field = ob.getClass().getDeclaredField(name);
            PropertyDescriptor pd = new PropertyDescriptor(field.getName(), ob.getClass());
            // 获取get方法
            Method method = pd.getReadMethod();
            return ReflectionUtils.invokeMethod(method, ob);
        } catch (Exception e){
            System.out.println("error");
        }
        return null;
    }

    /**
     * 执行 10000 x 200 耗时 38ms
     * @param object
     * @return
     */
    public static Map<String, Object> getFieldNameAndValue(Object object) {
        Map<String, Object> map = new HashMap<>();
        Class clazz = object.getClass();
        ArrayList<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(object));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

你可能感兴趣的:(java,数据库,java,缓存,jvm)