Remember once that Apache code caused a production problem

Time:2020-10-14

introduction

Two dogs: Er Pang, wake up and look at the alarm e-mail just now. The time taken for saving the user interface you wrote last time (ER Pang’s rough road to parameter verification) has greatly increased. Please find out the reason.
Two fatOK, look right away. I’m full of inner drama (I’m complaining. I’m dreaming of getting rich at noon. I was woken up just after I dreamed that the stock I bought was trading again). Complaints belong to complaints, their own problems still have to see ah, after all, they are written by themselvesbugWe need to fix it with tears. Er Pang is good at analyzing this kind of problem. After all, he is a veteran of the workplace.

Test environment replication problem

Second fat first through the internal monitoring tools to see whether the network is normal in this period of time, andcpuThe use ofdatabaseThese indicators seem to be normal. The only difference is that the traffic has increased a little during this period. It must be that the company has spent money on marketing and advertising. Then Er Pang analyzed several requests through cat (public comments open source monitoring tool), and the time spent in each stage was as followsok。 If the production environment is too simple to solve, it will be difficult to solve the problem. Isn’t the flow of production going up a bit? The test environment to pressure test it, two fat decisively downloaded onejmeter(pressure testing tool) carried out a crazy pressure test in the test environment, and the same problems as production appeared. It’s good to be able to reproduce the problem, which is a big step closer to solving the problem.

Arthas location problem

The problem is that it is repeated. The next step is to find out the time-consuming parts of the interface. Generally, when we find the interface that takes a long time, we always record the time consumption of each step of log printing. This is a common practice, but Er Pang remembers that he shared a artifact with “Er Gou”, the technical champion of the Department last timearthasTime consumption on each node on the method path can be output. Because I have no chance to use it for practical operation, today I can finally take it to practice. Installation of what will not be introduced, this official website is written in more detail, and the document is also in Chinese, very easy to start. Let’s use it nowarthasYeah.
Successfully launched interface
Remember once that Apache code caused a production problem
Now let’s base onarthasProvidedtraceCommand to see where the interface takes time.
Remember once that Apache code caused a production problemWe can see from the above that the main time consumption is concentrated inorg.apache.commons.beanutils.BeanUtils#copyPropertiesIn this method, is not the property assignment conversion between an entity? Does it take so long? It’s not scientific,apacheThe method offered is still the samelowIs that right? With these questions in mind, let’s look at the efficiency of other tool classes that provide property copy.

Performance comparison of common attribute assignment using jmh

  • usegetsetMethod copy.
  • cglibOfBeanCopier
  • SpringOfBeanUtils
  • apacheOfBeanUtils
  • MapStruct

Let’s compare the performance of the above operations.
Write the following test class.

