feat(cache): 优化缓存系统并重构数据库连接管理
- 将Redis连接方式改为连接池模式,提升连接复用效率 - 修复缓存注释错误,统一标识数据库缓存逻辑 - 添加数据检索结果非空验证,避免空指针异常 - 在数据库操作中添加读写锁保护,确保并发安全性 - 实现数据库查询和执行操作的重试机制,增强稳定性 - 更新配置文件中的缓存和数据库设置,优化缓存策略 - 重构README文档,补充框架特性和性能测试数据 - 添加示例路由配置,完善快速入门指南
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 压测配置
|
||||
type BenchConfig struct {
|
||||
URL string // 测试URL
|
||||
Concurrency int // 并发数
|
||||
Duration time.Duration // 持续时间
|
||||
Timeout time.Duration // 请求超时时间
|
||||
}
|
||||
|
||||
// 压测结果
|
||||
type BenchResult struct {
|
||||
TotalRequests int64 // 总请求数
|
||||
SuccessRequests int64 // 成功请求数
|
||||
FailedRequests int64 // 失败请求数
|
||||
TotalDuration time.Duration // 总耗时
|
||||
MinLatency time.Duration // 最小延迟
|
||||
MaxLatency time.Duration // 最大延迟
|
||||
AvgLatency time.Duration // 平均延迟
|
||||
QPS float64 // 每秒请求数
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("==========================================")
|
||||
fmt.Println(" HoTime 框架性能压力测试")
|
||||
fmt.Println("==========================================")
|
||||
fmt.Println()
|
||||
|
||||
// 测试配置
|
||||
configs := []BenchConfig{
|
||||
{
|
||||
URL: "http://127.0.0.1:8081/app/test/hello",
|
||||
Concurrency: 10,
|
||||
Duration: 10 * time.Second,
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
{
|
||||
URL: "http://127.0.0.1:8081/app/test/hello",
|
||||
Concurrency: 50,
|
||||
Duration: 10 * time.Second,
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
{
|
||||
URL: "http://127.0.0.1:8081/app/test/hello",
|
||||
Concurrency: 100,
|
||||
Duration: 10 * time.Second,
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
{
|
||||
URL: "http://127.0.0.1:8081/app/test/hello",
|
||||
Concurrency: 200,
|
||||
Duration: 10 * time.Second,
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
// 先检查服务是否可用
|
||||
fmt.Println("正在检查服务是否可用...")
|
||||
if !checkService(configs[0].URL) {
|
||||
fmt.Println("❌ 服务不可用,请先启动示例应用:")
|
||||
fmt.Println(" cd example && go run main.go")
|
||||
return
|
||||
}
|
||||
fmt.Println("✅ 服务已就绪")
|
||||
fmt.Println()
|
||||
|
||||
// 执行压测
|
||||
for i, config := range configs {
|
||||
fmt.Printf("【测试 %d】并发数: %d, 持续时间: %v\n", i+1, config.Concurrency, config.Duration)
|
||||
fmt.Println("------------------------------------------")
|
||||
|
||||
result := runBenchmark(config)
|
||||
printResult(result)
|
||||
fmt.Println()
|
||||
|
||||
// 测试间隔,让服务恢复
|
||||
if i < len(configs)-1 {
|
||||
fmt.Println("等待 3 秒后开始下一轮测试...")
|
||||
time.Sleep(3 * time.Second)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("==========================================")
|
||||
fmt.Println(" 压力测试完成")
|
||||
fmt.Println("==========================================")
|
||||
}
|
||||
|
||||
// 检查服务是否可用
|
||||
func checkService(url string) bool {
|
||||
client := &http.Client{Timeout: 3 * time.Second}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return resp.StatusCode == 200
|
||||
}
|
||||
|
||||
// 执行压测
|
||||
func runBenchmark(config BenchConfig) BenchResult {
|
||||
var (
|
||||
totalRequests int64
|
||||
successRequests int64
|
||||
failedRequests int64
|
||||
totalLatency int64 // 纳秒
|
||||
minLatency int64 = int64(time.Hour)
|
||||
maxLatency int64
|
||||
mu sync.Mutex
|
||||
)
|
||||
|
||||
// 创建HTTP客户端
|
||||
client := &http.Client{
|
||||
Timeout: config.Timeout,
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConns: config.Concurrency * 2,
|
||||
MaxIdleConnsPerHost: config.Concurrency * 2,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
// 控制退出
|
||||
done := make(chan struct{})
|
||||
var wg sync.WaitGroup
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
// 启动并发goroutine
|
||||
for i := 0; i < config.Concurrency; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
default:
|
||||
reqStart := time.Now()
|
||||
success := makeRequest(client, config.URL)
|
||||
latency := time.Since(reqStart).Nanoseconds()
|
||||
|
||||
atomic.AddInt64(&totalRequests, 1)
|
||||
atomic.AddInt64(&totalLatency, latency)
|
||||
|
||||
if success {
|
||||
atomic.AddInt64(&successRequests, 1)
|
||||
} else {
|
||||
atomic.AddInt64(&failedRequests, 1)
|
||||
}
|
||||
|
||||
// 更新最小/最大延迟
|
||||
mu.Lock()
|
||||
if latency < minLatency {
|
||||
minLatency = latency
|
||||
}
|
||||
if latency > maxLatency {
|
||||
maxLatency = latency
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 等待指定时间
|
||||
time.Sleep(config.Duration)
|
||||
close(done)
|
||||
wg.Wait()
|
||||
|
||||
totalDuration := time.Since(startTime)
|
||||
|
||||
// 计算结果
|
||||
result := BenchResult{
|
||||
TotalRequests: totalRequests,
|
||||
SuccessRequests: successRequests,
|
||||
FailedRequests: failedRequests,
|
||||
TotalDuration: totalDuration,
|
||||
MinLatency: time.Duration(minLatency),
|
||||
MaxLatency: time.Duration(maxLatency),
|
||||
}
|
||||
|
||||
if totalRequests > 0 {
|
||||
result.AvgLatency = time.Duration(totalLatency / totalRequests)
|
||||
result.QPS = float64(totalRequests) / totalDuration.Seconds()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 发起单个请求
|
||||
func makeRequest(client *http.Client, url string) bool {
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证响应
|
||||
if resp.StatusCode != 200 {
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证JSON格式
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证返回状态
|
||||
if status, ok := result["status"].(float64); !ok || status != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 打印结果
|
||||
func printResult(result BenchResult) {
|
||||
successRate := float64(result.SuccessRequests) / float64(result.TotalRequests) * 100
|
||||
|
||||
fmt.Printf("总请求数: %d\n", result.TotalRequests)
|
||||
fmt.Printf("成功请求: %d\n", result.SuccessRequests)
|
||||
fmt.Printf("失败请求: %d\n", result.FailedRequests)
|
||||
fmt.Printf("成功率: %.2f%%\n", successRate)
|
||||
fmt.Printf("总耗时: %v\n", result.TotalDuration.Round(time.Millisecond))
|
||||
fmt.Printf("QPS: %.2f 请求/秒\n", result.QPS)
|
||||
fmt.Printf("最小延迟: %v\n", result.MinLatency.Round(time.Microsecond))
|
||||
fmt.Printf("最大延迟: %v\n", result.MaxLatency.Round(time.Microsecond))
|
||||
fmt.Printf("平均延迟: %v\n", result.AvgLatency.Round(time.Microsecond))
|
||||
|
||||
// 性能评级
|
||||
fmt.Print("性能评级: ")
|
||||
switch {
|
||||
case result.QPS >= 10000:
|
||||
fmt.Println("🚀 优秀 (QPS >= 10000)")
|
||||
case result.QPS >= 5000:
|
||||
fmt.Println("⭐ 良好 (QPS >= 5000)")
|
||||
case result.QPS >= 2000:
|
||||
fmt.Println("👍 中等 (QPS >= 2000)")
|
||||
case result.QPS >= 1000:
|
||||
fmt.Println("📊 一般 (QPS >= 1000)")
|
||||
default:
|
||||
fmt.Println("⚠️ 需优化 (QPS < 1000)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user