性能大比拼

一、創建euraka集羣

  1. 創建父項目,包含父pom文件和子項目,並增加依賴,主要是:spring-cloud-starter-parent

    <parent>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-parent</artifactId>
        <version>Camden.RELEASE</version>
    </parent>
    <groupId>com.sohu.tv</groupId>
    <artifactId>spring-cloud-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    
    <modules>
        <module>eureka-test</module>
        <module>provider-test</module>
        <module>consumer-test</module>
    </modules>
    
  2. 創建eureka-test,並在pom添加依賴spring-cloud-starter,spring-cloud-starter-eureka-server

    <parent>
        <groupId>com.sohu.tv</groupId>
        <artifactId>spring-cloud-test</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    
    <artifactId>eureka-test</artifactId>
    <packaging>jar</packaging>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
  3. euraka代碼很簡單:

    @SpringBootApplication
    @EnableEurekaServer
    public class SpringCloudEurekaApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringCloudEurekaApplication.class, args);
        }
    }
    
  4. euraka-test配置application.yml

    spring: 
      application:
        name: eureka-test
    
    server: 
      port: 8000
    
    eureka:
      instance:
        preferIpAddress: true
        instanceId: ${spring.cloud.client.ipAddress}:${server.port}
    ---
    
    spring: 
      profiles: node1
    
    eureka: 
      client: 
        serviceUrl:
          defaultZone: http://eureka:8000/eureka/,http://eureka2:8000/eureka/
    
    ---
    
    spring: 
      profiles: node2
    
    eureka: 
      client:
        serviceUrl:
          defaultZone: http://eureka2:8000/eureka/,http://eureka3:8000/eureka/
    
    ---
    
    spring: 
      profiles: node3
    
    eureka: 
      client: 
        serviceUrl:
          defaultZone: http://eureka3:8000/eureka/,http://eureka:8000/eureka/
    
  5. 在對應的機器上啓動euraka-test,即完成集羣創建,啓動命令如下:

    nohup /opt/cloud/jdk/bin/java -Dspring.profiles.active=node1 -server -Xmx4g -Xms4g -Xss256k -XX:+UseG1GC -XX:+PrintGCDateStamps -Xloggc:/opt/cloud/gc.log -jar /opt/cloud/eureka-test.jar > /opt/cloud/stdout.log &
    nohup /opt/cloud/jdk/bin/java -Dspring.profiles.active=node2 -server -Xmx4g -Xms4g -Xss256k -XX:+UseG1GC -XX:+PrintGCDateStamps -Xloggc:/opt/cloud/gc.log -jar /opt/cloud/eureka-test.jar > /opt/cloud/stdout.log &
    nohup /opt/cloud/jdk/bin/java -Dspring.profiles.active=node3 -server -Xmx4g -Xms4g -Xss256k -XX:+UseG1GC -XX:+PrintGCDateStamps -Xloggc:/opt/cloud/gc.log -jar /opt/cloud/eureka-test.jar > /opt/cloud/stdout.log &
    

二、增加provider-test

  1. pom很簡單:

    <parent>
        <groupId>com.sohu.tv</groupId>
        <artifactId>spring-cloud-test</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    
    <artifactId>provider-test</artifactId>
    <packaging>jar</packaging>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
    
  2. 代碼主要是rest接口(hello10:返回10個字符,hello100:返回100個字符,hello1000:返回1000個字符):

    private String c10 = "abcvdfjiel";
    private String c100 = "abcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfd";
    private String c1000 = "abcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfdabcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfddabcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfdabcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfddabcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfdabcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfddabcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfdabcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfddabcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfdabcvdfjiel0938271648losdgshaiougoiewnavoienoidsa[yg[0e0u9g-rendsvsatg439098u6y480vb309ja0sv[nsdijfdddsds";
    
    @RequestMapping("/hello10")
    public String hello10() {
        return c10;
    }
    
    @RequestMapping("/hello100")
    public String hello100() {
        return c100;
    }
    
    @RequestMapping("/hello1000")
    public String hello1000() {
        return c1000;
    }
    
  3. 還有一個主類:

    @SpringBootApplication
    @EnableDiscoveryClient
    public class ProviderApplication {
        public static void main(String[] args) {
            SpringApplication.run(ProviderApplication.class, args);
        }
    }
    
  4. 配置文件如下:

    spring: 
      application: 
        name: spring-cloud-server
    
    server: 
      port: 9003
      tomcat: 
        maxThreads: 500
        uriEncoding: utf-8
    
    eureka:  
      instance: 
        preferIpAddress: true
        instanceId: ${spring.cloud.client.ipAddress}:${server.port}
      client: 
        serviceUrl: 
           defaultZone: http://eureka3:8000/eureka/,http://eureka:8000/eureka/,http://eureka2:8000/eureka/
    
  5. 啓動兩臺機器提供服務,啓動腳本如下:

    nohup /data/cloud/jdk/bin/java -server -Xmx4g -Xms4g -Xss256k -XX:+UseG1GC -XX:+PrintGCDateStamps -Xloggc:/data/cloud/gc.log -jar /data/cloud/provider-test.jar > /data/cloud/stdout.log &
    

