component的生命周期怎么理解

这篇文章主要介绍“component的生命周期怎么理解”,在日常操作中,相信很多人在component的生命周期怎么理解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”component的生命周期怎么理解”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

storm中的spout,bolt的生命周期,都是storm帮你管理好,你只要新建一个实例,指定该component的并行数,就可以。那么topology中所用到的工具类的生命周期该如何处理,例如数据库连接池、redis的连接池,这些对象该放在哪里初始化?本文以jdbc连接池为例,讨论此问题。阅读本文前请先自行了解storm topology的运行流程。

Storm Component的生命周期

storm component泛指topoloty中的spout、bolt,是spout和bolt的一个统称。而component生命周期,我结合storm作者nathanmarz大神的回答和自己的理解,描述一下:

1,当提交了topology后,spout、bolt的实例会在本地机器(执行storm submit所在的机器)上被创建,并且在本地序列化。另外,所有的component的构造函数、declareOutputFields方法都本地会运行一次。

2,整个topology被上传到nimbus上。

3,对应supervisor会向nimbus获取序列化后的topology代码,交给对应的worker执行。

4,每个worker执行如下:反序列化代码,运行对应component的prepare/open(初始化对应的component)。举个例子,某spout在topology中设置了3个并行度,且topology设置了3个worker,该open方法就会在3个不同的worker上分别调用1次,共调用3次。

5,worker通知executor不断循环去跑nextTuple/execute方法。

需要注意一点:component的初始化相关的操作应放在prepare/open方法中执行, 而不是在实例化component的时候进行或者topology的main函数。

Jdbc Pool 初始化方案

参考component的生命周期,能想到有两种方案:

1,每个component都维持一个与数据库的连接,此种方案适合于写操作非常频繁,component数目比较少,且中间不会有一段时间没有任何写、读操作,否则会发生mysql connection timeout;另外可省去从连接池获取连接,用完连接后返回给连接池这两步操作。如果确定这种方案,则只要将数据库的配置放到config中,在对应的component中初始化数据库连接即可。

2,在每worker中维持一个连接池,worker中所有executor需要用到连接时,从连接池中获取,用后归还。一般还是推荐这种方案。

下面说一下第二种方案的连接池,应该在什么时候初始化。

首先明确一点,在topology运行中,一个worker相当于jvm进程,相当于有N个worker,就会有N个连接池。初始化连接池的动作需要在worker端进行,一个worker中只有一个连接池的实例,适合用单例模式。

初始化思路:每个component接收数据库配置信息,在其prepare/open时,初始化连接池,这里需要保证在单个worker中只需要初始化一次就可以,即对初始化的代码加锁处理,保证只能有一个component初始化。

在storm源码包中,提供了storm-jdbc的实现,其中用了JDBC 连接池组件,具体实现思路就是上面讨论的第二种方案。以下为初始化时加锁的部分。

public class HikariCPConnectionProvider implements ConnectionProvider {

    private Map<String, Object> configMap;
    private transient HikariDataSource dataSource;

    public HikariCPConnectionProvider(Map<String, Object> hikariCPConfigMap) {
        this.configMap = hikariCPConfigMap;
    }

    @Override
    public synchronized void prepare() {
        if(dataSource == null) {
            Properties properties = new Properties();
            properties.putAll(configMap);
            HikariConfig config = new HikariConfig(properties);
            this.dataSource = new HikariDataSource(config);
            this.dataSource.setAutoCommit(false);
        }
    }

    @Override
    public Connection getConnection() {
        try {
            return this.dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void cleanup() {
        if(dataSource != null) {
            dataSource.shutdown();
        }
    }
}

看到,初始化prepare被上锁了,以保证只初始化一次。其实这里可以再优化一下:不要对方法加锁,而是对具体初始化连接的代码加锁,减少锁影响的范围。

到此,关于“component的生命周期怎么理解”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注蜗牛博客网站,小编会继续努力为大家带来更多实用的文章!

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

评论

有免费节点资源,我们会通知你!加入纸飞机订阅群

×
天气预报查看日历分享网页手机扫码留言评论Telegram