go: Bulkheads Pattern

项目结构:

Go 复制代码
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bulkheads Pattern 舱壁模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/27 22:36
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : config.go
*/
package config
 
// 舱壁配置:各业务域独立并发数、超时时间
var BulkheadConfig = map[string]BulkheadConf{
    "inventory": {MaxWorkers: 2, Timeout: 3}, // 库存:2并发,3秒超时
    "order":     {MaxWorkers: 3, Timeout: 3}, // 订单:3并发
    "logistics": {MaxWorkers: 2, Timeout: 3}, // 物流:2并发
}
 
type BulkheadConf struct {
    MaxWorkers int
    Timeout    int
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bulkheads Pattern 舱壁模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/27 22:37
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : logger.go
*/
package common
 
import (
    "log"
    "os"
)
 
var Logger = log.New(os.Stdout, "[Jewelry] ", log.LstdFlags|log.Lmsgprefix)
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bulkheads Pattern 舱壁模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/27 22:37
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : errors.go
*/
package core
 
import "errors"
 
var ErrBulkheadTimeout = errors.New("舱壁执行超时,已隔离保护")
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bulkheads Pattern 舱壁模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/27 22:38
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : bulkhead.go
*/
package core
 
import (
    "context"
    "time"
)
 
// Bulkhead 舱壁:隔离并发、超时、故障
type Bulkhead struct {
    sem     chan struct{} // 信号量:控制并发
    timeout time.Duration
}
 
func NewBulkhead(maxWorkers int, timeoutSec int) *Bulkhead {
    return &Bulkhead{
        sem:     make(chan struct{}, maxWorkers),
        timeout: time.Duration(timeoutSec) * time.Second,
    }
}
 
// Execute 带舱壁隔离 + 超时执行
func (b *Bulkhead) Execute(fn func() interface{}) interface{} {
    // 并发限流
    b.sem <- struct{}{}
    defer func() { <-b.sem }()
 
    // 超时控制
    ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
    defer cancel()
 
    // 执行结果通道
    done := make(chan interface{}, 1)
 
    go func() {
        defer func() { recover() }()
        done <- fn()
    }()
 
    select {
    case <-ctx.Done():
        return map[string]interface{}{"success": false, "code": 504, "msg": ErrBulkheadTimeout.Error()}
    case res := <-done:
        return res
    }
}
 
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bulkheads Pattern 舱壁模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/27 22:40
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : service.go
*/
package inventory
 
import (
    "godesginpattern/bulkheads/common"
    "godesginpattern/bulkheads/config"
    "godesginpattern/bulkheads/core"
    "time"
)
 
var bulkhead = core.NewBulkhead(
    config.BulkheadConfig["inventory"].MaxWorkers,
    config.BulkheadConfig["inventory"].Timeout,
)
 
type InventoryService struct{}
 
// QueryGemStock 查询宝石库存(模拟超时故障)
func (i *InventoryService) QueryGemStock(jewelryID string) interface{} {
    return bulkhead.Execute(func() interface{} {
        common.Logger.Println("查询珠宝库存 ID:", jewelryID)
        time.Sleep(5 * time.Second) // 故意超时
        return map[string]interface{}{
            "success": true, "code": 200,
            "data": map[string]interface{}{"jewelry_id": jewelryID, "stock": 15},
        }
    })
}
 
// QueryGoldStock 查询黄金库存(正常)
func (i *InventoryService) QueryGoldStock(jewelryID string) interface{} {
    return bulkhead.Execute(func() interface{} {
        common.Logger.Println("查询黄金库存 ID:", jewelryID)
        time.Sleep(300 * time.Millisecond)
        return map[string]interface{}{
            "success": true, "code": 200,
            "data": map[string]interface{}{"jewelry_id": jewelryID, "stock": 32},
        }
    })
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bulkheads Pattern 舱壁模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/27 22:40
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : service.go
*/
package order
 
import (
    "godesginpattern/bulkheads/common"
    "godesginpattern/bulkheads/config"
    "godesginpattern/bulkheads/core"
    "time"
)
 
var bulkhead = core.NewBulkhead(
    config.BulkheadConfig["order"].MaxWorkers,
    config.BulkheadConfig["order"].Timeout,
)
 
type OrderService struct{}
 
func (o *OrderService) CreateOrder(orderNo string, amount float64, userID string) interface{} {
    return bulkhead.Execute(func() interface{} {
        common.Logger.Println("创建订单:", orderNo, "用户:", userID)
        time.Sleep(500 * time.Millisecond)
        return map[string]interface{}{
            "success": true, "code": 200,
            "data": map[string]interface{}{"order_no": orderNo, "status": "待支付"},
        }
    })
}
 
func (o *OrderService) OrderSettle(orderNo, channel string) interface{} {
    return bulkhead.Execute(func() interface{} {
        common.Logger.Println("订单结算:", orderNo, "渠道:", channel)
        time.Sleep(400 * time.Millisecond)
        return map[string]interface{}{
            "success": true, "code": 200,
            "data": map[string]interface{}{"order_no": orderNo, "pay_status": "已支付"},
        }
    })
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bulkheads Pattern 舱壁模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/27 22:41
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : service.go
*/
package logistics
 
import (
    "godesginpattern/bulkheads/common"
    "godesginpattern/bulkheads/config"
    "godesginpattern/bulkheads/core"
    "time"
)
 
var bulkhead = core.NewBulkhead(
    config.BulkheadConfig["logistics"].MaxWorkers,
    config.BulkheadConfig["logistics"].Timeout,
)
 
type LogisticsService struct{}
 
func (l *LogisticsService) ShipJewelry(orderNo, addr string) interface{} {
    return bulkhead.Execute(func() interface{} {
        common.Logger.Println("订单发货:", orderNo, "地址:", addr)
        time.Sleep(400 * time.Millisecond)
        return map[string]interface{}{
            "success": true, "code": 200,
            "data": map[string]interface{}{"order_no": orderNo, "express_no": "SF123456"},
        }
    })
}
 
func (l *LogisticsService) TrackExpress(expressNo string) interface{} {
    return bulkhead.Execute(func() interface{} {
        common.Logger.Println("查询物流:", expressNo)
        time.Sleep(200 * time.Millisecond)
        return map[string]interface{}{
            "success": true, "code": 200,
            "data": map[string]interface{}{"express_no": expressNo, "location": "深圳转运中心"},
        }
    })
}

调用:

Go 复制代码
# encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bulkheads Pattern 舱壁模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : PyCharm 2024.3.6 python 3.11
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/26 23:31
# User      :  geovindu
# Product   : PyCharm
# Project   : pydesginpattern
# File      : BulkheadsBll.py
import threading
import time
from BulkheadsPattern.common.logger import logger
from BulkheadsPattern.business.inventory.inventory_service import InventoryService, inventory_bulkhead
from BulkheadsPattern.business.order_pay.order_service import OrderPayService, order_bulkhead
from BulkheadsPattern.business.logistics.logistics_service import LogisticsService, logistics_bulkhead
 
 
class BulkheadsBll(object):
    """
 
    """
    # 实例化各业务服务
    inv_svc = InventoryService()
    ord_svc = OrderPayService()
    log_svc = LogisticsService()
 
    def run_scene(self):
        """模拟珠宝门店高并发流量场景"""
        logger.info("===== 珠宝行业舱壁模式压测开始 =====")
        start = time.time()
 
        task_list = [
            # 库存域(会超时故障)
            threading.Thread(target=lambda: logger.info(self.inv_svc.query_gem_stock("D001"))),
            threading.Thread(target=lambda: logger.info(self.inv_svc.query_gem_stock("D002"))),
            # 库存正常接口
            threading.Thread(target=lambda: logger.info(self.inv_svc.query_gold_stock("G001"))),
            # 订单支付域
            threading.Thread(target=lambda: logger.info(self.ord_svc.create_order("O2026062601", 16888, "U10086"))),
            threading.Thread(target=lambda: logger.info(self.ord_svc.create_order("O2026062602", 9999, "U10087"))),
            threading.Thread(target=lambda: logger.info(self.ord_svc.order_settle("O2026062601", "微信支付"))),
            # 物流域
            threading.Thread(target=lambda: logger.info(self.log_svc.ship_jewelry("O2026062601", "深圳福田珠宝大厦"))),
            threading.Thread(target=lambda: logger.info(self.log_svc.track_express("SF12345678"))),
        ]
 
        # 启动所有并发任务
        for t in task_list:
            t.start()
        for t in task_list:
            t.join()
 
        cost = round(time.time() - start, 2)
        logger.info(f"===== 压测结束,总耗时 {cost}s =====")
 
    def run_example(self):
        """
 
        :return:
        """
        try:
            self.run_scene()
        finally:
            # 优雅释放所有舱壁线程池资源
            inventory_bulkhead.shutdown()
            order_bulkhead.shutdown()
            logistics_bulkhead.shutdown()
            logger.info("所有舱壁线程池已安全关闭")
 
    @staticmethod
    def demo():
        bll = BulkheadsBll()
        bll.run_example()

输出: