微服務架構的高並發問題


准備工作

修改代碼,模擬請求超時的代碼

先寫一個直接返回的代碼

    @RequestMapping(value = "/find/{id}",method = RequestMethod.GET)
    public String find(@PathVariable Long id) {
        return "查詢成功";
    }

在被調用端,加入線程睡眠

@RequestMapping(value = "/{id}",method = RequestMethod.GET)
    public Product findById(@PathVariable Long id) {
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Product product = productService.findById(id);
        product.setProductName("訪問的服務地址:"+ip + ":" + port);
        return product;
    }

然后再調用端修改配置,增大請求時間,不然直接會報錯

feign:
  client:
    config:
      service-product:
        readTimeout: 6000
        connectTimeout: 6000
        loggerLevel: FULL

然后開始調用,發現find接口很快返回

 

 性能工具Jmetter

 

Apache JMeter 是Apache組織開發的基於Java的壓力測試工具。用於對軟件做壓力測試,它最初被設計
用於Web應用測試,但后來擴展到其他測試領域。 它可以用於測試靜態和動態資源,例如靜態文件、
Java 小服務程序、CGI 腳本、Java 對象、數據庫、FTP 服務器, 等等。JMeter 可以用於對服務器、網
絡或對象模擬巨大的負載,來自不同壓力類別下測試它們的強度和分析整體性能。另外JMeter能夠對應
用程序做功能/回歸測試,通過創建帶有斷言的腳本來驗證你的程序返回了你期望的結果。為了最大限
度的靈活性,JMeter允許使用正則表達式創建斷言。

安裝Jmetter
Jmetter安裝十分簡單,使用資料中的 apache -jmeter-2.13.zip 完整壓縮包,解壓找到安裝目錄下
bin/jmeter.bat 已管理員身份啟動即可。

 

 

配置Jmetter
(1)創建新的測試計划

 

 ( 2)測試計划下創建發起請求的線程組

可以配置請求的線程數,以及每個請求發送的請求次數

(3)創建http請求模板

 

 ( 4)配置測試的接口信息

 

 開始測試,發現請求直接返回的接口都卡住了。

問題分析
在微服務架構中,我們將業務拆分成一個個的服務,服務與服務之間可以相互調用,由於網絡原因或者
自身的原因,服務並不能保證服務的100%可用,如果單個服務出現問題,調用這個服務就會出現網絡
延遲,此時若有大量的網絡涌入,會形成任務累計,導致服務癱瘓。
在SpringBoot程序中,默認使用內置tomcat作為web服務器。單tomcat支持最大的並發請求是有限
的,如果某一接口阻塞,待執行的任務積壓越來越多,那么勢必會影響其他接口的調用。

線程池的形式實現服務隔離

( 1) 配置坐標
為了方便實現線以線程池的形式完成資源隔離,需要引入如下依賴

 <!--hystrix-->
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-metrics-event-stream</artifactId>
            <version>1.5.12</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-javanica</artifactId>
            <version>1.5.12</version>
        </dependency>

( 2) 配置線程池
配置HystrixCommand接口的實現類,再實現類中可以對線程池進行配置

package com.topcheer.order.command;

import com.netflix.hystrix.*;
import com.topcheer.order.entity.Product;
import org.springframework.web.client.RestTemplate;

public class OrderCommand extends HystrixCommand<Product> {

    private RestTemplate restTemplate;
    
    private Long id;

    public OrderCommand(RestTemplate restTemplate, Long id) {
        super(setter());
        this.restTemplate = restTemplate;
        this.id = id;
    }

    private static Setter setter() {

        // 服務分組
        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("order_product");
        // 服務標識
        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("product");
        // 線程池名稱
        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("order_product_pool");
        /**
         * 線程池配置
         *     withCoreSize :  線程池大小為10
         *     withKeepAliveTimeMinutes:  線程存活時間15秒
         *     withQueueSizeRejectionThreshold  :隊列等待的閾值為100,超過100執行拒絕策略
         */
        HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter().withCoreSize(50)
                .withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100);

        // 命令屬性配置Hystrix 開啟超時
        HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
                // 采用線程池方式實現服務隔離
                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
                // 禁止
                .withExecutionTimeoutEnabled(false);
        return Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey)
                .andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties);

    }

    @Override
    protected Product run() throws Exception {
        System.out.println(Thread.currentThread().getName());
        return restTemplate.getForObject("http://service-product/product/"+id, Product.class);
    }

    /**
     * 降級方法
     */
    @Override
    protected Product getFallback(){
        Product product = new Product();
        product.setProductName("不好意思,出錯了");
        return product;
    }
}

 

3) 配置調用
修改 OrderController ,使用自定義的OrderCommand完成調用

    @RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
    public Product findById(@PathVariable Long id) {
        return new OrderCommand(restTemplate,id).execute();
    }

 

配置以后就不卡了,這就引出了服務熔斷Hystrix


免責聲明!

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



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