实时流计算系统设计与实现:服务治理和配置管理-动态配置

B站影视 2024-12-30 21:16 2

摘要:当将配置从代码中抽离出来的那刻起,它就是给人修改的。那从何谈起配置的静态和动态之分呢?这里我们做一个简单的划分,如果配置在程序启动后不再需要修改,那它就属于静态配置;而如果程序启动后,配置还会因为某些原因发生变更并重新生效,那它属于动态配置。

当将配置从代码中抽离出来的那刻起,它就是给人修改的。那从何谈起配置的静态和动态之分呢?这里我们做一个简单的划分,如果配置在程序启动后不再需要修改,那它就属于静态配置;而如果程序启动后,配置还会因为某些原因发生变更并重新生效,那它属于动态配置。

静态配置在程序启动前确定,在程序启动后就不再变化了。例如,程序使用的内存大小、数据库连接等配置在开发、测试、生产环境下各不相同。这些配置由构建或部署工具管理,如SaltStack的Pillar文件。静态配置由于其在程序启动后不变的特点,管理起来相对更简单,一般使用运维工具配合版本控制器即可。例如,使用SaltStack配合Git就可以很好地实现静态配置的管理。

动态配置则在程序运行过程中可以发生变更并重新生效,如调整日志级别、更新评分模型、修改决策规则等。

1.动态配置的复杂性

动态配置因为涉及改变程序运行时的行为,因此相比静态配置会复杂很多,主要体现在以下方面。

1)分布式系统环境。在分布式环境下,一个配置可能会被多个服务、多个实例使用。配置的变更如何通知到具体相关服务和实例?不同的服务和实例刷新配置的时间也可能并不一致。如果需要刷新的实例很多,那么系统在配置变更后多久能够稳定下来?在配置不稳定的过程中,业务流程的执行会受到什么影响?

2)安全性。动态配置因为改变了程序的运行时行为,有可能导致程序运行发生错误。如果程序真发生运行错误了,该怎样处理?如果回滚配置,也可能因为程序运行发生致命错误,导致回滚失败,又该怎样处理?

3)版本控制。动态配置时常在变化。如果线上客户发现配置变化后有问题需要回溯,那么该怎样跟踪配置的变更历史?

4)监控。动态配置在变更时可能引起各种各样的问题,安全性、程序重新稳定等问题。这些问题或许发生的概率不大,但如果它们真的发生了,实际上解决起来是比较棘手的。例如,动态配置下发成功,到底是服务实例收到新配置就算成功,还是服务实例收到新配置后运行成功才算成功?即使当时运行成功了,错误也可能是在运行一段时间后才出现。针对这一系列问题,即使实现了分布式事务,也是无济于事的。

鉴于以上原因,对各个服务实例当前使用的配置进行监控和检查是非常重要的事情。

当然,虽然有这么多考虑,但必须强调的是,动态配置系统的责任边界限定在相关服务实例正确接收新配置并替换本地配置即可,而不能将范围扩散太大,否则就真的会出现“到底什么时候才算配置更新成功”这种没完没了的问题了。例如,如果我们用ConfigBean类的一个对象来持有配置项,那么当用代表新配置的ConfigBean对象来替换代表旧配置的ConfigBean对象时,就已经算配置刷新成功了。至于后续程序是否能够正确运行,那是程序是否支持新配置的问题,与动态配置刷新的机制并无关系。在澄清动态配置系统的责任边界后,我们就能更加清晰地设计和实现动态配置过程了。

2.动态配置的实现方式

动态配置的实现方式有很多种,这里我们主要介绍3种:控制流方式、共享存储方式及配置服务方式。

(1)控制流方式在通信领域,除了用于数据传输的数据通道外,通常还会有一条用于传输控制信令的控制通道。在流计算领域,我们可以借鉴这种思路。

在数据流之外,我们可以新增一条控制流。通过控制流与数据流的关联(union或join)操作,就可以将控制信息作用到数据流上。而流本身又是动态的,所以通过控制流的方式来实现动态配置是一种水到渠成的方法。控制流与数据流的关系如图10-7所示。

图10-7控制流与数据流关系

