【代碼筆記】高并發場景下問題解決思路

高并發指的是在單位時間內,瞬時流量激增,系統需要同時處理大量并行的請求或操作。這種情況通常出現在面向大量用戶或服務的分布式系統中,尤其是當用戶請求高度集中時,比如促銷活動、秒殺活動、注冊搶課、熱點事件、定時任務調度等。

在高并發發生時,系統可能存在以下問題:
1.系統性能維度

  • 性能瓶頸:高并發可能導致系統資源(如CPU、內存、磁盤I/O、網絡帶寬)達到瓶頸,影響整體性能。
  • 響應延遲:系統處理請求的響應時間可能因并發量增加而延長,影響用戶體驗。
  • 系統過載:超出系統設計容量的并發請求可能導致系統過載,甚至宕機。
  • 容錯性差:在高并發下,系統的容錯性受到考驗,單點故障可能導致整個服務不可用。

2.用戶行為維度

  • 不可預測性:用戶行為在高并發期間可能變得難以預測,導致難以準確評估系統負載。
  • 用戶操作沖突:大量用戶同時進行操作可能導致沖突,如搶票、搶單等場景。
  • 用戶體驗下降:由于系統響應變慢,用戶體驗可能顯著下降。

3.數據處理維度

  • 數據不一致:在高并發寫入時,缺乏合適的鎖機制可能導致數據不一致。
  • 事務管理困難:高并發環境下,保持事務的ACID屬性變得更加困難。
  • 數據庫壓力:高并發可能導致數據庫連接數過多,查詢和事務處理速度下降。

二.策略

為了應對高并發帶來的壓力,在高并發場景下,系統設計和優化可以從以下幾個維度進行調整:

1. 架構設計維度

  • 服務拆分:將單體應用拆分成多個微服務,實現服務的獨立擴展和維護。
  • 負載均衡:使用硬件或軟件負載均衡器,如Nginx或HAProxy,分配網絡流量和請求。
  • 無狀態設計:確保應用服務器無狀態,可以水平擴展。無狀態設計是構建可伸縮、高可用系統的重要原則,特別是在高并發場景下。在無狀態設計中,服務器不會存儲任何關于客戶端請求的信息,每個請求都是獨立的,不依賴于之前的任何請求。

2. 數據庫與存儲優化維度

  • 數據庫優化:對數據庫進行定期的維護,如優化索引、更新統計信息。
  • 緩存應用:使用緩存減少數據庫訪問,如Redis進行熱點數據緩存。
  • 存儲優化:使用SSD代替HDD,提高I/O效率;考慮使用分布式存儲系統。

3. 緩存策略維度

  • 多級緩存:實現應用層、服務層和數據庫層的多級緩存機制。
  • 緩存淘汰策略:合理配置緩存淘汰策略,如LRU(最近最少使用)。
  • 熱點數據優化:對頻繁訪問的數據進行特殊緩存處理。

4. 代碼與應用優化維度

  • 異步處理:將非實時性的任務異步化,使用消息隊列如Kafka或RabbitMQ。
  • 代碼審查:定期進行代碼審查,優化代碼邏輯和結構。
  • 資源池:使用線程池、數據庫連接池等資源池技術,提高資源利用效率。

5. 運維與監控維度

  • 實時監控:部署實時監控系統,如Prometheus或Zabbix,監控系統性能指標。
  • 日志管理:集中管理日志,使用ELK(Elasticsearch, Logstash, Kibana)堆棧進行日志分析。
  • 自動擴縮容:結合云服務提供的自動擴縮容功能,根據流量自動調整資源。

通過上述維度的策略實施,可以顯著提升系統在高并發環境下的性能和穩定性。然而,每個系統的具體場景和需求都有所不同,因此在實施優化時需要根據實際情況進行定制化的調整。

三.例子

在大學搶課場景,課程的人數限制為30個學生,系統面臨的主要問題包括:

  1. 高并發處理:在搶課開始時,系統可能會收到大量并發請求,需要設計以承受這種瞬時流量。
  2. 數據一致性:確保在高并發下,課程的選課名額不會超賣。
  3. 公平性:確保所有學生在搶課開始時都有機會選到課程。
  4. 系統穩定性:在高負載下,系統需要保持穩定,避免宕機。

領域模型:

  • Course:代表一門課程,包含課程ID、課程名稱、剩余名額等屬性。
  • Student:代表學生,包含學生ID、姓名等屬性。
  • Enrollment:代表選課記錄,包含學生ID、課程ID、選課時間等信息。

