2-20 2 views
流量控制是保证服务稳定性的重要手段之一。大数据应用服务因为有缓存构建的过程,需要在启动后通过小流量出发缓存构建再才接收全量流量,若未构建缓存会导致上线即崩溃
结合数据侧架构发展场景、成本等诸多因素考虑,放弃部署服务网关这一更优雅的方案,采用用最低成本的技术手段来实现
1. 利用 Kubernetes 的 Informer (Informer 是 k8s 的高效的资源监听机制,可实时感知集群中资源的变化)监听 service 的 endpoint 的变化
|
1 2 3 4 5 6 |
watchlist := cache.NewListWatchFromClient( clientset.CoreV1().RESTClient(), endpoints, // 资源对象 namespace, // 服务所在的 namespace fields.OneTermEqualSelector("metadata.name", serviceName), // 服务的 service ) |
2. 结合 ResourceEventHandlerFuncs 适配器去实现对应的事件的处理方法
|
1 2 3 4 5 6 7 8 9 10 |
_, controller := cache.NewInformer( watchlist, &v1.Endpoints{}, 0*time.Second, cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) {}, // 添加事件 UpdateFunc: func(obj interface{}) {}, // 更新事件 DeleteFunc: func(obj interface{}) {}, // 删除事件 }, ) |
3. 利用 Redis 控制流量
将待放流量的主机标识存储在 Redis 中,设置 TTL 来控制放流量的时间窗口
当 TTL 到期时,自动移除主机流量
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// 检查实例是否已存在 func (s *Store) Check(ctx context.Context, key string) (bool, error) { cmd := s.cli.Exists(ctx, s.wrapperKey(key)) if err := cmd.Err(); err != nil { return false, err } return cmd.Val() > 0, nil } // 配置时间窗 func (s *Store) Set(ctx context.Context, key string, val interface{}, expiration time.Duration) error { cmd := s.cli.Set(ctx, s.wrapperKey(key), val, expiration) return cmd.Err() } // 配置时间窗 TTL 不变 func (s *Store) SetWithKeepTTL(ctx context.Context, key string, val interface{}) error { cmd := s.cli.SetArgs(ctx, s.wrapperKey(key), val, redisV8.SetArgs{KeepTTL: true}) return cmd.Err() } |
4. 声明策略
|
1 2 3 4 5 6 7 8 9 |
Strategy: - weight: 10 duration: 20 - weight: 40 duration: 20 - weight: 70 duration: 20 - weight: 100 duration: 0 |