項目命名為goodsKill一方面有商品秒殺的意思(好像有點chinglish的味道),另外也可理解為good skill ,本項目就是希望搭建一套完整的項目框架,把一些好的技術和開發技巧整合進來(偏向後端技術),方便學習查閱。
本項目為模擬秒殺項目,提供統一秒殺模擬請求接口,技術上整體採用SpringMVC + Mybatis持久層框架,採用Dubbo3.x [1] +Feign完成服務間接口調用,服務註冊發現以及配置中心使用Nacos,支持資料庫分庫分錶、分散式事務,使用狀態機完成資料狀態間的轉換(基於Spring Statemachine實作)。
整合了Spring AI服務,可以透過AI機器人完成模擬秒殺動作。
master
分支基於最新Spring Cloud 2023.x + Spring Boot 3.x + JDK21體系構建,目前僅保留核心的模擬秒殺API接口,如需使用Spring Boot 2.7.x + JDK11版本可以切換到tag v2.7.4(支持登入註冊以及簡單的後台管理功能)。 master分支目前升級改造中,功能不夠穩定,如遇代碼報錯建議使用舊版。
本專案功能目前比較簡陋且有很多不完善的地方,真實的秒殺場景遠比本專案中的實現方式複雜,本專案省略了真實場景中的部分技術實現細節,目前僅作學習參考之用,如果覺得本計畫對你有幫助的請多多star支持一下? ~ ~。
附:碼雲專案連結
https://gitee.com/techa/goodsKill
,clone速度慢的用碼雲倉儲拉吧,不定期同步到碼雲~
使用的工具或框架 | 名稱 | 官網 |
---|---|---|
Spring Boot | Spring Boot框架 | https://spring.io/projects/spring-boot |
MyBatis-Plus | MyBatis增強工具 | https://mp.baomidou.com/ |
ZooKeeper | 分散式協調服務 | http://zookeeper.apache.org/ |
Redis | 分散式快取資料庫 | https://redis.io/ |
Kafka | 訊息佇列 | http://kafka.apache.org/ |
RabbitMQ | 訊息佇列 | https://www.rabbitmq.com/ |
MongoDB | Mongo資料庫 | https://www.mongodb.com/ |
MySQL | MySQL資料庫 | https://www.mysql.com/ |
Elasticsearch | 全文搜尋引擎 | https://www.elastic.co |
Sharding-JDBC | 分庫分錶組件 | https://shardingsphere.apache.org |
Spring Cloud Alibaba | Cloud Alibaba元件 | https://github.com/alibaba/spring-cloud-alibaba |
Apache Dubbo | RPC服務遠端呼叫框架 | https://github.com/apache/dubbo |
Spring Cloud Gateway | 網關元件 | https://spring.io/projects/spring-cloud-gateway |
Seata | 分散式事務解決方案 | http://seata.io/zh-cn/index.html |
Spring Security OAuth2.0 | OAuth2.0授權組件 | https://spring.io/projects/spring-security-oauth |
GraphQL | 一種用於API 的查詢語言 | https://docs.spring.io/spring-graphql/docs/current/reference/html |
Spring Statemachine | Spring 狀態機 | https://spring.io/projects/spring-statemachine |
Sa-Token | 輕量級權限認證框架 | https://sa-token.cc/ |
Flyway | 資料庫版本控制工具 | https://flywaydb.org/ |
MinIO | 對象儲存服務 | https://min.io/ |
Spring AI | 人工智慧組件 | https://spring.io/projects/spring-ai |
goodsKill |--goodskill-admin ||SpringBoot Admin監控服務端,支援Spring Cloud微服務發現|--goodskill-ai ||AI機器人聊天服務|--goodskill-gateway ||微服務API網關,統一服務鑑權,支援動態路由載入|--goodskill-order-provider ||訂單服務提供者|--goodskill-seckill-provider ||秒殺服務提供者|--goodskill-spring-boot-starter ||專案配置自動組裝|--goodskill-common ||公共服務(目前包含minio上傳下載功能) |--goodskill-web ||提供秒殺模擬介面存取|--goodskill-job ||elastic-job定時任務|--goodskill-seata ||整合nacos+dubbo+shardingjdbc+seata的分散式事務解決方案範例| --goodskill-auth ||auth登入以及授權模組| |--auth-service ||基於Sa-Token框架的使用者登入授權服務|--oauth2-auth-server ||oauth2.0登入授權服務端,自訂的登入授權服務|--oauth2-resource-server ||oauth2.0資源服務端,自訂的登入授權服務
目前實作了幾種秒殺方案,透過SeckillMockController
提供測試介面
聚合網關Openapi文檔位址: http://localhost/doc.html#/home
(需要開啟網關服務)
Spring Boot Admin應用程式監控位址: http://www.goodskill.com:19031
, 登入使用者名稱密碼:user/123456
場景一:Sychronized同步鎖定實現
場景二:Redisson分散式鎖定實現
場景三:ActiveMQ實作(已廢棄)
場景四:Kafka訊息佇列實現
場景五:資料庫原子性更新
場景六:即時等待秒殺處理結果(已廢棄)
場景七:ZooKeeper分散式鎖定
場景八:使用Redis進行秒殺商品減庫存操作,秒殺結束後異步發送MQ,使用MongoDB完成資料落地
場景九:Spring Cloud Stream實現
場景十:Sentinel限流+資料庫原子性更新(需搭配sentinel控制台配置資源名稱limit
的串流規則)
2021-04-14 21:58:59.857 INFO [goodskill-web,df43cc8f59291c48,df43cc8f59291c48] 15808 --- [ main] o.s.w.controller.SeckillMockController : 秒杀场景二(redis分布式锁实现)开始时间:Wed Apr 14 21:58:59 CST 2021,秒杀id:1000
2021-04-14 21:59:00.094 INFO [goodskill-web,144aa7910cca9520,2821cb8d62c5a908] 15808 --- [AClOSzbugzYng-1] o.s.w.s.c.SeckillMockResponseListener : 秒杀活动结束,秒杀场景二(redis分布式锁实现)时间:Wed Apr 14 21:59:00 CST 2021,秒杀id:1000
2021-04-14 21:59:00.101 INFO [goodskill-web,144aa7910cca9520,2821cb8d62c5a908] 15808 --- [AClOSzbugzYng-1] o.s.w.s.c.SeckillMockResponseListener : 最终成功交易笔数统计中。。。
2021-04-14 21:59:01.616 INFO [goodskill-web,144aa7910cca9520,2821cb8d62c5a908] 15808 --- [AClOSzbugzYng-1] o.s.w.s.c.SeckillMockResponseListener : 最终成功交易笔数统计中。。。
2021-04-14 21:59:03.129 INFO [goodskill-web,144aa7910cca9520,2821cb8d62c5a908] 15808 --- [AClOSzbugzYng-1] o.s.w.s.c.SeckillMockResponseListener : 最终成功交易笔数:10
2021-04-14 21:59:03.130 INFO [goodskill-web,144aa7910cca9520,2821cb8d62c5a908] 15808 --- [AClOSzbugzYng-1] o.s.w.s.c.SeckillMockResponseListener : 历史任务耗时统计:StopWatch '': running time = 36159894800 ns
---------------------------------------------
ns % Task name
---------------------------------------------
4492195700 012% 秒杀场景四(kafka消息队列实现)
3164155900 009% 秒杀场景八(秒杀商品存放redis减库存,异步发送秒杀成功MQ,mongoDb数据落地)
6219218300 017% 秒杀场景十(Sentinel限流+数据库原子性更新)
9189080600 025% 秒杀场景七(zookeeper分布式锁)
3135926500 009% 秒杀场景五(数据库原子性更新update set num = num -1)
3342791800 009% 秒杀场景九(基于springcloud stream rabbitmq)
3343433700 009% 秒杀场景一(sychronized同步锁实现)
3273092300 009% 秒杀场景二(redis分布式锁实现)
JDK: OpenJDK21
Sharding-JDBC: 5.5.0
SpringCloud: 2023.xx
SpringBoot: 3.3.x
SpringCloudAlibaba: 2023.xx
Apache Dubbo: 3.3.x
使用的Docker映像
鏡像 | 版本 | 連接埠 | 使用者名稱密碼 |
---|---|---|---|
Nacos | 2.3.2-slim | 8848 | nacos:nacos(控制台) |
Redis | latest | 6379 | 密碼:123456 |
Kafka | 3.1.1 | 9092 | 無 |
KafkaManager | latest | 9001:9000 | 無 |
Mongo | 6.0.7 | 27017 | 無 |
MySQL | 8.0.29 | 3306 | root:Password123 |
Zookeeper | 3.6.2 | 2181 | 無 |
Elasticsearch | 7.17.3 | 9200 9300 | 無 |
Kibana | 7.17.3 | 5601 | 無 |
RabbitMQ | latest | 5672 15672 | 無 |
MinIO | latest | 9000 | root:password |
Seata | 2.0.0 | 7091 8091 | seata:seata(控制台) |
專案根目錄goodsKill
中執行
mvn clean install 或#跳過單元測試mvn clean install -DskipTests
預設連接埠啟動nacos、redis、mysql、rabbitmq、kafka、zookeeper、elasticsearch、seataServer,或使用docker-compose [2]指令:
docker-compose -f goodskill-simple.yml up -d
進入goodskill-web/src/main/sql
目錄,找到seckill.sql
文件,在本機mysql資料庫建立seckill
倉庫並執行完成資料初始化作業
docker-compose啟動MySQL映像時會自動執行初始化腳本,如已執行過上一個步驟可跳過 |
設定host
127.0.0.1 kafka
127.0.0.1 nacos
127.0.0.1 redis
127.0.0.1 mysql
127.0.0.1 zookeeper
127.0.0.1 mongo
127.0.0.1 elasticsearch
127.0.0.1 rabbitmq
127.0.0.1 logstash
##如果网关服务部署在远程机器,此处改为相应的远程机器ip
127.0.0.1 www.goodskill.com
在Nacos配置中心中加入DataId為goodskill-common-connection.yml
(中間件公共配置)、 goodskill-common.yml
(服務公共配置)的公共配置,Group為DEFAULT_GROUP
,具體內容可參考項目根目錄中的goodskill-common-connection.yml
、 goodskill-common.yml
文件
main方法運行OrderApplication
類別(訂單服務)
main方法運行SeckillApplication
類別(秒殺管理服務提供者)
main方法運行SampleWebApplication
類別(模擬秒殺web服務)
發送一個秒殺模擬請求: 秒殺活動id 1000,商品數量10,執行20次購買操作,使用sychronized同步鎖定執行,例如:
可直接使用以下指令發送模擬秒殺請求,每個秒殺活動seckillId對應唯一的一個商品id,每次執行介面時會有一個庫存初始化動作,介面執行完成後可重複調用
curl -X POST " http://www.goodskill.com:8080/sychronized "
-H " accept: */* " -H " Content-Type: application/json " -d
" { " requestCount " : 20, " seckillCount " : 10, " seckillId " : 1000} "
curl -X POST " http://www.goodskill.com:8080/redisson "
-H " accept: */* " -H " Content-Type: application/json " -d
" { " requestCount " : 20, " seckillCount " : 10, " seckillId " : 1000} "
curl --location --request POST ' http://www.goodskill.com:8080/limit '
--header ' User-Agent: apifox/1.0.0 (https://www.apifox.cn) '
--header ' Content-Type: application/json '
--data-raw ' {
"maxPoolSize": 10,
"seckillId": 1000,
"corePoolSize": 2,
"seckillCount": 100,
"requestCount": 120
} '
請求預設非同步執行,可在控制台查看執行日誌,如果最終成功交易筆數等於商品數量10則表示沒有出現超賣或少賣問題
基於Spring AI Alibaba構建的簡易秒殺機器人服務,可以透過機器人服務完成服務調用,目前僅支援開啟秒殺活動,以及輸出活動耗時情況
進入goodskill-ai
模組,替換配置spring.ai.dashscope.api-key
,可透過阿里雲百煉平台取得
main方法運行AiBotApplication
類,訪問聊天頁面http://127.0.0.1:18077
以下是對話範例
我: 帮我执行秒杀
AI: 当然可以帮助您执行秒杀活动啦!为了顺利进行,请告诉我以下几个信息:1.秒杀活动的ID是多少?2. 这次秒杀的商品数量是多少?3.您打算这次请求的次数是多少?有了这些信息,我就能帮您开始了!?
我: 秒杀活动id 1001,请求次数20,商品数量10个
AI: 秒杀活动已成功开启!我们现在等待10秒钟,然后我会为您获取任务的耗时统计信息。秒杀活动已成功启动,并在10秒后获得了任务耗时统计信息:总耗时:6.673773375秒具体耗时分布如下:- 秒杀活动id:1001,秒杀场景五(数据库原子性更新update setnum = num -1)耗时 3.528280125 秒,占比 53%-秒杀活动id:1001,秒杀场景五(数据库原子性更新updateset num = num-1)耗时3.14549325 秒,占比 47%希望这些信息对您有帮助!如果还有其他问题或需要进一步的帮助,请随时告诉我哦!?
在快速開始部分基礎上增加以下步驟即可啟動完整項目
進入goodskill-gateway
模組,透過GatewayBootApplication
類別main方法啟動服務網關,統一透過網關存取各個服務
http://www.goodskill.com/api/order/**
對應訪問goodskill-order
服務
http://www.goodskill.com/api/seata/**
對應造訪goodskill-seata
服務
http://www.goodskill.com/api/seckill/**
對應訪問goodskill-seckill
服務
http://www.goodskill.com/api/auth/**
對應造訪goodskill-auth
服務
http://www.goodskill.com/api/web/**
對應造訪goodskill-web
服務
已整合Sentinel
限流元件,支援nacos
配置中心方式推送限流規則,使用時需啟動Sentinel
控制台,並以18088
埠啟動,docker環境暫不支援。
Seata分散式事務測試方法請參考Seata分散式事務測試範例運行說明
main方法執行GoodskillAdminApplication
類別(微服務健康狀態指標監控)
docker es映像啟動失敗
出現此問題一般為linux環境,執行下列指令即可sysctl -w vm.max_map_count=262144
,或修改/etc/sysctl.conf文件,追加下列設定:
grep vm.max_map_count /etc/sysctl.conf
vm.max_map_count=262144
如何使用本項目自訂的OAuth2.0授權伺服器進行登入授權?
待完善。 。
專案整合的各個框架之間目前的兼容性如何?
本專案目前所依賴的各個主流框架的版本比較新,尚未經過完整測試[3] 。
服務啟動控制台報ERROR日誌no available service found in cluster 'default', please make sure registry config correct and keep your seata server running
如何解決?
啟動seata-server
服務即可(docker-compose.yml檔案中已提供),可參考Seata官網新增nacos相關設定。如未使用分散式事務,可忽略此錯誤,不影響服務正常運作
docker-compose無法拉取鏡像
hub.docker被牆,國內可使用阿里雲鏡像加速器,具體操作請見阿里雲鏡像加速器
使用JDK17以上啟動專案失敗
啟動時加入以下jvm參數,例如:
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/java.util.concurrent=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED
目前秒殺活動狀態的控制是基於Spring Statemachine狀態機實現,使用狀態機的優點:
統一控制活動狀態,方便狀態的集中維護;
防止業務狀態隨意更改,保證狀態的可控更新;
表 | 資料庫 | 是否分庫 | 分庫字段 | 是否分錶 | 分錶字段 |
---|---|---|---|---|---|
success_killed | MySQL | 是(同一伺服器中,分為seckill和seckill_01兩個函式庫) | seckill_id | 是(分為success_killed_0,success_kill_1兩張表格) | user_phone |
? | 其他表均未分庫分錶,預設使用seckill為主庫 |
解決Docker容器連接Kafka 連線失敗問題: https://www.cnblogs.com/hellxz/p/why_cnnect_to_kafka_always_failure.html