實現邏輯:

  1. 初始化課程:在系統中預先定義好每門課程的信息,包括課程ID、課程名稱、容量等。
  2. 發布課程:將課程信息發布到選課系統中,學生可以查看到可選用課的列表。
  3. 學生選課:學生發送選課請求到系統。
  4. 獲取分布式鎖:系統嘗試獲取對應課程的分布式鎖,確保同時只有一個請求能修改名額。
  5. 檢查名額:檢查Redis中該課程的剩余名額是否大于0。
  6. 更新名額:如果名額足夠,更新Redis中該課程的剩余名額,并記錄選課信息到數據庫。
  7. 釋放鎖:完成名額更新后,釋放分布式鎖。
  8. 返回結果:向學生返回選課成功或失敗的結果。

Demo

以下是使用Spring Boot和Redis實現大學搶課邏輯的示例代碼

CourseController.java - REST 控制器用于處理課程注冊請求:

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/courses") // 定義API的基礎路由
public class CourseController {@Autowiredprivate CourseService courseService; // 注入課程服務類@PostMapping("/{courseId}/enroll") // 定義POST請求,用于搶課操作public ResponseEntity<?> enrollStudent(@PathVariable("courseId") String courseId, // 課程ID作為路徑參數@RequestParam("studentId") String studentId) { // 學生ID作為請求參數boolean result = courseService.enroll(courseId, studentId); // 調用服務類的方法進行搶課if (result) {return ResponseEntity.ok("Enrollment successful!"); // 如果成功,返回成功響應} else {return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body("Course is full."); // 如果失敗,返回服務不可用響應}}
}

CourseService.java - 服務類使用Redis進行分布式鎖控制:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;@Service
public class CourseService {@Autowiredprivate StringRedisTemplate redisTemplate; // 注入Redis字符串模板類@Autowiredprivate EnrollmentRepository enrollmentRepository; // 注入選課記錄的持久層接口private static final String LOCK_SCRIPT = // 定義Lua腳本用于獲取鎖"if redis.call('set', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2]) == 1 then return 1 else return 0 end";public boolean enroll(String courseId, String studentId) {String lockKey = "course:" + courseId + ":lock"; // 定義鎖的keyString studentKey = "course:" + courseId + ":student:" + studentId; // 定義學生的key// 使用Redis的Lua腳本原子地嘗試獲取鎖,使用隨機值和1000ms超時Boolean acquiredLock = redisTemplate.execute(new DefaultRedisScript(LOCK_SCRIPT),Collections.singletonList(lockKey),studentId,String.valueOf(1000L));if (Boolean.TRUE.equals(acquiredLock)) {try {// 檢查學生是否已經選過這門課程if (redisTemplate.opsForSet().isMember(studentKey, studentId)) {return false;}// 檢查剩余座位數Integer remainingSeats = redisTemplate.opsForValue().increment("course:" + courseId + ":seats", -1);if (remainingSeats >= 0) {// 選課成功,將學生添加到選課集合中redisTemplate.opsForSet().add(studentKey, studentId);// 保存選課記錄Enrollment enrollment = new Enrollment(studentId, courseId);enrollmentRepository.save(enrollment);return true;} else {// 恢復座位數,因為課程已滿redisTemplate.opsForValue().increment("course:" + courseId + ":seats", 1);return false;}} finally {// 總是在finally塊中釋放鎖,以防止鎖泄露redisTemplate.delete(lockKey);}} else {return false;}}
}

EnrollmentRepository.java - 持久層接口用于管理選課記錄:

import org.springframework.data.jpa.repository.JpaRepository;public interface EnrollmentRepository extends JpaRepository<Enrollment, Long> {// JPA/JDBC方法用于管理選課記錄
}

CourseService中,我們使用Lua腳本來嘗試獲取課程的鎖。如果鎖被成功獲取(acquiredLocktrue),我們進一步檢查學生是否已經選過這門課程。如果沒有,我們減少座位數,并且如果座位仍然可用,我們將學生添加到選課集合中并保存選課記錄。如果課程已滿或者學生已經選過這門課程,我們釋放鎖并返回false

