MyBilibili 抽象层设计:基础设施可插拔

MyBilibili 抽象层设计:基础设施可插拔 MyBilibili 抽象层设计基础设施可插拔1. 设计目标1.1 为什么需要抽象层当前 MyBilibili 微服务版本直接依赖 Spring Cloud Alibaba 具体实现组件当前绑定问题RocketMQTemplateRocketMQ换 MQ 要改业务代码FeignClientFeign换 RPC 要改业务代码NacosDiscoveryNacos换注册中心要改业务代码RedisTemplateRedis换缓存要改业务代码业务代码和基础设施强耦合导致无法在弱设备部署Nacos/RocketMQ 太重无法切换实现嵌入式 vs 企业级语言锁定Spring 生态绑定 Java1.2 抽象原则接口定义每个基础设施组件定义标准接口多实现每个接口有多个实现嵌入式/轻量/企业级配置驱动通过配置文件选择实现零业务侵入业务代码只依赖接口不依赖实现测试友好内存实现用于单元测试2. 核心接口定义2.1 ServiceDiscovery服务发现/注册职责服务注册、服务发现、健康检查// ServiceDiscovery 服务发现接口typeServiceDiscoveryinterface{// Register 注册当前服务实例Register(ctx context.Context,instance ServiceInstance)error// Deregister 注销当前服务实例Deregister(ctx context.Context)error// Discover 根据服务名发现可用实例Discover(ctx context.Context,serviceNamestring)([]ServiceInstance,error)// Watch 监听服务变化Watch(ctx context.Context,serviceNamestring)(-chan[]ServiceInstance,error)// Healthy 上报当前实例健康状态Healthy(ctx context.Context)error}typeServiceInstancestruct{ServiceNamestringInstanceIDstringHoststringPortintMetadatamap[string]stringHealthybool}实现列表实现类型适用场景配置参数FileDiscovery文件嵌入式/单机configPathEtcdDiscoveryetcdK8s 标准云原生endpoints, prefixNacosDiscoveryNacos现有系统兼容serverAddr, namespaceMemoryDiscovery内存单元测试无2.2 MessageQueue消息队列职责消息发布/订阅、任务队列、事件广播// MessageQueue 消息队列接口typeMessageQueueinterface{// Publish 发布消息到主题Publish(ctx context.Context,topicstring,msg Message)error// Subscribe 订阅主题返回消息通道Subscribe(ctx context.Context,topicstring,groupstring)(-chanMessage,error)// Ack 确认消息已处理Ack(ctx context.Context,topicstring,msg Message)error// Nack 消息处理失败重新投递Nack(ctx context.Context,topicstring,msg Message)error// Enqueue 入队延迟/任务队列Enqueue(ctx context.Context,queuestring,msg Message,delay time.Duration)error// Close 关闭连接Close()error}typeMessagestruct{IDstringTopicstringKeystringPayload[]byteTimestamp time.Time RetryCountint}实现列表实现类型适用场景配置参数MemoryQueue内存单元测试/单机无RedisStreamQueueRedis Stream轻量无需额外组件redisAddr, streamPrefixRocketMQQueueRocketMQ企业级兼容nameServer, groupNATSQueueNATS高性能轻量url, subjectPrefixRedis Stream 实现说明使用 Stream主题 Consumer Group消费者组单消费者XADD / XREADGROUP多消费者XGROUP负载均衡延迟队列Sorted Set 时间戳 定时扫描2.3 CacheStore缓存职责缓存读写、分布式锁、限流计数// CacheStore 缓存接口typeCacheStoreinterface{// Get 读取缓存Get(ctx context.Context,keystring)([]byte,error)// Set 写入缓存Set(ctx context.Context,keystring,value[]byte,ttl time.Duration)error// Delete 删除缓存Delete(ctx context.Context,keystring)error// Lock 获取分布式锁Lock(ctx context.Context,keystring,ttl time.Duration)(bool,error)// Unlock 释放分布式锁Unlock(ctx context.Context,keystring)error// Incr 原子自增限流/计数Incr(ctx context.Context,keystring,ttl time.Duration)(int64,error)// Close 关闭连接Close()error}实现列表实现类型适用场景配置参数MemoryCache内存单元测试/单机maxItemsSQLiteCacheSQLite嵌入式持久化path, tableRedisCacheRedis分布式标准addr, password, dbBoltDBCacheBoltDB嵌入式 KVpath2.4 ServiceCaller服务间调用职责RPC 调用、负载均衡、超时重试// ServiceCaller 服务间调用接口typeServiceCallerinterface{// Call 同步调用Call(ctx context.Context,targetstring,methodstring,req[]byte)([]byte,error)// CallStream 流式调用SSE/长连接CallStream(ctx context.Context,targetstring,methodstring,req[]byte)(-chan[]byte,error)// Close 关闭连接池Close()error}实现列表实现类型适用场景配置参数GRPCClientgRPC跨语言标准registry, timeout, retriesHTTPClientHTTP/JSON简单服务baseURL, timeoutMemoryCaller内存单元测试routergRPC 实现说明服务发现对接 ServiceDiscovery 自动发现负载均衡round-robin / 加权超时默认 3s可配置重试幂等方法自动重试 3 次服务名 → 地址映射service://core/user.GetUser2.5 StorageService文件存储职责文件上传/下载、对象存储、访问控制// StorageService 文件存储接口typeStorageServiceinterface{// Put 上传文件Put(ctx context.Context,bucketstring,keystring,data[]byte,contentTypestring)error// Get 下载文件Get(ctx context.Context,bucketstring,keystring)([]byte,error)// Delete 删除文件Delete(ctx context.Context,bucketstring,keystring)error// GetURL 获取访问 URL可能是签名 URLGetURL(ctx context.Context,bucketstring,keystring,expire time.Duration)(string,error)// Head 检查文件是否存在Head(ctx context.Context,bucketstring,keystring)(bool,error)}实现列表实现类型适用场景配置参数LocalStorage本地文件嵌入式/单机rootPath, baseURLMinioStorageMinIO轻量对象存储endpoint, accessKey, secretKeyS3StorageAWS S3云上标准region, bucket, credentials注意现有代码已有 StorageService 抽象且已有 MinioStorageService 实现说明此层已先行实践模式正确。2.6 SearchEngine搜索职责全文索引、搜索、推荐排序// SearchEngine 搜索引擎接口typeSearchEngineinterface{// Index 建立/更新索引Index(ctx context.Context,indexstring,docIDstring,docinterface{})error// Delete 删除索引Delete(ctx context.Context,indexstring,docIDstring)error// Search 搜索Search(ctx context.Context,indexstring,querystring,opts SearchOptions)(*SearchResult,error)// Reindex 重建索引Reindex(ctx context.Context,indexstring)error}实现列表实现类型适用场景配置参数BleveSearchBleve嵌入式 GoindexPathSQLiteFTSSearchSQLite FTS嵌入式轻量path, tableElasticSearchES企业级addresses2.7 DocumentStore文档存储职责非结构化/半结构化文档存储// DocumentStore 文档存储接口typeDocumentStoreinterface{Insert(ctx context.Context,collectionstring,docinterface{})(string,error)FindByID(ctx context.Context,collectionstring,idstring)(interface{},error)Update(ctx context.Context,collectionstring,idstring,docinterface{})errorDelete(ctx context.Context,collectionstring,idstring)errorQuery(ctx context.Context,collectionstring,filtermap[string]interface{},page Page)([]interface{},error)}实现列表实现类型适用场景SQLiteDocumentSQLite JSON嵌入式MongoDocumentMongoDB企业级3. 工厂与配置3.1 工厂函数模式每个抽象层提供工厂函数根据配置创建对应实现funcNewServiceDiscovery(cfg Config)(ServiceDiscovery,error){switchcfg.Type{casefile:returnNewFileDiscovery(cfg)caseetcd:returnNewEtcdDiscovery(cfg)casenacos:returnNewNacosDiscovery(cfg)casememory:returnNewMemoryDiscovery()default:returnnil,fmt.Errorf(unknown servicediscovery type: %s,cfg.Type)}}3.2 统一配置结构infrastructure:servicediscovery:type:etcd# etcd / nacos / file / memoryendpoints:[http://localhost:2379]prefix:/servicesmessagequeue:type:redis-stream# redis-stream / rocketmq / nats / memoryredisAddr:localhost:6379streamPrefix:mqcachestore:type:redis# redis / sqlite / boltdb / memoryaddr:localhost:6379password:db:0servicecaller:type:grpc# grpc / http / memorytimeout:3sretries:3storageservice:type:minio# local / minio / s3endpoint:localhost:9000accessKey:secretKey:searchengine:type:bleve# bleve / elasticsearchindexPath:/var/data/search.blevedocumentstore:type:sqlite# sqlite / mongodbpath:/var/data/app.db3.3 配置切换效果场景配置说明Android 盒子sqlite memory redis-stream全轻量零外部依赖Redis 可本机起老电脑sqlite redisRedis 起本机云服务器mysql redis etcd标准分布式单元测试memory memory memory全内存4. 与现有代码的映射4.1 替换清单现有组件新接口改造点RocketMQTemplateMessageQueue业务代码改调 MessageQueueFeignClientServiceCallerController 层替换为 gRPC 调用NacosDiscoveryServiceDiscovery启动注册逻辑替换RedisTemplateCacheStore缓存/限流/锁替换MinioStorageServiceStorageService已有标准化接口ElasticsearchTemplateSearchEngine搜索服务替换4.2 改造原则先抽接口再换实现先定义接口让业务依赖接口最后替换实现一个服务一个 PR每个服务独立迁移可回滚配置先行先支持配置切换默认保持原实现Nacos/RocketMQ跑通后再切兼容层过渡必要时写适配器Adapter让旧实现走新接口5. 抽象层好处总结弱设备可部署全轻量组件组合SQLite Redis Stream 内存企业级可用切配置即换 etcd RocketMQ ES语言不锁定接口是语言中立的Go/Java 都能实现测试容易全内存实现单元测试零依赖渐进迁移配置驱动一个服务一个服务切随时回滚