go: Bulkheads Pattern

项目结构:

image

 

/*
# 版权所有  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": "深圳转运中心"},
		}
	})
}

  

调用:

# 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()

  

输出:

image

 

posted @ 2026-06-27 22:50  ®Geovin Du Dream Park™  阅读(4)  评论(0)    收藏  举报