請注意,上述代碼知識一個思路演示,在生產系統中,還需要處理各種邊緣情況和潛在的異常。可能還需要適當配置StringRedisTemplateEnrollmentRepository,包括在Spring Boot應用程序中設置必要的依賴和注解。
此外,用于鎖定和跟蹤學生請求的Redis鍵需要精心設計,以避免沖突,并確保它們可以被輕松管理和在不再使用后清理。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/10002.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/10002.shtml
英文地址,請注明出處:http://en.pswp.cn/web/10002.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Maven 插件使用

1.spring-boot-maven-plugin 我們直接使用 maven package &#xff08;maven自帶的package打包功能&#xff09;&#xff0c;打包Jar包的時候&#xff0c;不會將該項目所依賴的Jar包一起打進去&#xff0c;在使用java -jar命令啟動項目時會報錯&#xff0c;項目無法正常啟動。…

開源相機管理庫Aravis例程學習(七)——chunk-parser

開源相機管理庫Aravis例程學習&#xff08;七&#xff09;——chunk-parser 簡介例程代碼函數說明arv_camera_create_chunk_parserarv_camera_set_chunksarv_chunk_parser_get_integer_value 簡介 本文針對官方例程中的&#xff1a;05-chunk-parser做簡單的講解。并介紹其中調…

kali linux更新卡在libc6:amd64 (2.37-15)

適配于linux的windows子系統&#xff0c;wsl2&#xff0c;安裝kali linux&#xff0c;運行 sudo apt update 卡在&#xff1a;Setting up libc6:amd64 (2.37-15) … 關機重啟、重新修復執行也不行 解決辦法&#xff1a;kill當前apt進程或者關機重啟kali-linux&#xff0c;然…

【系統架構師】-選擇題(十二)計算機網絡

1、網閘的作用&#xff1a;實現內網與互聯網通信&#xff0c;但內網與互聯網不是直連的 2、管理距離是指一種路由協議的路由可信度。15表示該路由信息比較可靠 管理距離越小&#xff0c;它的優先級就越高&#xff0c;也就是可信度越高。 0是最可信賴的&#xff0c;而255則意味…

MySQL變量的定義與使用(一)

一、標識符的命名規范 1、不能以數字開頭 2、不能使用關鍵字 3、只能使用_和$符號&#xff0c;不允許使用其他符號 二、定義MySQL變量的方法 set userName"鵝卵石"; #讀取變量 select userName as 名稱; #讀取時包含賦值操作 select userName:喜羊羊 as 賦值查詢名…

【JavaScript】內置對象 - 數組對象 ① ( 數組簡介 | 數組創建 | 數組類型檢測 )

文章目錄 一、數組對象1、數組簡介2、數組創建3、數組檢測 - Array.isArray() 方法4、數組檢測 - instanceof 運算符 Array 數組對象參考文檔 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array 一、數組對象 1、數組簡介 在 JavaScr…

(三十八)第 6 章 樹和二叉樹(二叉樹的二叉線索存儲)

1. 背景說明 2. 示例代碼 1) errorRecord.h // 記錄錯誤宏定義頭文件#ifndef ERROR_RECORD_H #define ERROR_RECORD_H#include <stdio.h> #include <string.h> #include <stdint.h>// 從文件路徑中提取文件名 #define FILE_NAME(X) strrchr(X, \\) ? strrc…

Html生成自定義函數的圖形(2024/5/10)

大概效果如下&#xff1a; 可以自定義函數和x的定義域。 我們可以使用數學表達式解析庫來解析用戶輸入的函數方程&#xff0c;并根據給定的 x 區間計算函數的值&#xff0c;然后使用圖表庫繪制圖形。 在這里&#xff0c;我將使用 math.js 庫來解析數學表達式&#xff0c;并使…

探索計算之美:HTML CSS 計算器案例

本次案例是通過HTML和CSS&#xff0c;我們可以為計算器賦予獨特的外觀和功能&#xff1b; 在這個計算器中&#xff0c;你將會發現&#xff1a; 簡潔清晰的界面設計&#xff0c;使用戶能夠輕松輸入和查看計算結果。利用HTML構建的結構&#xff0c;確保頁面具有良好的可訪問性和…

【全開源】JAVA上門家政服務系統源碼微信小程序+微信公眾號+APP+H5

功能介紹 用戶端&#xff1a;精準分類、支持家政、維修、萬能服務、一口價、報價、線上、各類家政服務、優惠專區、師傅入駐、商家入駐、我的需求、補費明細、我的投訴 師傅端&#xff1a;接單池、消息通知、接單管理、今日訂單、師傅入駐、我的錢包、實名認證 商家端&#…

