可扩展系统设计的黄金法则与Go语言实践|得物技术
一、 引言:为什么需要可扩展的系统?
在软件开发领域,需求变更如同家常便饭。一个缺乏扩展性的系统,往往在面对新功能需求或业务调整时,陷入“改一行代码,崩整个系统”的困境。可扩展性设计的核心目标是:让系统能够以最小的修改成本,适应未来的变化。对于Go语言开发者而言,利用其接口、并发、组合等特性,可以高效构建出适应业务演进的系统。
本文将从架构设计原则、编码实践、架构实现模式、验证指标到演进路线,系统讲解如何设计一个“生长型”系统。
二、可扩展系统的核心设计原则
2.1 开闭原则:对扩展开放,对修改关闭
理论补充:
开闭原则是面向对象设计的基石之一。它要求系统中的模块、类或函数,应该对扩展新功能保持开放,而对修改现有代码保持关闭。这意味着,当需求变更时,我们应通过添加新代码(如新增实现类)来满足需求,而不是修改已有的代码逻辑。
Go语言的实现方式:
Go语言通过接口(Interface)和组合(Composition)特性,天然支持开闭原则。接口定义了稳定的契约,具体实现可以独立变化;组合则允许通过“搭积木”的方式扩展功能,而无需修改原有结构。
示例:数据源扩展
假设我们需要支持从不同数据源(如MySQL、S3)读取数据,核心逻辑是“读取数据”,而具体数据源的实现可能频繁变化。此时,我们可以通过接口定义稳定的读取契约:
// DataSource 定义数据读取的稳定接口(契约)
type DataSource interface {
Read(p []byte) (n int, err error) // 读取数据到缓冲区
Close() error // 关闭数据源
}
// MySQLDataSource 具体实现:MySQL数据源
type MySQLDataSource struct {
db *sql.DB // 依赖MySQL连接
}
func (m *MySQLDataSource) Read(p []byte) (int, error) {
// 实现MySQL数据读取逻辑(如执行查询、填充缓冲区)
return m.db.QueryRow("SELECT data FROM table").Scan(&p)
}
func (m *MySQLDataSource) Close() error {
return m.db.Close() // 关闭数据库连接
}
// S3DataSource 新增实现:S3数据源(无需修改原有代码)
type S3DataSource struct {
client *s3.Client // 依赖AWS S3客户端
bucket string // S3存储桶名
}
func (s *S3DataSource) Read(p []byte) (int, error) {
// 实现S3数据读取逻辑(如下载对象到缓冲区)
obj, err := s.client.GetObject(context.Background(), &s3.GetObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String("data.txt"),
})
if err != nil {
return 0, err
}
defer obj.Body.Close()
return obj.Body.Read(p) // 读取数据到缓冲区
}
func (s *S3DataSource) Close() error {
// S3客户端通常无需显式关闭,可根据需要实现
return nil
}
设计说明:
- DataSource接口定义了所有数据源必须实现的方法(Read和 Close),这是系统的“稳定契约”。
- 当需要新增数据源(如S3)时,只需实现该接口,无需修改现有的MySQL数据源或其他依赖DataSource的代码。
- 这一设计符合开闭原则:系统对扩展(新增S3数据源)开放,对修改(无需改动现有代码)关闭。
2.2 模块化设计:低耦合、高内聚
理论补充:
模块化设计的核心是将系统拆分为独立的功能模块,模块之间通过明确的接口交互。衡量模块化质量的关键指标是:
- 耦合度:模块之间的依赖程度(越低越好)。
- 内聚度:模块内部功能的相关性(越高越好)。
理想情况下,模块应满足“高内聚、低耦合”:模块内部功能高度相关(如订单处理模块仅处理订单相关逻辑),模块之间通过接口通信(如订单模块通过接口调用支付模块,而非直接依赖支付模块的实现)。
Go语言的实现方式:
Go语言通过包(Package)管理模块边界,通过接口隔离依赖。开发者可以通过以下方式提升模块化质量:
- 单一职责原则:每个模块/包仅负责单一功能(如order包处理订单逻辑,payment包处理支付逻辑)。
- 接口隔离:模块间通过小而精的接口交互,避免暴露内部实现细节。
示例:订单模块的模块化设计
// order/order.go:订单核心逻辑(高内聚)
package order
// Order 表示一个订单(核心数据结构)
type Order struct {
ID string
Items []Item
Status OrderStatus
}
// Item 表示订单中的商品项
type Item struct {
ProductID string
Quantity int
Price float64
}
// OrderStatus 订单状态枚举
type OrderStatus string
const (
OrderStatusCreated OrderStatus = "created"
OrderStatusPaid OrderStatus = "paid"
OrderStatusShipped OrderStatus = "shipped"
)
// CalculateTotal 计算订单总金额(核心业务逻辑,无外部依赖)
func (o *Order) CalculateTotal() float64 {
total := 0.0
for _, item := range o.Items {
total += item.Price * float64(item.Quantity)
}
return total
}
// payment/payment.go:支付模块(独立模块)
package payment
// PaymentService 定义支付接口(与订单模块解耦)
type PaymentService interface {
Charge(orderID string, amount float64) error // 支付操作
}
// AlipayService 支付宝支付实现
type AlipayService struct {
client *alipay.Client // 支付宝SDK客户端
}
func (a *AlipayService) Charge(orderID string, amount float64) error {
// 调用支付宝API完成支付
return a.client.TradeAppPay(orderID, amount)
}
设计说明:
- order包专注于订单的核心逻辑(如计算总金额),不依赖任何外部支付实现。
- payment包定义支付接口,具体实现(如支付宝、微信支付)独立存在。
- 订单模块通过PaymentService接口调用支付功能,与具体支付实现解耦。当需要更换支付方式时,只需新增支付实现(如WechatPayService),无需修改订单模块。
三、Go语言的扩展性编码实践
3.1 策略模式:动态切换算法
理论补充:
策略模式(Strategy Pattern)属于行为型设计模式,用于定义一系列算法(策略),并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用它的客户端。
Go语言的实现方式:
Go语言通过接口实现策略的抽象,通过上下文(Context)管理策略的切换。这种模式适用于需要动态选择不同算法的场景(如缓存策略、路由策略)。
示例:缓存策略的动态切换
假设系统需要支持多种缓存(Redis、Memcached),且可以根据业务场景动态切换。通过策略模式,可以将缓存的Get和Set操作抽象为接口,具体实现由不同缓存提供。
// cache/cache.go:缓存策略接口
package cache
// CacheStrategy 定义缓存操作的接口
type CacheStrategy interface {
Get(key string) (interface{}, error) // 从缓存获取数据
Set(key string, value interface{}, ttl time.Duration) error // 向缓存写入数据
}
// redis_cache.go:Redis缓存实现
type RedisCache struct {
client *redis.Client // Redis客户端
ttl time.Duration // 默认过期时间
}
func NewRedisCache(client *redis.Client, ttl time.Duration) *RedisCache {
return &RedisCache{client: client, ttl: ttl}
}
func (r *RedisCache) Get(key string) (interface{}, error) {
return r.client.Get(context.Background(), key).Result()
}
func (r *RedisCache) Set(key string, value interface{}, ttl time.Duration) error {
return r.client.Set(context.Background(), key, value, ttl).Err()
}
// memcached_cache.go:Memcached缓存实现
type MemcachedCache struct {
client *memcache.Client // Memcached客户端
}
func NewMemcachedCache(client *memcache.Client) *MemcachedCache {
return &MemcachedCache{client: client}
}
func (m *MemcachedCache) Get(key string) (interface{}, error) {
item, err := m.client.Get(key)
if err != nil {
return nil, err
}
var value interface{}
if err := json.Unmarshal(item.Value, &value); err != nil {
return nil, err
}
return value, nil
}
func (m *MemcachedCache) Set(key string, value interface{}, ttl time.Duration) error {
data, err := json.Marshal(value)
if err != nil {
return err
}
return m.client.Set(&memcache.Item{
Key: key,
Value: data,
Expiration: int32(ttl.Seconds()),
}).Err()
}
// cache_context.go:缓存上下文(管理策略切换)
type CacheContext struct {
strategy CacheStrategy // 当前使用的缓存策略
}
func NewCacheContext(strategy CacheStrategy) *CacheContext {
return &CacheContext{strategy: strategy}
}
// SwitchStrategy 动态切换缓存策略
func (c *CacheContext) SwitchStrategy(strategy CacheStrategy) {
c.strategy = strategy
}
// Get 使用当前策略获取缓存
func (c *CacheContext) Get(key string) (interface{}, error) {
return c.strategy.Get(key)
}
// Set 使用当前策略写入缓存
func (c *CacheContext) Set(key string, value interface{}, ttl time.Duration) error {
return c.strategy.Set(key, value, ttl)
}
设计说明:
- CacheStrategy接口定义了缓存的核心操作(Get和Set),所有具体缓存实现必须实现该接口。
- RedisCache和MemcachedCache是具体的策略实现,分别封装了Redis和Memcached的底层逻辑。
- CacheContext作为上下文,持有当前使用的缓存策略,并提供SwitchStrategy方法动态切换策略。客户端只需与CacheContext交互,无需关心具体使用的是哪种缓存。
优势:当需要新增缓存类型(如本地内存缓存)时,只需实现CacheStrategy接口,无需修改现有代码;切换缓存策略时,只需调用SwitchStrategy方法,客户端无感知。
3.2 中间件链:可插拔的请求处理流程
理论补充:
中间件(Middleware)是位于请求处理链中的组件,用于实现横切关注点(如日志记录、限流、鉴权)。中间件链模式允许将多个中间件按顺序组合,形成处理流水线,每个中间件可以处理请求、传递请求或终止请求。
Go语言的实现方式:
Go语言通过函数类型(func(http.HandlerFunc) http.HandlerFunc)定义中间件,通过组合多个中间件形成处理链。这种模式灵活且易于扩展,适用于HTTP服务的请求处理。
示例:HTTP中间件链的实现
假设需要为Web服务添加日志记录、限流和鉴权功能,通过中间件链可以将这些功能解耦,按需组合。
// middleware/middleware.go:中间件定义
package middleware
import (
"net/http"
"time"
"golang.org/x/time/rate"
)
// Middleware 定义中间件类型:接收http.HandlerFunc,返回新的http.HandlerFunc
type Middleware func(http.HandlerFunc) http.HandlerFunc
// LoggingMiddleware 日志中间件:记录请求信息
func LoggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// 记录请求方法和路径
println("Request received:", r.Method, r.URL.Path)
// 调用下一个中间件或处理函数
next(w, r)
// 记录请求耗时
println("Request completed in:", time.Since(start))
}
}
// RateLimitMiddleware 限流中间件:限制请求频率
func RateLimitMiddleware(next http.HandlerFunc, limiter *rate.Limiter) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !limiter.Allow() {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
return
}
next(w, r)
}
}
// AuthMiddleware 鉴权中间件:验证请求令牌
func AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token != "valid-token" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next(w, r)
}
}
// chain.go:中间件链组合
func Chain(middlewares ...Middleware) Middleware {
return func(final http.HandlerFunc) http.HandlerFunc {
// 反向组合中间件(确保执行顺序正确)
for i := len(middlewares) - 1; i >= 0; i-- {
final = middlewares[i](final)
}
return final
}
}
使用示例:
// main.go:Web服务入口
package main
import (
"net/http"
"middleware"
"golang.org/x/time/rate"
)
func main() {
// 创建限流器:每秒允许100个请求,突发10个
limiter := rate.NewLimiter(100, 10)
// 定义业务处理函数
handleRequest := func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World"))
}
// 组合中间件链:日志 → 限流 → 鉴权
middlewareChain := middleware.Chain(
middleware.LoggingMiddleware,
middleware.RateLimitMiddlewareWithLimiter(limiter),
middleware.AuthMiddleware,
)
// 应用中间件链到处理函数
http.HandleFunc("/", middlewareChain(handleRequest))
// 启动服务
http.ListenAndServe(":8080", nil)
}
设计说明:
- 每个中间件(如LoggingMiddleware、RateLimitMiddleware)专注于单一功能,通过Middleware类型定义,确保接口统一。
- Chain函数将多个中间件按顺序组合,形成一个处理链。请求会依次经过日志记录、限流、鉴权,最后到达业务处理函数。
- 新增中间件(如CORS跨域中间件)时,只需实现Middleware类型,即可通过Chain函数轻松加入处理链,无需修改现有中间件或业务逻辑。
四、可扩展架构的实现模式
4.1 插件化架构:热插拔的功能扩展
理论补充:
插件化架构允许系统在运行时动态加载、卸载插件,从而实现功能的灵活扩展。这种架构适用于需要支持第三方扩展或多租户定制的场景(如IDE插件、电商平台应用市场)。
Go语言的实现方式:
Go语言通过plugin包支持动态库加载,结合接口定义插件契约,可以实现安全的插件化架构。插件需实现统一的接口,主程序通过接口调用插件功能。
示例:插件化系统的实现
假设需要开发一个支持插件的数据处理系统,主程序可以动态加载处理数据的插件(如csv_parser、json_parser)。
// plugin/interface.go:插件接口定义(主程序与插件共享)
package plugin
// DataProcessor 定义数据处理插件的接口
type DataProcessor interface {
Name() string // 插件名称(如"csv_parser")
Process(input []byte) (output []byte, err error) // 处理数据
}
// plugin/csv_parser/csv_processor.go:CSV处理插件(动态库)
package main
import (
"encoding/csv"
"io"
"os"
"plugin"
)
// CSVProcessor 实现DataProcessor接口
type CSVProcessor struct{}
func (c *CSVProcessor) Name() string {
return "csv_parser"
}
func (c *CSVProcessor) Process(input []byte) ([]byte, error) {
// 解析CSV数据
r := csv.NewReader(bytes.NewReader(input))
records, err := r.ReadAll()
if err != nil {
return nil, err
}
// 转换为JSON格式输出
var result []map[string]string
for _, record := range records {
row := make(map[string]string)
for i, field := range record {
row[fmt.Sprintf("col_%d", i)] = field
}
result = append(result, row)
}
jsonData, err := json.Marshal(result)
if err != nil {
return nil, err
}
return jsonData, nil
}
// 插件的入口函数(必须命名为"Plugin",主程序通过此函数获取插件实例)
var Plugin plugin.DataProcessor = &CSVProcessor{}
// main.go:主程序(加载插件并调用)
package main
import (
"fmt"
"plugin"
"path/filepath"
)
func main() {
// 插件路径(假设编译为so文件)
pluginPath := filepath.Join("plugins", "csv_parser.so")
// 加载插件
p, err := plugin.Open(pluginPath)
if err != nil {
panic(err)
}
// 获取插件实例(通过接口类型断言)
sym, err := p.Lookup("Plugin")
if err != nil {
panic(err)
}
processor, ok := sym.(plugin.DataProcessor)
if !ok {
panic("插件未实现DataProcessor接口")
}
// 使用插件处理数据
inputData := []byte("name,age
张三,20
李四,25")
output, err := processor.Process(inputData)
if err != nil {
panic(err)
}
fmt.Println(string(output)) // 输出JSON格式数据
}
设计说明:
- 接口定义:主程序定义DataProcessor接口,规定插件必须实现的方法(Name和Process)。
- 插件实现:插件(如csv_parser)实现DataProcessor接口,并导出名为Plugin的全局变量(主程序通过此变量获取插件实例)。
- 动态加载:主程序通过plugin.Open加载插件,通过Lookup获取插件实例,并转换为DataProcessor接口调用。
优势:
- 主程序与插件解耦,插件的添加、删除或升级不影响主程序运行。
- 支持热插拔:插件可以在运行时动态加载(需注意Go插件的局限性,如版本兼容性)。
4.2 配置驱动架构:外部化的灵活配置
理论补充:
配置驱动架构(Configuration-Driven Architecture)通过将系统行为参数化,使系统可以通过修改配置(而非代码)来适应不同的运行环境或业务需求。这种架构适用于需要支持多环境(开发、测试、生产)、多租户定制或多场景适配的系统。
Go语言的实现方式:
Go语言通过encoding/json、encoding/yaml等包支持配置文件的解析,结合viper等第三方库可以实现更复杂的配置管理(如环境变量覆盖、热更新)。
示例:配置驱动的数据库连接
假设系统需要支持不同环境(开发、生产)的数据库配置,通过配置文件动态加载数据库连接参数。
// config/config.go:配置结构体定义
package config
// DBConfig 数据库配置
type DBConfig struct {
DSN string `json:"dsn"` // 数据库连接字符串
MaxOpenConn int `json:"max_open_conn"` // 最大打开连接数
MaxIdleConn int `json:"max_idle_conn"` // 最大空闲连接数
ConnTimeout int `json:"conn_timeout"` // 连接超时时间(秒)
}
// AppConfig 应用全局配置
type AppConfig struct {
Env string `json:"env"` // 环境(dev/test/prod)
DB DBConfig `json:"db"` // 数据库配置
Log LogConfig `json:"log"` // 日志配置
}
// LogConfig 日志配置
type LogConfig struct {
Level string `json:"level"` // 日志级别(debug/info/warn/error)
Path string `json:"path"` // 日志文件路径
}
// config/loader.go:配置加载器(支持热更新)
package config
import (
"encoding/json"
"os"
"path/filepath"
"time"
"github.com/fsnotify/fsnotify"
)
// LoadConfig 加载配置文件
func LoadConfig(path string) (*AppConfig, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
var cfg AppConfig
decoder := json.NewDecoder(file)
if err := decoder.Decode(&cfg); err != nil {
return nil, err
}
return &cfg, nil
}
// WatchConfig 监听配置文件变化(热更新)
func WatchConfig(path string, callback func(*AppConfig)) error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
defer watcher.Close()
// 监听配置文件所在目录
dir := filepath.Dir(path)
if err := watcher.Add(dir); err != nil {
return err
}
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
// 仅处理写事件
if event.Op&fsnotify.Write == fsnotify.Write {
// 重新加载配置
newCfg, err := LoadConfig(path)
if err != nil {
println("加载配置失败:", err.Error())
continue
}
// 触发回调(通知其他模块配置已更新)
callback(newCfg)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
println("配置监听错误:", err.Error())
}
}
}()
// 保持程序运行
select {}
}
// main.go:使用配置驱动的数据库连接
package main
import (
"database/sql"
"fmt"
"config"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// 加载初始配置
cfg, err := config.LoadConfig("config.json")
if err != nil {
panic(err)
}
// 初始化数据库连接
db, err := sql.Open("mysql", cfg.DB.DSN)
if err != nil {
panic(err)
}
defer db.Close()
// 设置连接池参数(从配置中读取)
db.SetMaxOpenConns(cfg.DB.MaxOpenConn)
db.SetMaxIdleConns(cfg.DB.MaxIdleConn)
db.SetConnMaxLifetime(time.Duration(cfg.DB.ConnTimeout) * time.Second)
// 启动配置监听(热更新)
go func() {
err := config.WatchConfig("config.json", func(newCfg *config.AppConfig) {
// 配置更新时,重新设置数据库连接池参数
db.SetMaxOpenConns(newCfg.DB.MaxOpenConn)
db.SetMaxIdleConns(newCfg.DB.MaxIdleConn)
db.SetConnMaxLifetime(time.Duration(newCfg.DB.ConnTimeout) * time.Second)
fmt.Println("配置已更新,数据库连接池参数调整")
})
if err != nil {
panic(err)
}
}()
// 业务逻辑...
}
设计说明:
- 配置结构化:通过AppConfig、DBConfig等结构体定义配置的层次结构,确保配置的清晰性和可维护性。
- 热更新支持:通过fsnotify监听配置文件变化,触发回调函数重新加载配置,并更新系统状态(如数据库连接池参数)。
- 多环境适配:通过不同的配置文件(如config-dev.json、config-prod.json)或环境变量覆盖,实现不同环境的配置隔离。
优势:
- 系统行为的调整无需修改代码,只需修改配置文件,降低了维护成本。
- 支持动态调整关键参数(如数据库连接池大小、日志级别),提升了系统的灵活性和可观测性。
五、可扩展性的验证与演进
5.1 扩展性验证指标
为了确保系统具备良好的扩展性,需要从多个维度进行验证。以下是关键指标及测量方法:
指标 |
测量方法 |
目标值 |
新功能开发周期 |
统计新增一个中等复杂度功能所需的时间(包括设计、编码、测试) |
< 2人日 |
修改影响范围 |
统计修改一个功能时,需要修改的模块数量和代码行数 |
< 5个模块,< 500行代码 |
配置生效延迟 |
测量配置变更到系统完全应用新配置的时间 |
< 100ms |
并发扩展能力 |
测量系统在增加CPU核数时,吞吐量的增长比例(理想为线性增长) |
吞吐量增长 ≥ 核数增长 × 80% |
插件加载时间 |
测量动态加载一个插件的时间 |
< 1秒 |
5.2 扩展性演进路线
系统的扩展性不是一蹴而就的,需要随着业务的发展逐步演进。以下是一个典型的演进路线:
graph TD
A[单体架构] -->|垂直拆分| B[核心服务+支撑服务]
B -->|接口抽象| C[模块化架构]
C -->|策略模式/中间件| D[可扩展的分布式架构]
D -->|插件化/配置驱动| E[云原生可扩展架构]
- 阶段1:单体架构:初期业务简单,系统以单体形式存在。此时应注重代码的可读性和可维护性,为后续扩展打下基础。
- 阶段2:核心服务+支撑服务:随着业务增长,将核心功能(如订单、用户)与非核心功能(如日志、监控)拆分,降低耦合。
- 阶段3:模块化架构:通过接口抽象和依赖倒置,将系统拆分为高内聚、低耦合的模块,支持独立开发和部署。
- 阶段4:可扩展的分布式架构:引入策略模式、中间件链等模式,支持动态切换算法和处理流程,适应多样化的业务需求。
- 阶段5:云原生可扩展架构:结合容器化(Docker)、编排(Kubernetes)和Serverless技术,实现资源的弹性扩展和自动伸缩。
六、结 语
可扩展性设计是软件系统的“生命力”所在。通过遵循开闭原则、模块化设计等核心原则,结合策略模式、中间件链、插件化架构等Go语言友好的编码模式,开发者可以构建出适应业务变化的“生长型”系统。
需要注意的是,扩展性设计并非追求“过度设计”,而是在当前需求和未来变化之间找到平衡。建议定期进行架构评审,通过压力测试和代码分析(如go mod graph查看模块依赖)评估系统的扩展性健康度,及时调整设计策略。
最后,记住:优秀的系统不是完美的,而是能够持续进化的。保持开放的心态,拥抱变化,才能在快速发展的技术领域中立于不败之地。
往期回顾
1. 得物新商品审核链路建设分享
2. 营销会场预览直通车实践|得物技术
3. 基于TinyMce富文本编辑器的客服自研知识库的技术探索和实践|得物技术
4. AI质量专项报告自动分析生成|得物技术
5. Rust 性能提升“最后一公里”:详解 Profiling 瓶颈定位与优化|得物技术
文 / 悟
关注得物技术,每周更新技术干货
要是觉得文章对你有帮助的话,欢迎评论转发点赞~
未经得物技术许可严禁转载,否则依法追究法律责任。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
如何基于 SpringBoot 快速构建 Apache Pulsar 实时应用
Spring Boot Starter Pulsar [1] 是Spring 官方为 Apache Pulsar 开发的构建项目,该项目允许开发者轻松集成 Pulsar 客户端,并通过 Spring Boot 的方式,快速构建和开发 Pulsar 应用程序。 本文将带领大家基于SpringBoot 快速构建一个 Pulsar 实时应用。 快速开始 准备一个Pulsar Standalone 集群 Pulsar 支持 Standalone 模式启动服务,并且功能与集群模式几乎一致,我们可以据此快速搭建测试服务。 参考:Run a standalone Pulsar cluster locally[2] 下载Pulsar 二进制包(本文以 3.0.7 LTS版本示例): Apache 地址:https://archive.apache.org/dist/pulsar/ 腾讯云镜像:https://mirrors.cloud.tencent.com/apache/pulsar/ 阿里云镜像:https://mirrors.aliyun.com/apache/pulsar/ 下载二进制包 wg...
-
下一篇
基于 Apache Pulsar 构建统一消息流 PaaS 平台
作者:翟佳,AscentStream 谙流科技联合创始人兼 CEO,Apache Pulsar PMC 成员,Apache软件基金会成员。 注:此篇 《基于 Apache Pulsar 构建统一消息流 PaaS 平台》为翟佳老师在 Apache PulsarMeetup 北京 2024 大会演讲的转录文字,经社区志愿者赵国瑞 ronnie 编辑修改完成,强烈推荐阅读。 Apache Pulsar 社区简介 近年来,消息流和分布式基础设施领域的进步吸引了广泛的关注。自 20 世纪 80 年代和 90 年代 IBM 等公司的早期产品,到 2000 年代初的开源项目,再到 2007 年大数据和分布式系统的兴起,消息系统经历了几轮技术革新。Kafka、RocketMQ 等分布式消息系统的崛起,正是为了满足用户日益增长和变化的需求。 在这样的技术演进背景下,Apache Pulsar 应运而生。它起源于 2012 年的雅虎实验室,并于 2017 年正式对外开源。Pulsar 的诞生恰逢云原生时代的到来,它凭借先进的设计和强大的功能,迅速赢得了开源社区和众多技术专家的青睐,成为了分布式消息系统领域...
相关文章
文章评论
共有0条评论来说两句吧...