zoukankan      html  css  js  c++  java
  • 网络性能优化

    高并发网络编程的性能测试一直是个非常难的问题
    困难点:
    1 纯网络性能测试会把业务逻辑最小化,需要一定的改造。
    2测试虚要给服务器足够的压力,这样对于测试用的客户端的QPS就有较高的要求
    解决方案,
    1 将业务逻辑跟网络框架拆分
    2 我们可以开启多个实例
     
    我们用来测试的代码库就是https://www.cnblogs.com/nerdlerss/p/9035928.html
    中的库,在这个库中,我们把业务逻辑跟网络框架进行了拆分

    我们的业务代码就是

    counter = 0   
    if __name__ == '__main__':
                  
        def logic(d_in):
            global counter
            counter += 1
            if counter %100000 ==0:   
                print counter,time.time()
            return(d_in[::-1])
        reverseD = nbNet('0.0.0.0', 9099, logic)
        reverseD.run()
    

      说白了就是 每响应10w下答应一下时间

    我们测试端代码

    #!/usr/bin/env python
    
    import socket, sys, os
    
    HOST = '127.0.0.1'
    PORT = 9099
    CNT = int(sys.argv[2])
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    
    cmd = sys.argv[1]
    data = "%010d%s"%(len(cmd), cmd)
    while True:
        s.send(data * CNT)
        s.recv(len(data) * CNT)
    

    但是我们的客户端是不可能打到server端的性能瓶颈的,我们可以开启多个终端,启动多个实例,这样达到我们性能要求

    我们首先看下没有优化之前的性能

    我们虚拟机的性能是:一核心CPU没有超线程 2.5G 内存2G

    我们从300w次请求之后选取后面100w次的时间

    3000000 1527159028.98

    3100000 1527159031.62

    3200000 1527159034.16

    3300000 1527159036.72

    3400000 1527159039.27

    3500000 1527159041.82

    3600000 1527159044.38

    3700000 1527159047.01

    3800000 1527159049.56

    3900000 1527159052.12

    4000000 1527159054.69

     

    我们计算下每10w次请求的时间(取小数点后两位)

    [0] 2.63s

    [1]  2.54s 

    [2] 2.56s 

    [3] 2.55s

    [4] 2.56s

    [5]2.62s

    [6] 2.55s

    [7] 2.56s

    [8] 2.57s

    [9]2.56s

    最差 2.63s  QPS 约等于 38022

    最好 2.54s QPS 约等于 39370

    ==============================================================

    在python内建了一个 profiler工具,可以帮我们定位性能瓶颈

     服务端调用方法

      python -m cProfile -s cumulative nbNetFramework.py
      -s cumulative 的意思是按照系统调用的总体耗时排序
    

     客户端调用方法

      python loadrun.py a 100

      python loadrun.py a 100
    

     执行一段时间后 结束server的时候会输出这段时间代码中的方法执行时间情况

    root@work:/home/rico/python/rebootMon/nbNet# python  -mcProfile -s cumulative  nbNetFramework.py
    100000 1527160075.61
    200000 1527160079.19
    300000 1527160082.8
    ^C         11986059 function calls (11985241 primitive calls) in 14.675 seconds
    
       Ordered by: cumulative time
    
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
            1    0.001    0.001   14.675   14.675 nbNetFramework.py:4(<module>)
            1    1.693    1.693   14.654   14.654 nbNetFramework.py:166(run)
      1088050    0.615    0.000   10.292    0.000 nbNetFramework.py:192(state_machine)
       725366    0.622    0.000    5.588    0.000 nbNetFramework.py:271(read2process)
       362683    0.670    0.000    4.089    0.000 nbNetFramework.py:307(write2read)
       725366    1.722    0.000    2.981    0.000 nbNetFramework.py:66(read)
      1088050    2.669    0.000    2.669    0.000 {method 'poll' of 'select.epoll' objects}
       362683    1.209    0.000    1.985    0.000 nbNetFramework.py:232(process)
       362683    0.605    0.000    1.691    0.000 nbNetFramework.py:124(write)
       362685    0.719    0.000    1.382    0.000 nbNetFramework.py:21(setFd)
       725366    1.070    0.000    1.070    0.000 {method 'recv' of '_socket.socket' objects}
       362683    0.894    0.000    0.894    0.000 {method 'send' of '_socket.socket' objects}
       725365    0.740    0.000    0.740    0.000 {method 'modify' of 'select.epoll' objects}
       362692    0.303    0.000    0.423    0.000 socket.py:227(meth)
       362683    0.320    0.000    0.320    0.000 nbNetFramework.py:339(logic)
    2905468/2905319    0.250    0.000    0.250    0.000 {len}
       362685    0.240    0.000    0.240    0.000 nbNetUtils.py:164(__init__)
       363892    0.192    0.000    0.192    0.000 {isinstance}
       362725    0.067    0.000    0.067    0.000 {getattr}
       362688    0.053    0.000    0.053    0.000 {method 'fileno' of '_socket.socket' objects
    
    ncalls -- 调用多少次
    #自己调用的时间,不包括其他十年
    tottime 调用时耗
    percall 每次调用的时间
    #包括子函数时间
    cumtime调用耗时
    percall 每次调用耗时

     这样我们就知道那个方法比较耗费时间了。

    然后通过 line_profiler来优化具体的行

    #pip install line_profiler 安装

    在比较耗时的方法上面加上@profile 这个装饰(这里我们看到之前的read方法比较耗时)
    # kernprof -l -v ./nbNet.py 执行命令

    然后我们执行客户端代码

    然后等一段时间结束

    Function: read at line 45
    
    Line #      Hits         Time  Per Hit   % Time  Line Contents
    ==============================================================
        45                                               @profile
        46                                               def read(self, fd):
        47                                                   """fd is fileno() of socket"""
        48     87910     118605.0      1.3      7.1          try:
        49     87910     104105.0      1.2      6.2              sock_state = self.conn_state[fd]
        50     87910      71153.0      0.8      4.2              conn = sock_state.sock_obj
        51     87910      79448.0      0.9      4.7              if sock_state.need_read <= 0:
        52                                                           raise socket.error
        53     87910     433116.0      4.9     25.8              one_read = conn.recv(sock_state.need_read)
        54     87910     118447.0      1.3      7.1              if len(one_read) == 0:
        55                                                           raise socket.error
        56     87910     122770.0      1.4      7.3              sock_state.buff_read += one_read
        57     87910      92267.0      1.0      5.5              sock_state.have_read += len(one_read)
        58     87910      99366.0      1.1      5.9              sock_state.need_read -= len(one_read)
        59                                                        
        60                                           
        61     87910      78578.0      0.9      4.7              if sock_state.have_read == 10:
        62     43955     126373.0      2.9      7.5                  header_said_need_read = int(sock_state.buff_read)
        63     43955      41639.0      0.9      2.5                  if header_said_need_read <= 0:
        64                                                               raise socket.error
        65     43955      45788.0      1.0      2.7                  sock_state.need_read += header_said_need_read
        66     43955      39130.0      0.9      2.3                  sock_state.buff_read = ''
        67     43955      33228.0      0.8      2.0                  return "readcontent"
        68     43955      37326.0      0.8      2.2              elif sock_state.need_read == 0:
        69     43955      35561.0      0.8      2.1                  return "process"
        70                                                       else:
        71                                                           return "readmore"
        72                                                   except (socket.error, ValueError), msg:
        73                                                       try:
        74                                                           if msg.errno == 11:
        75                                                               return "retry"
        76                                                       except:
        77                                                           pass
        78                                                       return 'closing'
    

      

     

  • 相关阅读:
    python中datetime的使用方法
    apple for liudanping
    fiddle教程收藏
    idea下maven project dependencies 有红线
    win7,下安装mysql如何初始化
    使用idea练习springmvc时,出现404错误总结
    spring拦截器
    spring 学习总结
    eclipse 中maven项目的运行
    Java对象new,到赋null过程的总结
  • 原文地址:https://www.cnblogs.com/nerdlerss/p/9084337.html
Copyright © 2011-2022 走看看