HTTPS 原理和 TLS 握手機制

HTTPS的概述與重要性 在當今數字化時代&#xff0c;網絡安全問題日益凸顯&#xff0c;數據在傳輸過程中的安全性備受關注。HTTPS 作為一種重要的網絡通信協議&#xff0c;為數據的傳輸提供了強有力的安全保障。它是在 HTTP 的基礎上發展而來&#xff0c;通過引入數據加密機制&a…

流量分析(一)

數據庫類流量分析 MySQL流量 常規操作&#xff0c;查找flag ctfhub{} 注意要選擇字符集 Redis流量 查找ctfhub結果沒找到 嘗試把其變成十六進制繼續進行查找 看到了前半段flag 接著往下看 找到了后半段的flag MongoDB流量 還是一樣查找ctfhub 字符串沒找到 轉成十六進制也沒…

c 在線教育系統論文,在線教育需要在哪些渠道做付費推廣呢?

隨著在網上學習的人越來越多&#xff0c;很多在線教育公司都開發了屬于自己的平臺。如果只做開發&#xff0c;不去做運營推廣的話&#xff0c;這個在線平臺就等于是白做了。那么在線教育需要在哪些渠道做付費推廣呢? 1、官網廣告推薦位 Banner作為一款展示型頁面橫幅廣告&…

Spring狀態機的實現原理和業務場景

Spring Statemachine 是 Spring Framework 的一部分&#xff0c;它提供了一種實現狀態機的方式&#xff0c;允許開發者定義狀態機的狀態、事件、行為和轉換。狀態機是一種計算模型&#xff0c;它可以根據一系列規則從一個狀態轉移到另一個狀態。以下 V 哥將從Spring狀態機的基本…

OpenVoiceV2本地部署教程,蘋果MacOs部署流程,聲音響度統一,文字轉語音,TTS

最近OpenVoice項目更新了V2版本&#xff0c;新的模型對于中文推理更加友好&#xff0c;音色也得到了一定的提升&#xff0c;本次分享一下如何在蘋果的MacOs系統中本地部署OpenVoice的V2版本。 首先下載OpenVoiceV2的壓縮包&#xff1a; OpenVoiceV2-for-mac代碼和模型 https:…

Kitti數據集再識(官網閱讀)

KITTI數據集中真值與標定參數 0. 前言 為了再研KITTI數據集及方便下載文件,特地買了梯子,心疼人民幣QWQ~555 1. KITTI-home Welcome to the KITTI Vision Benchmark Suite! 我們利用我們的自動駕駛平臺開發新穎的具有挑戰性的真實世界計算機視覺基準。我們感興趣的任務是…

interview_bak

flink內存管理 JVM 存在的幾個問題: Java 對象存儲密度低。一個只包含 boolean 屬性的對象占用了16個字節內存:對象頭占了8個,boolean 屬性占了1個,對齊填充占了7個。而實際上只需要一個bit(1/8字節)就夠了。Full GC 會極大地影響性能,尤其是為了處理更大數據而開了很大…

安裝openssh-server,提供遠程ssh

安裝openssh-server&#xff0c;提供遠程ssh 1.檢查自己是否安裝了openssh-server dpkg -l | grep ssh如果輸出內容有openssh-server&#xff0c;說明已經安裝過了&#xff0c;可以跳過下一步 2.安裝openssh-server 由于ubuntu自帶ssh客戶端&#xff0c;只需要安裝openssh-se…

mysql -- CRUD

CRUD MySQL是一個廣泛使用的開源關系數據庫管理系統&#xff08;RDBMS&#xff09;&#xff0c;它支持通過SQL&#xff08;Structured Query Language&#xff09;語言進行數據的管理。在MySQL中&#xff0c;CRUD是一個常見的術語&#xff0c;代表了數據管理的四個基本操作&am…

圖片轉圖標(ICO)的工具軟件

目前常用的ICO轉換方式大多都是網頁在線轉換&#xff0c;沒網就無法使用了。自己編寫了一款小軟件&#xff0c;可以將各種格式圖片轉為ICO圖標。 目前支持PNG,BMP,JPG,JPEG,GIF等格式的圖片轉換成ICO&#xff0c;支持的尺寸有常用的16*16&#xff0c;24*24&#xff0c;32*32&am…