zoukankan      html  css  js  c++  java
  • spring boot2.0.4集成druid,用jmeter并发测试工具调用接口,druid查看监控的结果

    一、项目介绍(本项目用的编程语言是jdk8,项目源码: https://github.com/zhzhair/mybatis-druid-spring-boot.git)
      1.引入pom依赖:
      <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.2</version>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <scope>runtime</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
        </dependency>

        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid-spring-boot-starter</artifactId>
          <version>1.1.14</version>
        </dependency>
      </dependencies>
      由引入的jar包可知,项目用MySQL + mybatis + redis架构,数据库连接池用阿里的druid

      2.配置文件application.yml配置(配置MySQL数据源、druid连接池及监控、redis):
      spring:
        datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: "jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false"
        username: root
        password: 123456
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
          max-active: 100
          min-idle: 10
          max-wait: 60000
          filter:
            stat:
              merge-sql: true
              slow-sql-millis: 200
          test-on-borrow: true
          validation-query: SELECT 1
          use-global-data-source-stat: true
          # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
          # http://127.0.0.1:8080/druid2/index.html
          filters: stat,wall,slf4j
          pool-prepared-statements: true
          max-pool-prepared-statement-per-connection-size: 20
        redis:
          host: 127.0.0.1
          password:
          database: 0
          timeout: PT1M1S
          jedis:
            pool.max-active: 200
            pool.max-idle: 50
            pool.max-wait: PT-1S
            pool.min-idle: 10

      table-num: 64

      3.引入druid配置类(sql和uri监控访问地址:http://localhost:8080/druid/index.html,用户名和密码分别是admin和123456):

        package com.example.demo.config.druid;
    
        import com.alibaba.druid.support.http.StatViewServlet;
        import com.alibaba.druid.support.http.WebStatFilter;
        import org.springframework.boot.web.servlet.FilterRegistrationBean;
        import org.springframework.boot.web.servlet.ServletRegistrationBean;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
    
        @Configuration
        public class DruidConfiguration {
            @Bean
            public ServletRegistrationBean DruidStatViewServle2() {
                //org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.
                ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid2/*");
                //添加初始化参数:initParams
                servletRegistrationBean.addUrlMappings("/druid/*");
                //白名单:
        //        servletRegistrationBean.addInitParameter("allow","192.168.1.106");
                //IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
                // servletRegistrationBean.addInitParameter("deny", "192.168.1.73");
                //登录查看信息的账号密码.
                servletRegistrationBean.addInitParameter("loginUsername","admin");
                servletRegistrationBean.addInitParameter("loginPassword","123456");
                //是否能够重置数据.
                servletRegistrationBean.addInitParameter("resetEnable","false");
                return servletRegistrationBean;
            }
            
            @Bean
            public FilterRegistrationBean druidStatFilter2(){
                FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>(new WebStatFilter());
                filterRegistrationBean.setName("druidFilter2");
                //添加过滤规则.
                filterRegistrationBean.addUrlPatterns("/*");
                //添加不需要忽略的格式信息.
                filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*");
                return filterRegistrationBean;
            }
    
        }

      4.在测试类创建表user_*和user_mobile_*:

        @RunWith(SpringRunner.class)
        @SpringBootTest
        public class DemoApplicationTests {
    
            @Resource
            private TestUserService userService;
            @Test
            public void contextLoads() {
                userService.dropTables();
                userService.createTables();
            }
    
        }
        
        @Service
        public class TestUserServiceImpl implements TestUserService {
            @Resource
            private UserMapper userMapper;//jdbc操作接口
            @Value("${table-num}")
            private int tableNum;//分表的个数
    
            @Override
            public void dropTables() {
                IntStream.range(0,tableNum).parallel().forEach(this::dropTables);
            }
    
            private void dropTables(int i){
                userMapper.dropTable("user_" + i);
                userMapper.dropTable("user_mobile_" + i);
            }
    
            @Override
            public void createTables() {
                IntStream.range(0,tableNum).parallel().forEach(this::createTables);
            }
    
            private void createTables(int i){
                String suffix = String.valueOf(i);
                userMapper.createTableUser(suffix);
                userMapper.createTableUserMobile(suffix);
            }
        }

      5.编写restful风格的接口(包括登录和注册):

        @RestController
        @RequestMapping("test/user")
        public class TestUserController extends BaseController {
            @Resource
            private TestUserService userService;
            @Resource
            private TokenManager tokenManager;//给登录用户生成token,并放到redis
            @RequestMapping(value = "/loginByMobile", method = {RequestMethod.GET}, produces = {MediaType.APPLICATION_JSON_VALUE})
            public BaseResponse<LoginResponse> loginByMobile() {
                BaseResponse<LoginResponse> baseResponse = new BaseResponse<>();
                Integer userId = userService.getUserIdByMobile();
                if(userId != null){
                    baseResponse.setCode(0);
                    baseResponse.setMsg("手机号登录成功");
                    String token = tokenManager.generateToken(userId);
                    LoginResponse loginResponse = new LoginResponse();
                    loginResponse.setUserId(userId);
                    loginResponse.setToken(token);
                    loginResponse.setExpire(System.currentTimeMillis() + 3600 * 1000);
                    baseResponse.setData(loginResponse);
                }else{
                    baseResponse.setCode(-3);
                    baseResponse.setMsg("手机号未注册");
                }
                return baseResponse;
            }
    
            @RequestMapping(value = "/register", method = {RequestMethod.POST}, produces = {MediaType.APPLICATION_JSON_VALUE})
            public BaseResponse<User> register() {
                BaseResponse<User> baseResponse = new BaseResponse<>();
                Integer userId = userService.getUserIdByMobile();
                if(userId == null){
                    User user = userService.register();
                    baseResponse.setCode(0);
                    baseResponse.setData(user);
                    baseResponse.setMsg("注册成功");
                }else{
                    baseResponse.setCode(1);
                    baseResponse.setMsg("手机号已被注册");
                }
                return baseResponse;
            }
        }
        
        @Service
        public class TestUserServiceImpl implements TestUserService {
            @Resource
            private UserService userService;
            @Value("${table-num}")
            private int tableNum;//分表的个数
    
            @Override
            public Integer getUserIdByMobile() {
                return userService.getUserIdByMobile(getMobileStr());
            }
    
            @Override
            public User register() {
                UserRequest userRequest = new UserRequest();
                userRequest.setMobile(getMobileStr());
                userRequest.setIcon("http://127.0.0.1/"+getMobileStr()+".jpg");
                int rand = new Random().nextInt(4);
                userRequest.setNickname(new String[]{"xiaoming","xiaohong","xiaoqiang","xiaoli"}[rand]);
                return userService.register(userRequest);
            }
    
            /**
             * 模拟手机号
             */
            private String getMobileStr(){
                String[] strings = {"13","15","16","18"};
                String beginString = strings[new Random().nextInt(4)];
                int a = new Random().nextInt(10_0000_0000);
                String endString = String.valueOf(a);
                int length = 9 - endString.length();
                StringBuilder stringBuilder = new StringBuilder(beginString);
                for (int i = 0; i < length; i++) {
                    stringBuilder.append("0");
                }
                return stringBuilder.append(endString).toString();
            }
        }    
        
        @Service
        public class UserServiceImpl implements UserService {
            private final String USER_ID_INC = "USER_ID_INC";
            @Resource
            private UserMapper userMapper;//jdbc操作接口
            @Resource(name = "stringRedisTemplate")
            private RedisTemplate<String, String> redisTemplate;
    
            @Value("${table-num}")
            private int tableNum;//分表的个数
    
            @Transactional(isolation = Isolation.REPEATABLE_READ)
            @Override
            public User register(UserRequest userRequest) {
                String usercode = redisTemplate.opsForValue().get(USER_ID_INC);
                Integer userId;
                if(usercode == null){//如果redis的数据丢失,就找出最大的userId,并给USER_ID_INC赋值
                    int temp = 0;
                    for (int i = 0; i < tableNum; i++) {
                        Integer maxUserId = userMapper.getMaxUserId(String.valueOf(i));
                        if(maxUserId != null && temp < maxUserId){
                            temp = maxUserId;
                        }
                    }
                    userId = temp + 1;
                    redisTemplate.opsForValue().set(USER_ID_INC,String.valueOf(userId));
                }else{
                    Long num = redisTemplate.opsForValue().increment(USER_ID_INC,1);
                    userId = Integer.valueOf(num + "");
                }
                User user = new User();
                user.setUserId(userId);
                user.setMobile(userRequest.getMobile());
                user.setIcon(userRequest.getIcon());
                user.setNickname(userRequest.getNickname());
                int rem = userId % tableNum;
                userMapper.insertUser(user,String.valueOf(rem));
                int rem0 = Math.abs(userRequest.getMobile().hashCode()) % tableNum;
                String mobile = userRequest.getMobile();
                userMapper.insertUserMobile(mobile,userId,String.valueOf(rem0));
                return user;
            }
    
            @Override
            public Integer getUserIdByMobile(String mobile) {
                int rem = Math.abs(mobile.hashCode()) % tableNum;
                return userMapper.getUserByMobile(mobile,String.valueOf(rem));
            }
    
        }

    二、用jmeter做并发测试(jmeter版本4.0):
      1.双击打开bin目录下的jmeter.bat文件,菜单选简体中文:Options->Choose language->Chinese(Simplified)。点文件夹图标可以选择已有的jmeter脚本。

      2.右键测试计划->添加->Threads(Users)->线程组,然后配置执行线程数、持续时间等信息。登录和注册我都建了单独的线程组,其中:登录的线程数36000,持续时间600秒;注册的线程数6000,持续时间600秒。
      3.右键测试计划->添加->监听器->(查看结果数和聚合报告等,用于分析并发测试结果)。
      4.分别右键选中登录和注册的线程组->添加->sampler->HTTP请求,配置如下:
    登录和注册的协议都填http,IP都填127.0.0.1,端口号都填8080。登录的方式选GET,注册的方式选POST。登录的路径填/test/user/loginByMobile,注册的路径填/test/user/register。
      5.点击打开聚合报告,启动项目,点击菜单栏绿色的三角形图标运行,观察聚合报告的结果如下图所示:

    三、查看druid的sql监控和uri监控:
      jmeter运行时,访问http://localhost:8080/druid/index.html,sql监控和webUI等监控结果如图所示:

  • 相关阅读:
    Building a Space Station POJ
    Networking POJ
    POJ 1251 Jungle Roads
    CodeForces
    CodeForces
    kuangbin专题 专题一 简单搜索 POJ 1426 Find The Multiple
    The Preliminary Contest for ICPC Asia Shenyang 2019 F. Honk's pool
    The Preliminary Contest for ICPC Asia Shenyang 2019 H. Texas hold'em Poker
    The Preliminary Contest for ICPC Asia Xuzhou 2019 E. XKC's basketball team
    robotparser (File Formats) – Python 中文开发手册
  • 原文地址:https://www.cnblogs.com/zhzhair-coding/p/10657971.html
Copyright © 2011-2022 走看看