<noframes id="bhrfl"><address id="bhrfl"></address>

    <address id="bhrfl"></address>

    <noframes id="bhrfl"><address id="bhrfl"><th id="bhrfl"></th></address>

    <form id="bhrfl"><th id="bhrfl"><progress id="bhrfl"></progress></th></form>

    <em id="bhrfl"><span id="bhrfl"></span></em>

    全部
    常見問題
    產品動態
    精選推薦

    Spring Boot虛擬線程與Webflux在JWT驗證和MySQL查詢上的性能比較

    管理 管理 編輯 刪除

    測試場景

    1. 從授權頭信息中提取JWT
    2. 驗證JWT并從中提取用戶的Email
    3. 使用用戶的Email去MySQL里執行查詢
    4. 返回用戶記錄

    測試技術

    這里要對比的兩個核心技術點是:

    1. 帶有虛擬線程的Spring Boot:這不是一個跑在傳統物理線程上的Spring Boot應用,而是跑在虛擬線程上的。這些輕量級線程簡化了開發、維護和調試高吞吐量并發應用程序的復雜任務。雖然虛擬線程仍然在底層操作系統線程上運行,但它們帶來了顯著的效率改進。當虛擬線程遇到阻塞 I/O 操作時,Java 運行時會暫時掛起它,從而釋放關聯的操作系統線程來為其他虛擬線程提供服務。這個優雅的解決方案優化了資源分配并增強了整體應用程序響應能力。
    2. Spring Boot Webflux:Spring Boot WebFlux是Spring生態系統中的反應式編程框架,它利用Project Reactor庫來實現非阻塞、事件驅動的編程。所以,它特別適合需要高并發和低延遲的應用程序。依靠反應式方法,它允許開發人員有效地處理大量并發請求,同時仍然提供與各種數據源和通信協議集成的靈活性。

    不論是Webflux還是虛擬線程,這兩個都是為了提供程序的高并發能力而生,那么誰更勝一籌呢?下面一起看看具體的測試。

    測試環境

    運行環境與工具

    • 一臺16G內存的MacBook Pro M1
    • Java 20
    • Spring Boot 3.1.3
    • 啟用預覽模式,以獲得虛擬線程的強大能力
    • 依賴的第三方庫:jjwt、mysql-connector-java
    • 測試工具:Bombardier
    • 數據庫:MySQL

    數據準備

    • 在Bombardier中準備100000個JWT列表,用來從中隨機選取,并將其放入HTTP請求的授權信息中。
    • 在MySQL中創建一個users表,表結構如下:
    mysql> desc users;
    +--------+--------------+------+-----+---------+-------+
    | Field  | Type         | Null | Key | Default | Extra |
    +--------+--------------+------+-----+---------+-------+
    | email  | varchar(255) | NO   | PRI | NULL    |       |
    | first  | varchar(255) | YES  |     | NULL    |       |
    | last   | varchar(255) | YES  |     | NULL    |       |
    | city   | varchar(255) | YES  |     | NULL    |       |
    | county | varchar(255) | YES  |     | NULL    |       |
    | age    | int          | YES  |     | NULL    |       |
    +--------+--------------+------+-----+---------+-------+
    6 rows in set (0.00 sec)
    • 為users表準備100000條用戶數據

    測試代碼

    帶虛擬線程的Spring Boot程序

    application.properties配置文件:


    server.port=3000
    
    spring.datasource.url= jdbc:mysql://localhost:3306/testdb?useSSL=false
    spring.datasource.username= testuser
    spring.datasource.password= testpwd
    spring.jpa.hibernate.ddl-auto= update
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

    User實體類(為了讓文章讓簡潔一些,這里省略了getter和setter):


    @Entity
    @Table(name = "users")
    public class User {
      @Id
      private String email;
    
      private String first;
    
      private String last;
    
      private String city;
    
      private String county;
    
      private int age;
    
    }

    應用主類:


    @SpringBootApplication
    public class UserApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(UserApplication.class, args);
        }
    
        @Bean
        public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
            return protocolHandler -> {
                protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
            };
        }
    }

    提供CRUD操作的UserRepository


    import org.springframework.data.repository.CrudRepository;
    import com.example.demo.User;
    
    public interface UserRepository extends CrudRepository<User, String> {
    
    }

    提供API接口的UserController類:


    @RestController
    public class UserController {
    
        @Autowired
        UserRepository userRepository;
    
        private SignatureAlgorithm sa = SignatureAlgorithm.HS256;
        private String jwtSecret = System.getenv("JWT_SECRET");
    
        @GetMapping("/")
        public User handleRequest(@RequestHeader(HttpHeaders.AUTHORIZATION) String authHdr) {
            String jwtString = authHdr.replace("Bearer","");
            Claims claims = Jwts.parser()
                .setSigningKey(jwtSecret.getBytes())
                .parseClaimsJws(jwtString).getBody();
    
            Optional<User> user = userRepository.findById((String)claims.get("email"));
            return user.get();
        }
    }

    Spring Boot Webflux程序

    application.properties配置文件:


    server.port=3000
    
    spring.r2dbc.url=r2dbc:mysql://localhost:3306/testdb
    spring.r2dbc.username=dbser
    spring.r2dbc.password=dbpwd

    User實體(這里也省略了構造函數、getter和setter):


    public class User {
    
      @Id
      private String email;
    
      private String first;
    
      private String last;
    
      private String city;
    
      private String county;
    
      private int age;
    
      // 省略了構造函數、getter、setter
      
    }

    應用主類:


    @EnableWebFlux
    @SpringBootApplication
    public class UserApplication {
    
      public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
      }
    
    }

    提供CRUD操作的UserRepository


    public interface UserRepository extends R2dbcRepository<User, String> {
    
    }

    提供根據id查用戶的業務類UserService


    @Service
    public class UserService {
    
      @Autowired
      UserRepository userRepository;
    
      public Mono<User> findById(String id) {
        return userRepository.findById(id);
      }
    }

    提供API接口的UserController類:


    @RestController
    @RequestMapping("/")
    public class UserController {
    
      @Autowired
      UserService userService;
    
      private SignatureAlgorithm sa = SignatureAlgorithm.HS256;
      private String jwtSecret = System.getenv("JWT_SECRET");
    
      @GetMapping("/")
      @ResponseStatus(HttpStatus.OK)
      public Mono<User> getUserById(@RequestHeader(HttpHeaders.AUTHORIZATION) String authHdr) {
        String jwtString = authHdr.replace("Bearer","");
        Claims claims = Jwts.parser()
            .setSigningKey(jwtSecret.getBytes())
            .parseClaimsJws(jwtString).getBody();
        return userService.findById((String)claims.get("email"));
      }
    
    }

    測試結果

    接下來是重頭戲了,作者對兩個技術方案都做了500w個請求的測試,評估的不同并發連接級別包含:50、100、300。

    具體結果如下三張圖:

    94bd8202412171544248853.png

    73a3e202412171544494284.png

    c166920241217154504217.png

    最后得出結論:Spring Boot Webflux要更優于帶虛擬線程的Spring Boot。

    請登錄后查看

    CRMEB 最后編輯于2024-12-17 15:45:45

    快捷回復
    回復
    回復
    回復({{post_count}}) {{!is_user ? '我的回復' :'全部回復'}}
    排序 默認正序 回復倒序 點贊倒序

    {{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level }}

    作者 管理員 企業

    {{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
    {{item.is_suggest == 1? '取消推薦': '推薦'}}
    沙發 板凳 地板 {{item.floor}}#
    {{item.user_info.title || '暫無簡介'}}
    附件

    {{itemf.name}}

    {{item.created_at}}  {{item.ip_address}}
    {{item.like_count}}
    {{item.showReply ? '取消回復' : '回復'}}
    刪除
    回復
    回復

    {{itemc.user_info.nickname}}

    {{itemc.user_name}}

    回復 {{itemc.comment_user_info.nickname}}

    附件

    {{itemf.name}}

    {{itemc.created_at}}
    {{itemc.like_count}}
    {{itemc.showReply ? '取消回復' : '回復'}}
    刪除
    回復
    回復
    查看更多
    1218
    {{like_count}}
    {{collect_count}}
    添加回復 ({{post_count}})

    相關推薦

    快速安全登錄

    使用微信掃碼登錄
    {{item.label}} 加精
    {{item.label}} {{item.label}} 板塊推薦 常見問題 產品動態 精選推薦 首頁頭條 首頁動態 首頁推薦
    取 消 確 定
    回復
    回復
    問題:
    問題自動獲取的帖子內容,不準確時需要手動修改. [獲取答案]
    答案:
    提交
    bug 需求 取 消 確 定

    微信登錄/注冊

    切換手機號登錄

    {{ bind_phone ? '綁定手機' : '手機登錄'}}

    {{codeText}}
    切換微信登錄/注冊
    暫不綁定
    亚洲欧美字幕
    CRMEB客服

    CRMEB咨詢熱線 咨詢熱線

    400-8888-794

    微信掃碼咨詢

    CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
    返回頂部 返回頂部
    CRMEB客服