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等監控結果如圖所示:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM