Maxwell1.29.0源码-1

Maxwell初始化准备阶段

当我们执行了 maxwell --host bigdata1时

maxwell会先进入 Maxwell.java 中的 main 方法中
在 mian 方法里,优先将配置信息 --host 赋予MaxwellConfig()并创建其对象,可见MaxwellConfig应该是初始化配置信息的类

	public static void main(String[] args) {
		try {
			Logging.setupLogBridging();
			MaxwellConfig config = new MaxwellConfig(args);

进入MaxwellConfig中,当存在配置信息参数时,MaxwellConfig将会调用重载方法MaxwellConfig,否则会调用没有形参的MaxwellConfig

//带形参	
public MaxwellConfig(String argv[]) {
		this();
		this.parse(argv);
	}
//不带形参,不带形参会将所有必须配置设置上默认值
	public MaxwellConfig() { // argv is only null in tests
		this.customProducerProperties = new Properties();
		this.kafkaProperties = new Properties();
		this.replayMode = false;
		this.replicationMysql = new MaxwellMysqlConfig();
		this.maxwellMysql = new MaxwellMysqlConfig();
		this.schemaMysql = new MaxwellMysqlConfig();
		this.masterRecovery = false;
		this.gtidMode = false;
		this.bufferedProducerSize = 200;
		this.outputConfig = new MaxwellOutputConfig();
		setup(null, null); // setup defaults
	}

同时,将接收到的参数传递给 parse 方法

	private void parse(String [] argv) {
		MaxwellOptionParser parser = buildOptionParser();
		OptionSet options = parser.parse(argv);

parse优先将拿到的配置信息交给 buildOptionParser()对象,当配置信息能够与 buildOptionParser 所必须的配置匹配上后,会返回给 parse

随后parse会进行判断:

final Properties properties;

		if (options.has("config")) {
			properties = parseFile((String) options.valueOf("config"), true);
		} else {
			properties = parseFile(DEFAULT_CONFIG_FILE, false);
		}

如果配置信息上存在config,那么就使用指定的config,否则使用默认的config文件

同时进行env_config的判断,检查是否拥有 env_config文件,如果存在,则读取配置文件,并输出日志提醒env_config文件的配置已经更改

if (options.has("env_config")) {
   Properties envConfigProperties = readPropertiesEnv((String) options.valueOf("env_config"));
   for (Map.Entry<Object, Object> entry : envConfigProperties.entrySet()) {
      Object key = entry.getKey();
      if (properties.put(key, entry.getValue()) != null) {
         LOGGER.debug("Replaced config key {} with value from env_config", key);
      }
   }
}

随后判断是否有env_config_prefix,由于这个配置参数是没有预先设置默认值的,所以需要采用 fetchStringOption 进行确定,具体是拿到 配置参数 和 env_config 中被修改的配置信息,然后在里面查找有没有 env_config_prefix,如果没有,则默认为null,随后进行判断,如果存在 env_config_prefix,那么其中的所有值将会:

​ 首先被转换成流,筛选前缀为 prefix 的数据

​ 对其中的每一条数据,获取到它的键,并将前缀去除,随后往config生成的properties中输入,目的是为了更改config中的配置

String envConfigPrefix = fetchStringOption("env_config_prefix", options, properties, null);

if (envConfigPrefix != null) {
   String prefix = envConfigPrefix.toLowerCase();
   System.getenv().entrySet().stream()
         .filter(map -> map.getKey().toLowerCase().startsWith(prefix))
         .forEach(config -> {
            String rawKey = config.getKey();
            String newKey = rawKey.toLowerCase().replaceFirst(prefix, "");
            if (properties.put(newKey, config.getValue()) != null) {
               LOGGER.debug("Got env variable {} and replacing config key {}", rawKey, newKey);
            } else {
               LOGGER.debug("Got env variable {} as config key {}", rawKey, newKey);
            }
         });
}

最后将 配置参数 和config配置传递给 setup;同时如果有help则输出教程,如果有未解析的选项则返回报错

if (options.has("help"))
   usage("Help for Maxwell:", parser, (String) options.valueOf("help"));

setup(options, properties);

List<?> arguments = options.nonOptionArguments();
if(!arguments.isEmpty()) {
   usage("Unknown argument(s): " + arguments);
}

至此,Maxwell 的初始化阶段基本结束

初始化初期

setup中保存一系列的参数,这些参数可以由前面初始化阶段进行更改,当一些选项没有出现时,一定程度上会有默认值或者直接置为null,接下来以kafka为例:

private void setup(OptionSet options, Properties properties) {
    this.kafkaTopic         	= fetchStringOption("kafka_topic", options, properties, "maxwell");
		this.kafkaKeyFormat     	= fetchStringOption("kafka_key_format", options, properties, "hash");

		this.kafkaPartitionHash 	= fetchStringOption("kafka_partition_hash", options, properties, "default");
		this.ddlKafkaTopic 		    = fetchStringOption("ddl_kafka_topic", options, properties, this.kafkaTopic);
}

这里保存了一些需要使用的配置参数,其中由topic、分区格式等,topic如果为空时,默认为waxwell

同样的,mysql也一样

		this.databaseName       = fetchStringOption("schema_database", options, properties, "maxwell");
		this.maxwellMysql.database = this.databaseName;

默认情况下,使用maxwell作为database

可以看到,setup最后也只是配置MaxwellConfig的属性,在validate中,也提供了一系列配置这些属性的逻辑,比如setup中缺失的kafka的bootstrap.servers:

public void validate() {
   validatePartitionBy();
   validateFilter();

   if ( this.producerType.equals("kafka") ) {
      if ( !this.kafkaProperties.containsKey("bootstrap.servers") ) {
         usageForOptions("Please specify kafka.bootstrap.servers", "kafka");
      }

      if ( this.kafkaPartitionHash == null ) {
         this.kafkaPartitionHash = "default";
      } else if ( !this.kafkaPartitionHash.equals("default")
            && !this.kafkaPartitionHash.equals("murmur3") ) {
         usageForOptions("please specify --kafka_partition_hash=default|murmur3", "kafka_partition_hash");
      }

      if ( !this.kafkaKeyFormat.equals("hash") && !this.kafkaKeyFormat.equals("array") )
         usageForOptions("invalid kafka_key_format: " + this.kafkaKeyFormat, "kafka_key_format");
       ......

而mysql中缺失的配置,则是在AbstractConfig.java中,这是Maxwell最初的配置类

protected MaxwellMysqlConfig parseMysqlConfig(String prefix, OptionSet options, Properties properties) {
   MaxwellMysqlConfig config = new MaxwellMysqlConfig();
   config.host     = fetchStringOption(prefix + "host", options, properties, null);
   config.password = fetchStringOption(prefix + "password", options, properties, null);
   config.user     = fetchStringOption(prefix + "user", options, properties, null);
   config.port     = fetchIntegerOption(prefix + "port", options, properties, 3306);
   config.sslMode  = this.getSslModeFromString(fetchStringOption(prefix + "ssl", options, properties, null));
   config.setJDBCOptions(
       fetchStringOption(prefix + "jdbc_options", options, properties, null));

   // binlog_heartbeat isn't prefixed, as it only affects replication
   config.enableHeartbeat = fetchBooleanOption("binlog_heartbeat", options, properties, config.enableHeartbeat);
   return config;
}

可以见到,这里直接配置了mysql和binlog的相关信息

至此,初始化初期阶段结束

在这里插入图片描述

Maxwell初始化

回到main方法

public static void main(String[] args) {
   try {
      Logging.setupLogBridging();
      MaxwellConfig config = new MaxwellConfig(args);

      if ( config.log_level != null ) {
         Logging.setLevel(config.log_level);
      }

      final Maxwell maxwell = new Maxwell(config);

在完成初始化的参数配置后,main创建了一个Maxwell对象,同时将配置参数传递给这个对象

public Maxwell(MaxwellConfig config) throws SQLException, URISyntaxException {
   this(new MaxwellContext(config));
}

这个Maxwell维护一个MaxwellContext对象,并将config配置参数传递给它

MaxwellContext中创建一个C3P0ConnectionPool对象,并使用这个对象创建mysql的连接池

this.replicationConnectionPool = new C3P0ConnectionPool(
   config.replicationMysql.getConnectionURI(false),
   config.replicationMysql.user,
   config.replicationMysql.password
);

最后,开启一个线程,进行判断,如果hashMode存在,则使用maxwell HA模式,否则直接调用start()方法启动maxwell

public static void main(String[] args) {
   try {
      Logging.setupLogBridging();
      MaxwellConfig config = new MaxwellConfig(args);

      if ( config.log_level != null ) {
         Logging.setLevel(config.log_level);
      }

      final Maxwell maxwell = new Maxwell(config);

      Runtime.getRuntime().addShutdownHook(new Thread() {
         @Override
         public void run() {
            maxwell.terminate();
            StaticShutdownCallbackRegistry.invoke();
         }
      });

      LOGGER.info("Starting Maxwell. maxMemory: " + Runtime.getRuntime().maxMemory() + " bufferMemoryUsage: " + config.bufferMemoryUsage);

      if ( config.haMode ) {
         new MaxwellHA(maxwell, config.jgroupsConf, config.raftMemberID, config.clientID).startHA();
      } else {
         maxwell.start();
      }

至此,Maxwell初始化完成

在这里插入图片描述

maxwell启动

进入start方法:

public void start() throws Exception {
   try {
      this.startInner();
   } catch ( Exception e) {
      this.context.terminate(e);
   } finally {
      onReplicatorEnd();
      this.terminate();
   }

   Exception error = this.context.getError();
   if (error != null) {
      throw error;
   }
}
() throws Exception {
   try {
      this.startInner();
   } catch ( Exception e) {
      this.context.terminate(e);
   } finally {
      onReplicatorEnd();
      this.terminate();
   }

   Exception error = this.context.getError();
   if (error != null) {
      throw error;
   }
}

待续

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.英杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值