三、增加consumer-test實現

  1. pom如下:

    <parent>
        <groupId>com.sohu.tv</groupId>
        <artifactId>spring-cloud-test</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    
    <artifactId>consumer-test</artifactId>
    <packaging>jar</packaging>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
    </dependencies>
    
  2. 代碼如下:

    1 啓動類:
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
    
    2 feign 服務
    @FeignClient(name = "spring-cloud-server"/**)
    public interface ConsumerService {
        @RequestMapping("/hello10")
        public String hello10();
         
        @RequestMapping("/hello100")
        public String hello100();
         
        @RequestMapping("/hello1000")
        public String hello1000();
    }
    
    3 對外的rest接口
    @RestController
    public class ConsumerController {
        @Autowired
        ConsumerService consumerService;
         
        @RequestMapping("/hello10")
        public String hello10() {
            return consumerService.hello10();
        }
         
        @RequestMapping("/hello100")
        public String hello100() {
            return consumerService.hello100();
        }
         
        @RequestMapping("/hello1000")
        public String hello1000() {
            return consumerService.hello1000();
        }
    }
    
  3. 配置文件如下:

    spring: 
      application:
        name: spring-cloud-consumer
    
    server:
      port: 9001
      tomcat: 
        maxThreads: 1000
        uriEncoding: utf-8
    
    eureka:
      instance:
        preferIpAddress: true
        instanceId: ${spring.cloud.client.ipAddress}:${server.port}
      client:
        serviceUrl:
          defaultZone: http://eureka3:8000/eureka/,http://eureka:8000/eureka/,http://eureka2:8000/eureka/
    
    feign:
      hystrix: 
        enabled: false     
    
    spring-cloud-server: 
      ribbon: 
        MaxAutoRetries: 1
        ConnectTimeout: 2000
        ReadTimeout: 1000
        OkToRetryOnAllOperations: false
        EnableGZIPContentEncodingFilter: true
    
  4. 啓動腳本:

    nohup /opt/cloud/jdk/bin/java -server -Xmx4g -Xms4g -Xss256k -XX:+UseG1GC -XX:+PrintGCDateStamps -Xloggc:/opt/cloud/gc.log -jar /opt/cloud/consumer-test.jar > /opt/cloud/stdout.log &
    

四、feign性能測試

爲了測試不同的http客戶端的表現,並未增加hystrix的支持,consumer的鏈接超時爲2秒,讀取超時爲1秒,另外,每次測試都經過了預熱,只測試小數據傳輸

  1. 爲consumer增加client依賴

    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-httpclient</artifactId>
    </dependency>
    或
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-okhttp</artifactId>
    </dependency>
    或什麼都不依賴,採用jdk的URLConnection
    

    進行性能壓測,併發3000,壓測10萬次,採用長鏈,分別壓測3個接口:

    ab -k -n 100000 -c 3000 http://127.0.0.1:9001/hello10

    ab -k -n 100000 -c 3000 http://127.0.0.1:9001/hello100

    ab -k -n 100000 -c 3000 http://127.0.0.1:9001/hello1000

  2. 機器配置如下:

    cpu核數 主頻
    consumer-test 16 2.40GHz
    provider-test 16 2.27GHz
  3. 具體數據如下(併發3000,壓測10萬次表現如下(壓測3次以上,取最好表現)):

    client 10個字符 100個字符 1000個字符
    吞吐量 響應時間中位值 吞吐量 響應時間中位值 吞吐量 響應時間中位值
    httpclient 3542 846ms 3526 850ms 3427 875ms
    okhttp 14389 208ms 13782 217ms 13761 218ms
    JDK URLConnection 13728 218ms 13577 220ms 13800 217ms

五、resttemplate性能測試

  1. consumer採用resttemplate作爲測試,代碼比較簡單,如下:

    1 默認實現 - 採用jdk的HttpURLConnection
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate(f);
    }
    
    2 採用okhttp3
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        OkHttp3ClientHttpRequestFactory f  =new OkHttp3ClientHttpRequestFactory();
        f.setConnectTimeout(2000);
        f.setReadTimeout(1000);
        f.setWriteTimeout(1000);
        return new RestTemplate(f);
    }
    
    3 採用httpclient 4.3
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {        
        HttpComponentsClientHttpRequestFactory f = new HttpComponentsClientHttpRequestFactory();
        f.setConnectTimeout(2000);
        f.setReadTimeout(1000);
        return new RestTemplate(f);
    }
    
  2. 壓測表現如下:(併發3000,壓測10萬次表現如下(壓測3次以上,取最好表現)):

    client 10個字符 100個字符 1000個字符
    吞吐量 響應時間中位值 吞吐量 響應時間中位值 吞吐量 響應時間中位值
    httpclient 6058 495ms 6051 495ms 6021 498ms
    okhttp 16134 185ms 16194 185ms 15885 188ms
    JDK URLConnection 16009 187ms 15695 191ms 15172 197ms

六、結論

從壓測數據表現來看,性能上resttemplate整體上更勝一籌(可能由於feign採用了動態代理和反射機制)。

在各個http客戶端默認配置下,okhttp3性能更好一些。

從代碼優雅角度來講,feign更簡潔,易懂。

測試結果依賴於測試的環境和數據,及依賴的軟硬件版本和性能,不代表所有情況!

發佈了62 篇原創文章 · 獲贊 23 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章