feat(db): implement read-write splitting for postgres
Add support for database read replicas using the GORM dbresolver plugin. This allows for scaling read operations by distributing them across one or multiple replica nodes. - Update `DatabaseConfig` to support single and multiple replica configurations. - Add configuration options for replica connection pooling and selection policy. - Integrate `dbresolver` in the database initialization process for PostgreSQL. - Add helper methods to aggregate replica configurations.
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"gorm.io/plugin/dbresolver"
|
||||
|
||||
"with_you/internal/config"
|
||||
)
|
||||
@@ -63,6 +64,40 @@ func NewDB(cfg *config.DatabaseConfig) (*gorm.DB, error) {
|
||||
sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
|
||||
}
|
||||
|
||||
// 配置读写分离(仅 PostgreSQL 且配置了读副本时生效)
|
||||
if (cfg.Type == "postgres" || cfg.Type == "postgresql") && cfg.HasReplica() {
|
||||
allReplicas := cfg.AllReplicas()
|
||||
replicaDialectors := make([]gorm.Dialector, len(allReplicas))
|
||||
for i, replica := range allReplicas {
|
||||
replicaDialectors[i] = postgres.Open(replica.DSN())
|
||||
}
|
||||
|
||||
replicaMaxIdle := cfg.ReplicaMaxIdle
|
||||
if replicaMaxIdle == 0 {
|
||||
replicaMaxIdle = cfg.MaxIdleConns
|
||||
}
|
||||
replicaMaxOpen := cfg.ReplicaMaxOpen
|
||||
if replicaMaxOpen == 0 {
|
||||
replicaMaxOpen = cfg.MaxOpenConns
|
||||
}
|
||||
|
||||
resolver := dbresolver.Register(dbresolver.Config{
|
||||
Replicas: replicaDialectors,
|
||||
}).
|
||||
SetMaxIdleConns(replicaMaxIdle).
|
||||
SetMaxOpenConns(replicaMaxOpen).
|
||||
SetConnMaxLifetime(time.Hour)
|
||||
|
||||
if err := db.Use(resolver); err != nil {
|
||||
return nil, fmt.Errorf("failed to register dbresolver plugin: %w", err)
|
||||
}
|
||||
|
||||
zap.L().Info("Database read/write splitting configured",
|
||||
zap.String("type", cfg.Type),
|
||||
zap.Int("replica_count", len(allReplicas)),
|
||||
)
|
||||
}
|
||||
|
||||
// 自动迁移
|
||||
if err := autoMigrate(db); err != nil {
|
||||
return nil, fmt.Errorf("failed to auto migrate: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user