下面我们按照这个原理来演示在Flink中如何实现控制流对数据流的控制。

public static void testFlinkControlStream throws Exception {

StreamExecutionEnvironment env =

StreamExecutionEnvironment.getExecutionEnvironment.setParallelism(3);

// 控制流

List> control = new ArrayList;

control.add(new Tuple1("BLUE"));

YELLOW"));

DataStream> controlStream = env.fromCollection(control);

// 数据流

List> data = new ArrayList;

for (int i = 0; i

data.add(new Tuple1("BLUE"));

data.add(new Tuple1("YELLOW"));

data.add(new Tuple1("WHITE"));

data.add(new Tuple1("RED"));

data.add(new Tuple1("BLUE"));

data.add(new Tuple1("YELLOW"));

data.add(new Tuple1("RED"));

}

DataStream> dataStream = env.fromCollection(data).keyBy(0); DataStream result = controlStream

.broadcast

.connect(dataStream)

.flatMap(new ColorCoFlatMap);

result.print;

env.execute;

}

private static final class ColorCoFlatMap

implements CoFlatMapFunction, Tuple1, String> {

HashSet blacklist = new HashSet;

@Override

public void flatMap1(Tuple1 control_value, Collector out) {

blacklist.add(control_value);

}

@Override

public void flatMap2(Tuple1 data_value, Collector out) {

if (blacklist.contains(data_value)) {

out.collect("invalid color " + data_value);

} else {

out.collect("valid color " + data_value);

}

}

}

在上面的代码中,testFlinkControlStream函数创建了两个流,即控制流controlStream和数据流dataStream,然后将controlStream广播(broadcast)后与dataStream连接(connect)起来。在ColorCoFlatMap中,如果接收到的是控制事件,就将其保存到黑名单;

如果接收到的是颜色事件,就检查其是否在黑名单中。这样,控制流动态配置黑名单清单,而数据流使用这个黑名单清单,所以我们通过控制流的方式对数据流的行为进行动态配置。另外,在Flink中,为了方便实现动态配置,引入可以直接使用的广播状态(broadcast state)。

广播状态的使用方式与广播类似,这里不再展开叙述了。

(2)共享存储方式

共享存储是一种实现动态配置的方法,即将配置存放在共享数据库中,当配置发生变更时,先将配置写入共享数据库,然后通过配置使用方轮询或者通知配置使用者配置变更的方式,配置使用者即可重新读取更新后的配置。

图10-8共享存储实现动态配置

图10-8展示了用MongoDB结合ZooKeeper来实现动态配置的方案。

在图10-8的解决方案中,当配置管理者需要修改配置时,首先将配置写入MongoDB,然后变更Zookeeper的某个节点。当配置使用者监听到Zookeeper的这个节点变更时,就知道配置已经发生变更,从而从MongoDB重新读取新的配置。这样,就完成了动态配置的功能。

ZooKeeper本身具备存储数据的能力,如果配置很简单,直接使用ZooKeeper存储即可。但是,在复杂的业务场景下,可能配置也非常复杂,并具有丰富的层次组织结构。在这种情况下,尽量将配置本身从ZooKeeper中剥离出来,并存储到专门的数据库(如MongoDB或MySQL中),ZooKeeper只用于全局配置变更时的协调。毕竟,ZooKeeper的设计目的是做分布式协调,而不是一个文件系统。

(3)配置服务方式

还有一种动态配置实现的方式是在微服务系统中经常使用的,这就是使用专门的配置服务中心。在前面讨论服务治理的配置管理功能时,我们已经介绍了Spring Cloud Config的配置服务中心的功能。当结合Spring Cloud bus后,就能够实现分布式动态配置刷新功能了。

图10-9就是Spring Cloud Config实现动态配置的过程。当用户更新配置时,可以手动或自动(通过Git Hooks)向Config Server发送/bus/refresh请求,Config Server接收到配置刷新请求后,再通过RabbitMQ将配置刷新命令发布到每一个服务实例。当服务实例收到配置刷新命令后,从Config Server重新加载配置,最终完成配置的动态更新。

图10-9 Spring Cloud Config实现动态配置的过程

来源:大数据架构师

相关推荐