/**
 * @author:
 * @Date: 2020/7/11
 * @Description:
 */
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 5, time = 5)
@Threads(6)
@Fork(1)
@State(value = Scope.Benchmark)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class BeanCopyTest {
    @Param(value = {"1","10","100"})
    private int count;

    public UserBO bo;

    public  BeanCopier copier;

    @Setup( Level.Trial )// the initialization method is performed before all benchmarks are run
    public void init() {
        copier = BeanCopier.create(UserBO.class, UserVO.class, false);
        bo = new UserBO();
        bo.setUserName ("Java finance");
        bo.setAge(1);
        bo.setIdCard("88888888");
        bo.setEmail (Java [email protected] qq.com "";
    }


    public static void main(String[] args) throws RunnerException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
       Options opt = new OptionsBuilder().include(BeanCopyTest.class.getSimpleName()).result("result.json").resultFormat(ResultFormatType.JSON).build();
        new Runner(opt).run();

    }

    /**
     *Use mapstruct to operate
     */
    @Benchmark
    public void mapStruct() {
        for (int i = 1; i <= count; i++) {
            UserVO vo = UserMapping.INSTANCE.converter(bo);
        }
    }

    /**
     *Manual set and get
     */
    @Benchmark
    public void setAndGet() {
        for (int i = 1; i <= count; i++) {
            UserVO userVO = new UserVO();
            userVO.setUserName(bo.getUserName());
            userVO.setEmail(bo.getEmail());
            userVO.setSex(bo.getSex());
            userVO.setIdCard(bo.getIdCard());
            userVO.setAge(bo.getAge());
        }
    }

    /**
     *Copy method using cglib
     */
    @Benchmark
    public void cglibBeanCopier() {
        for (int i = 1; i <= count; i++) {
            UserVO vo = new UserVO();
            copier.copy(bo, vo, null);
        }
    }

    /**
     *Use the copyproperties method provided by spring
     */
    @Benchmark
    public void springBeanUtils() {
        for (int i = 1; i <= count; i++) {
            UserVO vo = new UserVO();
            BeanUtils.copyProperties(bo, vo);
        }
    }

    /**
     *Using Apache's copyproperties method
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    @Benchmark
    public void apacheBeanUtils() throws InvocationTargetException, IllegalAccessException {
        for (int i = 1; i <= count; i++) {
            UserVO vo = new UserVO();
            org.apache.commons.beanutils.BeanUtils.copyProperties(vo, bo);
        }
    }

The final test results are as follows:

Benchmark                     (count)  Mode  Cnt          Score          Error  Units
BeanCopyTest.apacheBeanUtils        1  avgt    5    2462103.419 ±  2292830.495  ns/op
BeanCopyTest.apacheBeanUtils       10  avgt    5   21025926.689 ± 11254755.603  ns/op
BeanCopyTest.apacheBeanUtils      100  avgt    5  193235312.113 ± 37929707.246  ns/op
BeanCopyTest.cglibBeanCopier        1  avgt    5          4.936 ±        1.187  ns/op
BeanCopyTest.cglibBeanCopier       10  avgt    5          4.820 ±        1.963  ns/op
BeanCopyTest.cglibBeanCopier      100  avgt    5          4.269 ±        0.890  ns/op
BeanCopyTest.mapStruct              1  avgt    5          4.809 ±        1.720  ns/op
BeanCopyTest.mapStruct             10  avgt    5          4.947 ±        1.320  ns/op
BeanCopyTest.mapStruct            100  avgt    5          4.440 ±        1.191  ns/op
BeanCopyTest.setAndGet              1  avgt    5          3.780 ±        1.785  ns/op
BeanCopyTest.setAndGet             10  avgt    5          3.930 ±        1.788  ns/op
BeanCopyTest.setAndGet            100  avgt    5          4.069 ±        2.181  ns/op
BeanCopyTest.springBeanUtils        1  avgt    5       1190.563 ±      165.574  ns/op
BeanCopyTest.springBeanUtils       10  avgt    5      10887.244 ±     1228.026  ns/op
BeanCopyTest.springBeanUtils      100  avgt    5     109686.562 ±     7485.261  ns/op

Remember once that Apache code caused a production problem

  • From the above conclusion, we can find that the best performance is rankinggetsetMethod replication, followed bymapStructandBean copier of cglibAnd then there isSpring's BeanUtilsAnd finallyBeanUtils of Apache
  • If you are interested in the above test performance, the code has been uploaded togithubYou can download and compare the results. Code address
  • About rightJMHThe use of will not be introduced, interested in Google. However, if you want to compare the performance, I really recommend using it. The results can be exportedjsonThe file then generates the chart.

Why apachebeanutils has the worst performance

apacheBeanUtilsandspringOfbeanUtilsThe bottom layer uses reflection to assign values. WhyapacheBeanUtilsThe performance of the system is much worse.There is no secret under the source codeLet’s take a look at the source code of this method.
Remember once that Apache code caused a production problem
Apache BeanUtilsA large number of logs are printed, as well as a variety of conversion, type judgment and so on, resulting in poor performance.

  • andspringOfbeanUtilDirect use of reflection Province, clean and neat, the core code is shown in the figure below.

Remember once that Apache code caused a production problem

  • In factAlibaba Development Manual(in the official account.Java Finance】Reply“Mount Tai”There are also properties in thecopyAvoid useapcheBeanUtils

Remember once that Apache code caused a production problem

  • If the production environment is already in useApache BeanUtilsIt needs to be replacedspring BeanUtilsYou need to pay attention to the two of them, although the methods provided are bothcopyPropertiesHowever, their parameters are opposite. It needs to be noted that the package name should not be changed directly.

summary

  • In actual use, it will not be usedgetandsetMethod copy, easy to miss attributes, and is also a physical work. RecommendedmapStructDuring the compilation process,MapStructThe implementation of the interface will be generated, and it can also implement the mapping of different names, such asnameMap tousernameHigh flexibility.
  • Er Pang feels that today’s harvest is full. I learned a littlejmeterarthasJMHThe use of three software.

end

  • As a result of their own shallow talent, there will inevitably be mistakes, if you find the wrong place, also hope to leave a message to me, I will correct it.
  • If you think the article is not bad, your forwarding, sharing, appreciating, liking, leaving a message is the biggest encouragement to me.
  • Thank you for your reading. Welcome and thank you for your attention.

Remember once that Apache code caused a production problem