9.1 Caddy架构深入理解
9.1.1 模块化架构
Caddy采用高度模块化的架构设计,所有功能都以模块形式实现。
核心组件: - App模块:HTTP、TLS、PKI等应用 - Handler模块:处理HTTP请求的中间件 - Matcher模块:请求匹配器 - Provider模块:DNS、存储等提供商
// 模块接口定义
type Module interface {
CaddyModule() ModuleInfo
}
type ModuleInfo struct {
ID ModuleID
New func() Module
}
// 示例模块实现
type MyModule struct {
Field string `json:"field,omitempty"`
}
func (MyModule) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.handlers.my_module",
New: func() caddy.Module { return new(MyModule) },
}
}
9.1.2 请求处理流程
// HTTP请求处理流程
type Server struct {
Listen []string `json:"listen,omitempty"`
Routes RouteList `json:"routes,omitempty"`
Errors *HTTPErrorConfig `json:"errors,omitempty"`
TLSConnPolicies caddytls.ConnectionPolicies `json:"tls_connection_policies,omitempty"`
}
// 路由匹配和处理
type Route struct {
Group string `json:"group,omitempty"`
Match MatcherSets `json:"match,omitempty"`
Handle HandlerModules `json:"handle,omitempty"`
Terminal bool `json:"terminal,omitempty"`
}
9.1.3 中间件链
// 中间件接口
type MiddlewareHandler interface {
ServeHTTP(http.ResponseWriter, *http.Request, Handler) error
}
// Handler接口
type Handler interface {
ServeHTTP(http.ResponseWriter, *http.Request) error
}
// 中间件链构建
func buildMiddlewareChain(handlers []MiddlewareHandler, finalHandler Handler) Handler {
if len(handlers) == 0 {
return finalHandler
}
return HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
return handlers[0].ServeHTTP(w, r, buildMiddlewareChain(handlers[1:], finalHandler))
})
}
9.2 自定义中间件开发
9.2.1 基础中间件结构
package mymiddleware
import (
"context"
"fmt"
"net/http"
"time"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"go.uber.org/zap"
)
func init() {
caddy.RegisterModule(Middleware{})
httpcaddyfile.RegisterHandlerDirective("my_middleware", parseCaddyfile)
}
// Middleware 自定义中间件
type Middleware struct {
Message string `json:"message,omitempty"`
Delay caddy.Duration `json:"delay,omitempty"`
logger *zap.Logger
}
// CaddyModule 返回模块信息
func (Middleware) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.handlers.my_middleware",
New: func() caddy.Module { return new(Middleware) },
}
}
// Provision 初始化模块
func (m *Middleware) Provision(ctx caddy.Context) error {
m.logger = ctx.Logger(m)
return nil
}
// Validate 验证配置
func (m *Middleware) Validate() error {
if m.Message == "" {
return fmt.Errorf("message cannot be empty")
}
return nil
}
// ServeHTTP 处理HTTP请求
func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
// 记录请求开始
start := time.Now()
m.logger.Info("request started",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
// 添加自定义头部
w.Header().Set("X-Custom-Message", m.Message)
// 模拟延迟
if m.Delay > 0 {
time.Sleep(time.Duration(m.Delay))
}
// 调用下一个处理器
err := next.ServeHTTP(w, r)
// 记录请求完成
duration := time.Since(start)
m.logger.Info("request completed",
zap.Duration("duration", duration),
zap.Int("status", w.(*caddyhttp.ResponseRecorder).Status()),
)
return err
}
// parseCaddyfile 解析Caddyfile配置
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
var m Middleware
for h.Next() {
for h.NextBlock(0) {
switch h.Val() {
case "message":
if !h.Args(&m.Message) {
return nil, h.ArgErr()
}
case "delay":
var delayStr string
if !h.Args(&delayStr) {
return nil, h.ArgErr()
}
delay, err := time.ParseDuration(delayStr)
if err != nil {
return nil, h.Errf("invalid delay duration: %v", err)
}
m.Delay = caddy.Duration(delay)
default:
return nil, h.Errf("unrecognized subdirective: %s", h.Val())
}
}
}
return m, nil
}
// Interface guards
var (
_ caddy.Provisioner = (*Middleware)(nil)
_ caddy.Validator = (*Middleware)(nil)
_ caddyhttp.MiddlewareHandler = (*Middleware)(nil)
_ caddyfile.Unmarshaler = (*Middleware)(nil)
)
9.2.2 高级中间件功能
// 带状态的中间件
type StatefulMiddleware struct {
Config string `json:"config,omitempty"`
counter int64
mutex sync.RWMutex
logger *zap.Logger
metrics *prometheus.CounterVec
}
func (m *StatefulMiddleware) Provision(ctx caddy.Context) error {
m.logger = ctx.Logger(m)
// 初始化Prometheus指标
m.metrics = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "caddy_custom_requests_total",
Help: "Total number of requests processed by custom middleware",
},
[]string{"method", "status"},
)
// 注册指标
prometheus.MustRegister(m.metrics)
return nil
}
func (m *StatefulMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
// 增加计数器
m.mutex.Lock()
m.counter++
currentCount := m.counter
m.mutex.Unlock()
// 添加请求ID
requestID := fmt.Sprintf("%d-%d", time.Now().Unix(), currentCount)
r.Header.Set("X-Request-ID", requestID)
w.Header().Set("X-Request-ID", requestID)
// 创建响应记录器
recorder := caddyhttp.NewResponseRecorder(w, nil, nil)
// 处理请求
err := next.ServeHTTP(recorder, r)
// 记录指标
m.metrics.WithLabelValues(
r.Method,
fmt.Sprintf("%d", recorder.Status()),
).Inc()
return err
}
// Cleanup 清理资源
func (m *StatefulMiddleware) Cleanup() error {
if m.metrics != nil {
prometheus.Unregister(m.metrics)
}
return nil
}
9.2.3 请求/响应修改中间件
// 请求/响应修改中间件
type RequestResponseModifier struct {
RequestHeaders map[string]string `json:"request_headers,omitempty"`
ResponseHeaders map[string]string `json:"response_headers,omitempty"`
RemoveHeaders []string `json:"remove_headers,omitempty"`
BodyTransform string `json:"body_transform,omitempty"`
}
func (m RequestResponseModifier) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
// 修改请求头
for key, value := range m.RequestHeaders {
r.Header.Set(key, value)
}
// 删除指定头部
for _, header := range m.RemoveHeaders {
r.Header.Del(header)
}
// 创建响应包装器
wrapper := &responseWrapper{
ResponseWriter: w,
modifier: &m,
}
return next.ServeHTTP(wrapper, r)
}
type responseWrapper struct {
http.ResponseWriter
modifier *RequestResponseModifier
written bool
}
func (rw *responseWrapper) WriteHeader(statusCode int) {
if !rw.written {
// 添加响应头
for key, value := range rw.modifier.ResponseHeaders {
rw.Header().Set(key, value)
}
rw.written = true
}
rw.ResponseWriter.WriteHeader(statusCode)
}
func (rw *responseWrapper) Write(data []byte) (int, error) {
if !rw.written {
rw.WriteHeader(http.StatusOK)
}
// 可以在这里对响应体进行转换
if rw.modifier.BodyTransform != "" {
// 实现响应体转换逻辑
data = rw.transformBody(data)
}
return rw.ResponseWriter.Write(data)
}
func (rw *responseWrapper) transformBody(data []byte) []byte {
// 实现具体的转换逻辑
switch rw.modifier.BodyTransform {
case "uppercase":
return []byte(strings.ToUpper(string(data)))
case "base64":
return []byte(base64.StdEncoding.EncodeToString(data))
default:
return data
}
}
9.3 高级匹配器开发
9.3.1 自定义匹配器
package custommatcher
import (
"net/http"
"regexp"
"strings"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
)
func init() {
caddy.RegisterModule(CustomMatcher{})
}
// CustomMatcher 自定义匹配器
type CustomMatcher struct {
UserAgent string `json:"user_agent,omitempty"`
IPRange string `json:"ip_range,omitempty"`
TimeRange string `json:"time_range,omitempty"`
HeaderMatch map[string]string `json:"header_match,omitempty"`
userAgentRegex *regexp.Regexp
ipNet *net.IPNet
}
func (CustomMatcher) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.matchers.custom",
New: func() caddy.Module { return new(CustomMatcher) },
}
}
func (m *CustomMatcher) Provision(ctx caddy.Context) error {
// 编译用户代理正则表达式
if m.UserAgent != "" {
regex, err := regexp.Compile(m.UserAgent)
if err != nil {
return fmt.Errorf("invalid user agent regex: %v", err)
}
m.userAgentRegex = regex
}
// 解析IP范围
if m.IPRange != "" {
_, ipNet, err := net.ParseCIDR(m.IPRange)
if err != nil {
return fmt.Errorf("invalid IP range: %v", err)
}
m.ipNet = ipNet
}
return nil
}
func (m CustomMatcher) Match(r *http.Request) bool {
// 匹配用户代理
if m.userAgentRegex != nil {
userAgent := r.Header.Get("User-Agent")
if !m.userAgentRegex.MatchString(userAgent) {
return false
}
}
// 匹配IP范围
if m.ipNet != nil {
clientIP := net.ParseIP(r.RemoteAddr)
if clientIP == nil || !m.ipNet.Contains(clientIP) {
return false
}
}
// 匹配时间范围
if m.TimeRange != "" {
if !m.matchTimeRange() {
return false
}
}
// 匹配自定义头部
for header, expectedValue := range m.HeaderMatch {
actualValue := r.Header.Get(header)
if actualValue != expectedValue {
return false
}
}
return true
}
func (m CustomMatcher) matchTimeRange() bool {
// 实现时间范围匹配逻辑
// 例如:"09:00-17:00" 表示工作时间
now := time.Now()
hour := now.Hour()
// 简单示例:工作时间匹配
if m.TimeRange == "business_hours" {
return hour >= 9 && hour < 17
}
return true
}
// Interface guard
var _ caddyhttp.RequestMatcher = (*CustomMatcher)(nil)
9.3.2 复合匹配器
// 复合匹配器
type CompoundMatcher struct {
And []caddyhttp.RequestMatcher `json:"and,omitempty"`
Or []caddyhttp.RequestMatcher `json:"or,omitempty"`
Not caddyhttp.RequestMatcher `json:"not,omitempty"`
}
func (m CompoundMatcher) Match(r *http.Request) bool {
// AND逻辑:所有条件都必须满足
if len(m.And) > 0 {
for _, matcher := range m.And {
if !matcher.Match(r) {
return false
}
}
}
// OR逻辑:至少一个条件满足
if len(m.Or) > 0 {
matched := false
for _, matcher := range m.Or {
if matcher.Match(r) {
matched = true
break
}
}
if !matched {
return false
}
}
// NOT逻辑:条件不能满足
if m.Not != nil {
if m.Not.Match(r) {
return false
}
}
return true
}
9.4 存储提供商开发
9.4.1 自定义存储后端
package customstorage
import (
"context"
"fmt"
"io"
"io/fs"
"time"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/certmagic"
)
func init() {
caddy.RegisterModule(CustomStorage{})
}
// CustomStorage 自定义存储提供商
type CustomStorage struct {
Endpoint string `json:"endpoint,omitempty"`
AccessKey string `json:"access_key,omitempty"`
SecretKey string `json:"secret_key,omitempty"`
BucketName string `json:"bucket_name,omitempty"`
client interface{} // 存储客户端
}
func (CustomStorage) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "caddy.storage.custom",
New: func() caddy.Module { return new(CustomStorage) },
}
}
func (s *CustomStorage) Provision(ctx caddy.Context) error {
// 初始化存储客户端
// s.client = createStorageClient(s.Endpoint, s.AccessKey, s.SecretKey)
return nil
}
func (s *CustomStorage) CertMagicStorage() (certmagic.Storage, error) {
return s, nil
}
// 实现certmagic.Storage接口
func (s *CustomStorage) Store(key string, value []byte) error {
// 实现存储逻辑
fmt.Printf("Storing key: %s, size: %d bytes\n", key, len(value))
return nil
}
func (s *CustomStorage) Load(key string) ([]byte, error) {
// 实现加载逻辑
fmt.Printf("Loading key: %s\n", key)
return nil, fmt.Errorf("key not found: %s", key)
}
func (s *CustomStorage) Delete(key string) error {
// 实现删除逻辑
fmt.Printf("Deleting key: %s\n", key)
return nil
}
func (s *CustomStorage) Exists(key string) bool {
// 实现存在性检查
fmt.Printf("Checking existence of key: %s\n", key)
return false
}
func (s *CustomStorage) List(prefix string, recursive bool) ([]string, error) {
// 实现列表功能
fmt.Printf("Listing keys with prefix: %s, recursive: %v\n", prefix, recursive)
return []string{}, nil
}
func (s *CustomStorage) Stat(key string) (certmagic.KeyInfo, error) {
// 实现状态查询
return certmagic.KeyInfo{
Key: key,
Modified: time.Now(),
Size: 0,
IsTerminal: true,
}, nil
}
// Interface guards
var (
_ caddy.Provisioner = (*CustomStorage)(nil)
_ caddy.StorageConverter = (*CustomStorage)(nil)
_ certmagic.Storage = (*CustomStorage)(nil)
)
9.4.2 分布式存储实现
// 分布式存储实现
type DistributedStorage struct {
Nodes []string `json:"nodes,omitempty"`
Replicas int `json:"replicas,omitempty"`
Timeout caddy.Duration `json:"timeout,omitempty"`
clients []StorageClient
hashRing *consistent.Consistent
}
type StorageClient interface {
Store(key string, value []byte) error
Load(key string) ([]byte, error)
Delete(key string) error
Exists(key string) bool
}
func (ds *DistributedStorage) Provision(ctx caddy.Context) error {
// 初始化一致性哈希环
ds.hashRing = consistent.New()
// 添加节点到哈希环
for _, node := range ds.Nodes {
ds.hashRing.Add(node)
// 创建客户端连接
client := createStorageClient(node)
ds.clients = append(ds.clients, client)
}
return nil
}
func (ds *DistributedStorage) Store(key string, value []byte) error {
// 获取负责该key的节点
nodes, err := ds.hashRing.GetN(key, ds.Replicas)
if err != nil {
return err
}
// 并行存储到多个副本
errChan := make(chan error, len(nodes))
for _, node := range nodes {
go func(n string) {
client := ds.getClientForNode(n)
errChan <- client.Store(key, value)
}(node)
}
// 等待所有存储操作完成
var errors []error
for i := 0; i < len(nodes); i++ {
if err := <-errChan; err != nil {
errors = append(errors, err)
}
}
// 如果大多数副本存储成功,则认为操作成功
if len(errors) <= len(nodes)/2 {
return nil
}
return fmt.Errorf("failed to store to majority of replicas: %v", errors)
}
func (ds *DistributedStorage) Load(key string) ([]byte, error) {
// 从任意一个副本读取
nodes, err := ds.hashRing.GetN(key, ds.Replicas)
if err != nil {
return nil, err
}
for _, node := range nodes {
client := ds.getClientForNode(node)
if data, err := client.Load(key); err == nil {
return data, nil
}
}
return nil, fmt.Errorf("key not found in any replica: %s", key)
}
func (ds *DistributedStorage) getClientForNode(node string) StorageClient {
// 根据节点名称获取对应的客户端
for i, n := range ds.Nodes {
if n == node {
return ds.clients[i]
}
}
return nil
}
9.5 DNS提供商开发
9.5.1 自定义DNS提供商
package customdns
import (
"context"
"fmt"
"time"
"github.com/caddyserver/caddy/v2"
"github.com/libdns/libdns"
)
func init() {
caddy.RegisterModule(Provider{})
}
// Provider 自定义DNS提供商
type Provider struct {
APIKey string `json:"api_key,omitempty"`
APISecret string `json:"api_secret,omitempty"
Endpoint string `json:"endpoint,omitempty"`
client DNSClient
}
type DNSClient interface {
CreateRecord(zone, name, recordType, value string, ttl int) error
DeleteRecord(zone, name, recordType string) error
GetRecords(zone string) ([]libdns.Record, error)
}
func (Provider) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "dns.providers.custom",
New: func() caddy.Module { return new(Provider) },
}
}
func (p *Provider) Provision(ctx caddy.Context) error {
// 初始化DNS客户端
p.client = NewDNSClient(p.APIKey, p.APISecret, p.Endpoint)
return nil
}
// 实现libdns.RecordGetter接口
func (p *Provider) GetRecords(ctx context.Context, zone string) ([]libdns.Record, error) {
records, err := p.client.GetRecords(zone)
if err != nil {
return nil, fmt.Errorf("failed to get records: %v", err)
}
return records, nil
}
// 实现libdns.RecordAppender接口
func (p *Provider) AppendRecords(ctx context.Context, zone string, records []libdns.Record) ([]libdns.Record, error) {
var createdRecords []libdns.Record
for _, record := range records {
err := p.client.CreateRecord(
zone,
record.Name,
record.Type,
record.Value,
int(record.TTL.Seconds()),
)
if err != nil {
return nil, fmt.Errorf("failed to create record %s: %v", record.Name, err)
}
// 设置记录ID(如果API返回)
record.ID = fmt.Sprintf("%s-%s-%s", zone, record.Name, record.Type)
createdRecords = append(createdRecords, record)
}
return createdRecords, nil
}
// 实现libdns.RecordDeleter接口
func (p *Provider) DeleteRecords(ctx context.Context, zone string, records []libdns.Record) ([]libdns.Record, error) {
var deletedRecords []libdns.Record
for _, record := range records {
err := p.client.DeleteRecord(zone, record.Name, record.Type)
if err != nil {
return nil, fmt.Errorf("failed to delete record %s: %v", record.Name, err)
}
deletedRecords = append(deletedRecords, record)
}
return deletedRecords, nil
}
// Interface guards
var (
_ caddy.Provisioner = (*Provider)(nil)
_ libdns.RecordGetter = (*Provider)(nil)
_ libdns.RecordAppender = (*Provider)(nil)
_ libdns.RecordDeleter = (*Provider)(nil)
)
9.5.2 DNS客户端实现
// DNS客户端实现
type dnsClient struct {
apiKey string
apiSecret string
endpoint string
httpClient *http.Client
}
func NewDNSClient(apiKey, apiSecret, endpoint string) DNSClient {
return &dnsClient{
apiKey: apiKey,
apiSecret: apiSecret,
endpoint: endpoint,
httpClient: &http.Client{
Timeout: 30 * time.Second,
},
}
}
func (c *dnsClient) CreateRecord(zone, name, recordType, value string, ttl int) error {
payload := map[string]interface{}{
"name": name,
"type": recordType,
"value": value,
"ttl": ttl,
}
return c.makeRequest("POST", fmt.Sprintf("/zones/%s/records", zone), payload)
}
func (c *dnsClient) DeleteRecord(zone, name, recordType string) error {
return c.makeRequest("DELETE", fmt.Sprintf("/zones/%s/records/%s/%s", zone, name, recordType), nil)
}
func (c *dnsClient) GetRecords(zone string) ([]libdns.Record, error) {
var response struct {
Records []struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Value string `json:"value"`
TTL int `json:"ttl"`
} `json:"records"`
}
err := c.makeRequest("GET", fmt.Sprintf("/zones/%s/records", zone), &response)
if err != nil {
return nil, err
}
var records []libdns.Record
for _, r := range response.Records {
records = append(records, libdns.Record{
ID: r.ID,
Name: r.Name,
Type: r.Type,
Value: r.Value,
TTL: time.Duration(r.TTL) * time.Second,
})
}
return records, nil
}
func (c *dnsClient) makeRequest(method, path string, payload interface{}) error {
url := c.endpoint + path
var body io.Reader
if payload != nil {
jsonData, err := json.Marshal(payload)
if err != nil {
return err
}
body = bytes.NewBuffer(jsonData)
}
req, err := http.NewRequest(method, url, body)
if err != nil {
return err
}
// 添加认证头
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.apiKey))
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
return fmt.Errorf("API request failed with status %d", resp.StatusCode)
}
return nil
}
9.6 企业级功能
9.6.1 集群配置同步
// 集群配置同步
type ClusterSync struct {
Nodes []string `json:"nodes,omitempty"`
SyncInterval caddy.Duration `json:"sync_interval,omitempty"`
ticker *time.Ticker
stopChan chan struct{}
}
func (cs *ClusterSync) Provision(ctx caddy.Context) error {
if cs.SyncInterval == 0 {
cs.SyncInterval = caddy.Duration(30 * time.Second)
}
cs.stopChan = make(chan struct{})
cs.ticker = time.NewTicker(time.Duration(cs.SyncInterval))
// 启动同步协程
go cs.syncLoop()
return nil
}
func (cs *ClusterSync) syncLoop() {
for {
select {
case <-cs.ticker.C:
cs.syncConfiguration()
case <-cs.stopChan:
return
}
}
}
func (cs *ClusterSync) syncConfiguration() {
// 获取本地配置
localConfig := cs.getLocalConfig()
// 与其他节点同步
for _, node := range cs.Nodes {
go func(nodeAddr string) {
remoteConfig, err := cs.getRemoteConfig(nodeAddr)
if err != nil {
return
}
// 比较配置版本
if remoteConfig.Version > localConfig.Version {
cs.updateLocalConfig(remoteConfig)
}
}(node)
}
}
func (cs *ClusterSync) getLocalConfig() *ClusterConfig {
// 实现获取本地配置逻辑
return &ClusterConfig{}
}
func (cs *ClusterSync) getRemoteConfig(nodeAddr string) (*ClusterConfig, error) {
// 实现获取远程配置逻辑
resp, err := http.Get(fmt.Sprintf("http://%s/api/config", nodeAddr))
if err != nil {
return nil, err
}
defer resp.Body.Close()
var config ClusterConfig
err = json.NewDecoder(resp.Body).Decode(&config)
return &config, err
}
type ClusterConfig struct {
Version int64 `json:"version"`
Config interface{} `json:"config"`
}
9.6.2 高可用性配置
// 高可用性配置
type HAConfig struct {
VirtualIP string `json:"virtual_ip,omitempty"`
Priority int `json:"priority,omitempty"`
CheckInterval caddy.Duration `json:"check_interval,omitempty"`
Peers []string `json:"peers,omitempty"`
isMaster bool
healthChan chan bool
}
func (ha *HAConfig) Provision(ctx caddy.Context) error {
ha.healthChan = make(chan bool, 1)
// 启动健康检查
go ha.healthCheck()
// 启动选主逻辑
go ha.leaderElection()
return nil
}
func (ha *HAConfig) healthCheck() {
ticker := time.NewTicker(time.Duration(ha.CheckInterval))
defer ticker.Stop()
for range ticker.C {
healthy := ha.checkHealth()
select {
case ha.healthChan <- healthy:
default:
}
}
}
func (ha *HAConfig) checkHealth() bool {
// 实现健康检查逻辑
// 检查关键服务状态
return true
}
func (ha *HAConfig) leaderElection() {
for health := range ha.healthChan {
if health && !ha.isMaster {
// 尝试成为主节点
if ha.tryBecomeMaster() {
ha.isMaster = true
ha.activateVirtualIP()
}
} else if !health && ha.isMaster {
// 释放主节点角色
ha.isMaster = false
ha.deactivateVirtualIP()
}
}
}
func (ha *HAConfig) tryBecomeMaster() bool {
// 实现选主逻辑(例如使用etcd或consul)
return true
}
func (ha *HAConfig) activateVirtualIP() {
// 激活虚拟IP
cmd := exec.Command("ip", "addr", "add", ha.VirtualIP, "dev", "eth0")
cmd.Run()
}
func (ha *HAConfig) deactivateVirtualIP() {
// 停用虚拟IP
cmd := exec.Command("ip", "addr", "del", ha.VirtualIP, "dev", "eth0")
cmd.Run()
}
9.7 性能优化技巧
9.7.1 连接池管理
// 连接池管理
type ConnectionPool struct {
MaxConnections int `json:"max_connections,omitempty"`
IdleTimeout caddy.Duration `json:"idle_timeout,omitempty"`
pool sync.Pool
active int64
mutex sync.RWMutex
}
func (cp *ConnectionPool) Provision(ctx caddy.Context) error {
cp.pool = sync.Pool{
New: func() interface{} {
return cp.createConnection()
},
}
return nil
}
func (cp *ConnectionPool) GetConnection() (net.Conn, error) {
cp.mutex.Lock()
defer cp.mutex.Unlock()
if atomic.LoadInt64(&cp.active) >= int64(cp.MaxConnections) {
return nil, fmt.Errorf("connection pool exhausted")
}
conn := cp.pool.Get().(net.Conn)
atomic.AddInt64(&cp.active, 1)
return conn, nil
}
func (cp *ConnectionPool) ReleaseConnection(conn net.Conn) {
atomic.AddInt64(&cp.active, -1)
cp.pool.Put(conn)
}
func (cp *ConnectionPool) createConnection() net.Conn {
// 创建新连接的逻辑
return nil
}
9.7.2 缓存优化
// 智能缓存中间件
type SmartCache struct {
TTL caddy.Duration `json:"ttl,omitempty"`
MaxSize int `json:"max_size,omitempty"`
CacheRules []CacheRule `json:"cache_rules,omitempty"`
cache *lru.Cache
stats CacheStats
}
type CacheRule struct {
Path string `json:"path,omitempty"`
Methods []string `json:"methods,omitempty"`
TTL caddy.Duration `json:"ttl,omitempty"`
VaryHeaders []string `json:"vary_headers,omitempty"`
}
type CacheStats struct {
Hits int64 `json:"hits"`
Misses int64 `json:"misses"`
Size int64 `json:"size"`
}
func (sc *SmartCache) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
// 检查是否应该缓存
rule := sc.matchCacheRule(r)
if rule == nil {
return next.ServeHTTP(w, r)
}
// 生成缓存键
cacheKey := sc.generateCacheKey(r, rule)
// 尝试从缓存获取
if cached, ok := sc.cache.Get(cacheKey); ok {
atomic.AddInt64(&sc.stats.Hits, 1)
cachedResponse := cached.(*CachedResponse)
// 检查是否过期
if time.Since(cachedResponse.Timestamp) < time.Duration(rule.TTL) {
sc.writeCachedResponse(w, cachedResponse)
return nil
}
}
atomic.AddInt64(&sc.stats.Misses, 1)
// 创建响应记录器
recorder := &cacheRecorder{
ResponseWriter: w,
statusCode: 200,
headers: make(http.Header),
}
// 处理请求
err := next.ServeHTTP(recorder, r)
if err != nil {
return err
}
// 缓存响应
if sc.shouldCache(recorder.statusCode) {
cachedResponse := &CachedResponse{
StatusCode: recorder.statusCode,
Headers: recorder.headers,
Body: recorder.body.Bytes(),
Timestamp: time.Now(),
}
sc.cache.Add(cacheKey, cachedResponse)
}
return nil
}
type CachedResponse struct {
StatusCode int
Headers http.Header
Body []byte
Timestamp time.Time
}
type cacheRecorder struct {
http.ResponseWriter
statusCode int
headers http.Header
body bytes.Buffer
}
func (cr *cacheRecorder) WriteHeader(statusCode int) {
cr.statusCode = statusCode
cr.ResponseWriter.WriteHeader(statusCode)
}
func (cr *cacheRecorder) Write(data []byte) (int, error) {
cr.body.Write(data)
return cr.ResponseWriter.Write(data)
}
9.8 本章总结
本章深入探讨了Caddy的高级特性和扩展开发:
- 架构理解:模块化设计和请求处理流程
- 中间件开发:自定义处理逻辑和状态管理
- 匹配器开发:复杂的请求匹配逻辑
- 存储提供商:自定义存储后端和分布式存储
- DNS提供商:自动化证书管理的DNS集成
- 企业功能:集群同步和高可用性配置
- 性能优化:连接池和智能缓存
9.9 练习题
- 开发一个请求限流中间件,支持多种限流策略
- 实现一个基于Redis的分布式存储提供商
- 创建一个自定义DNS提供商,集成您的DNS服务
- 开发一个API网关中间件,支持认证和路由
- 实现一个监控中间件,收集详细的性能指标
下一章预告:第十章将通过一个完整的实战项目,展示如何使用Caddy构建企业级的Web服务架构。