もう肥大化した Flink ストリーム処理プログラムを書くことを心配する必要はありません。Flink と Spring のエコロジーを完全に統合するスキャフォールディング プロジェクト、lazy squirrel Flink-Boot を見つけました。


Flink ストリーム処理アプリケーションを開発するときに、Spring Boot プログラムを開発するのと同じくらいエレガントに Bean を階層化してアセンブルできないことにまだ悩んでいますか?

次のような悩みに直面するかもしれません。

  1. 開発した Flink ストリーム処理アプリケーションでは、ビジネス ロジックはすべて Flink オペレーターで記述されており、コードを使用したり階層化したりすることはできません。
  2. Spring Boot プログラムの開発のように、Bean をエレガントに階層化して組み立てることができるようになれば、新しいオブジェクトは必要なくなります。
  3. さまざまな Spring エコロジカル フレームワークを使用でき、一部の些細なロジックがコードにハードコーディングされなくなりました。

GitHub で最近人気のあるオープン ソース フレームワークである怠惰なリス Flink-Boot スキャフォールディングは、Spring 開発エンジニアにとって単なる恩恵です。これは Spring エコシステムを完全に統合し、Java クラスで肥大化した Java オブジェクトを手動で作成する必要がなくなりました。大規模なストリーム処理アプリケーションを開発するのに不可欠なツールです。住所: Lazy Squirrel Flink-Boot Scaffolding は、「Flink Core Design and Practice Principles の詳細な理解」の著者によって開発されました。

インターフェースキャッシュ

あなたの現在の状況

static Map<String,String> cache=new HashMap<String,String>();

public String findUUID(FlowData flowData) {
    String value=cache.get(flowData.getSubTestItem());
    if(value==null)
    {
        String uuid=userMapper.findUUID(flowData);
        cache.put(uuid,value);
        return uuid;
    }
    return value;
}

あなたが欲しいのはこれです

@Cacheable(value = "FlowData.findUUID", key = "#flowData.subTestItem")
public String findUUID(FlowData flowData) {
    return userMapper.findUUID(flowData);
}

再試行メカニズム

あなたの現在の状況

public void insertFlow(FlowData flowData) {
    
    
    try{
    
    
        userMapper.insertFlow(flowData);
      }Cache(Exception e)
      {
    
    
         Thread.sleep(10000);
         userMapper.insertFlow(flowData);
      }
}

あなたが欲しいのはこれです

    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 1.5))
    @Override
    public void insertFlow(FlowData flowData) {
    
    
        userMapper.insertFlow(flowData);
    }

Bean の検証

あなたの現在の状況

if(flowData.getSubTestItem().length()<2&&flowData.getSubTestItem().length()>7)
{
    return null;
}
if(flowData.getBillNumber()==null)
{
    return null;
}

あなたが欲しいのはこれです

Map<String, StringBuffer> validate = ValidatorUtil.validate(flowData);
if (validate != null) {
    System.out.println(validate);
    return null;
}

public class FlowData {

    private String uuid;
    //声明该参数的校验规则字符串长度必须在7到20之间
    @Size(min = 7, max = 20, message = "长度必须在{min}-{max}之间")
    private String subTestItem;
    //声明该参数的校验规则字符串不能为空
    @NotBlank(message = "billNumber不能为空")
    private String billNumber;
}

等…

GitHub で最近人気のあるオープン ソース フレームワークである怠惰なリス Flink-Boot スキャフォールディングは、Spring 開発エンジニアにとって単なる恩恵です。これは Spring エコシステムを完全に統合し、Java クラスで肥大化した Java オブジェクトを手動で作成する必要がなくなりました。大規模なストリーム処理アプリケーションを開発するのに不可欠なツールです。Lazy Squirrel Flink-Boot Scaffolding は、「Flink Core Design and Practice Principles の詳細な理解」の著者によって開発されました。

ストリームコンピューティング開発エンジニアの問題を解決します

  1. すべてのオブジェクトの作成と依存関係の維持は Spring コンテナの管理に引き継がれるため、オブジェクト間の結合が減少し、コードがより簡潔になり、肥大化が回避されます。
  2. プロジェクト内でのシングルトンの過度の使用を排除します。
  3. 宣言型トランザクション処理を使用すると、手動でプログラミングすることなく、設定だけで管理を完了できます。
  4. 宣言型アノテーションでは、アノテーションを通じてメソッドのバッファ関数を定義し、順序なしで手動でプログラムできます。
  5. アノテーションはBeanオブジェクトの検証ルールを定義するもので、オブジェクトのパラメータ検証はアノテーションによって完了するため、手動でプログラミングする必要はありません。
  6. MyBatis ORM フレームワークを統合して、インスタンス オブジェクトの依存関係に注釈を付けます。
  7. Flink SQL を分離すると、SQL ステートメントが JAVA ファイルから取り除かれ、簡潔モードで XML ファイルに表現されます。
  8. Flink API をカプセル化し、ビジネス メソッドを提供するだけで、Spring のエコロジー統合はすべて完了しているため、心配する必要はありません。

これを使用すると、コードは次のようになります。

/**
* github地址: https://github.com/intsmaze
* 博客地址:https://www.cnblogs.com/intsmaze/
* 出版书籍《深入理解Flink核心设计与实践原理》 随书代码
* RichFlatMapFunction为Flink框架的一个通用型操作符(算子),开发者一般在该算子的flatMap方法中编写业务逻辑
* @auther: intsmaze(刘洋)
* @date: 2020/10/15 18:33
*/
public class MybatisFlatMap extends RichFlatMapFunction<String, String> {

   private static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

    protected ApplicationContext beanFactory;
    //mybatis的Service对象,操作数据库的user表
    private UserService userService;

    @Override
    public void open(Configuration parameters) {
        ExecutionConfig.GlobalJobParameters globalJobParameters = getRuntimeContext()
                .getExecutionConfig().getGlobalJobParameters();
        beanFactory = BeanFactory.getBeanFactory((Configuration) globalJobParameters);
        
        userService = beanFactory.getBean(UserServiceImpl.class);
    }

    @Override
    public void flatMap(String value, Collector<String> out){

        FlowData flowData = gson.fromJson(message, new TypeToken<FlowData>() {
        }.getType());
        Map<String, StringBuffer> validate = ValidatorUtil.validate(flowData);
        if (validate != null) {
            System.out.println(validate);
            return null;
        }
        //数据库查询,屏蔽掉获取数据库连接,是否数据库连接,事务的声明等
        String flowUUID = userService.findUUID(flowData);
        if (StringUtils.isBlank(flowUUID)) {
            flowUUID = UUID.randomUUID().toString();
            flowData.setUuid(flowUUID);
            //数据库插入,屏蔽掉获取数据库连接,是否数据库连接,事务的声明等
            userService.insertFlow(flowData);
        }
        out.collect(gson.toJson(flowData));
    }
}


public interface UserService {

    String findUUID(FlowData flowData);

    void insertFlow(FlowData flowData);
}

//通过注解实例化Bean对象。
@Service
//通过注解声明进行事务管理
@Transactional
//通过注解声明方法具有异常重试机制
@EnableRetry
public class UserServiceImpl implements UserService {
   //通过注解进行依赖注入
    @Resource
    private UserMapper userMapper;

    @Cacheable(value = "FlowData.findUUID", key = "#flowData.subTestItem")
    @Override
    public String findUUID(FlowData flowData) {
        return userMapper.findUUID(flowData);
    }
    
   //通过注解声明该方法异常后的重试机制,无需手动编程
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 1.5))
    @Override
    public void insertFlow(FlowData flowData) {
        userMapper.insertFlow(flowData);
    }
}

public interface UserMapper {

    String findUUID(FlowData flowData);

    void insertFlow(FlowData flowData);
}

//注解式声明参数校验规则
public class FlowData {

    private String uuid;
    //声明该参数的校验规则字符串长度必须在7到20之间
    @Size(min = 7, max = 20, message = "长度必须在{min}-{max}之间")
    private String subTestItem;
    //声明该参数的校验规则字符串不能为空
    @NotBlank(message = "billNumber不能为空")
    private String billNumber;

    @NotBlank(message = "barcode不能为空")
    private String barcode;

    private String flowName;

    private String flowStatus;

    ......
}

倉庫のアドレス: Lazy squirrel Flink-Boot

倉庫の住所: Lazy Squirrel Flink-Bootスキャフォールディングは、「Flink コアの設計と実践原則の詳細な理解」の著者によって開発されました。

  1. スキャフォールディングによって Flink API の組み立ての詳細が保護されるため、境界を越えることが容易になり、開発者は従来の Java WEB 開発モードで分散コンピューティング機能を備えたストリーム処理プログラムを開発できるようになります。

  2. 開発者は、分散コンピューティングの理論的知識や Flink フレームワークの詳細を理解していなくても、ビジネス コードを迅速に作成できます。

  3. スキャフォールディングプロジェクトでは、大規模プロジェクトの開発においてスキャフォールディングを利用する開発者の機敏性をさらに向上させるため、Bean管理にSpringフレームワークをデフォルトで統合するとともに、WEB開発の分野でよく使われるマイクロサービスやフレームワークを統合し、開発速度をさらに向上させています。

  4. さらに、現在普及している主要な Java フレームワークについては、次のような開発者のコ​​ーディング速度を向上させるために、Flink スキャフォールディング プロジェクトも統合されています。

  • Jbcp テンプレートを統合して、Mysql、Oracle、SQLServer などのリレーショナル データベースにすばやくアクセスします。
  • パラメーター検証のために Hibernate Validator フレームワークを統合します。
  • 再試行フラグ用に Spring Retry フレームワークを統合します。
  • Mybatis フレームワークを統合して、リレーショナル データベースの追加、削除、変更、チェックの開発速度を向上させます。
  • Spring Cache フレームワークを統合して、アノテーション スタイルの定義メソッド キャッシュを実装します。

1. 組織体制

Flink-Boot
├── Flink-Base -- Flink-Boot工程基础模块
├── Flink-Client -- Flink-Boot 客户端模块
├── flink-annotation -- 注解生效模块
├── flink-mybatis -- mybatis orm模块
├── flink-retry -- 注解重试机制模式
├── flink-validate -- 校验模块
├── flink-sql -- Flink SQL解耦至XML配置模块
├── flink-cache-annotation -- 接口缓冲模块
├── flink-junit -- 单元测试模块
├── flink-apollo -- 阿波罗配置客户端模块

2. テクノロジーのオプションと統合

テクノロジー 名前
春のフレームワーク 容器 統合された
Spring は XML に基づいて Bean を構成します アセンブリBean 統合された
Spring はアノテーションに基づいて Bean を構成します アセンブリBean 統合された
Spring はアノテーションに基づいてメソッドの再試行メカニズムを宣言します アノテーションの再試行 統合された
Spring はアノテーションに基づいてメソッドのキャッシュを宣言します キャッシュアノテーション 統合された
Hibernate バリデーター 検証フレームワーク 統合された
ドルイド僧 データベース接続プール 統合された
マイバティス ORMフレームワーク 統合された
カフカ メッセージキュー 統合された
HDFS 分散ファイルシステム 統合された
Log4J ログコンポーネント 統合された
ジュニット 単体テスト 統合された
マイバティスプラス MyBatis 拡張パック 進行中
ページヘルパー MyBatis 物理ページング プラグイン 進行中
動物園の飼育員 分散調整サービス 進行中
ダボ 分散サービスフレームワーク 進行中
レディス 分散キャッシュデータベース 進行中
Solr と Elasticsearch 分散型全文検索エンジン 進行中
Eキャッシュ インプロセスキャッシュフレームワーク 進行中
順序 分散型の効率的なID作成 進行中
ダッボール消費者 サービス消費者 進行中
Spring eurake コンシューマー サービス消費者 進行中
Apollo 構成センター Ctrip Apollo 構成センター 進行中
Spring Config 構成センター Spring Cloud Config 構成センター 進行中

3. クイックスタート

以下は Spring Ecology を統合するための基本マニュアルです。

3.1 コア基礎エンジニアリング

  • flink-base : Flink プロジェクトの開発に必要なパラメータをカプセル化する基本プロジェクト。同時に Spring コンテナを統合し、その後のさまざまな Spring フレームワークの統合をサポートします。
    1. ローカル開発環境と Flink クラスターオペレーティング環境を自由に切り替えることができます。
    2. 増分チェックポイントと完全チェックポイントを自由に切り替えることができます。
    3. チェックポイント用の永続ストレージ メディアとしての HDFS の組み込み使用。
    4. デフォルトでは、Kafka がデータ ソースとして使用されます
    5. タスク一時停止メカニズムの組み込み実装により、タスクはまだ実行中ですが、Kafka データ ソースからデータを受信しなくなり、タスクを停止した後にタスクを再デプロイするという面倒なプロセスが置き換えられます。
  • flink-client: flink-base プロジェクトに依存するビジネス プロジェクト。開発タスクは、このプロジェクトでビジネス ロジックを開発することです。

3.2 スプリングコンテナ

コンテナ モードは JdbcTemplate インスタンスで構成され、データベース接続プールは Druid を使用します。ビジネス メソッドでは、コンテナ内で JdbcTemplate インスタンスを取得するだけで、リレーショナル データベースとすばやく対話できます。dataService インスタンスは、データベース テーブルにアクセスするためのいくつかのメソッドをカプセル化します。

トポロジーベース.xml
<beans ......
       default-lazy-init="true" default-init-method="init">

    <context:property-placeholder location="classpath:config.properties"/>

    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url"
                  value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg ref="druidDataSource"></constructor-arg>
    </bean>
    
    <bean id="dataService" class="com.intsmaze.flink.base.service.DataService">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

</beans>
config.properties
jdbc.user = intsmaze
jdbc.password = intsmaze
jdbc.url = jdbc:mysql://127.0.0.1:3306/flink-boot?useUnicode=true&characterEncoding=UTF-8

3.3 スタートアップクラスの例

以下は、BaseFlinkを継承したSimpleClient(com.intsmaze.flink.client.SimpleClient)クラスのサンプルコードで、対応する実装メソッドが以下のように設定されていることがわかります。

  • public String getTopoName(): このジョブの名前を定義します。
  • public String getConfigName(): このジョブが読み取る必要がある Spring 構成ファイルの名前を定義します
  • public String getPropertiesName(): このジョブが読み取る必要があるプロパティ構成ファイルの名前を定義します。
  • public void createTopology(StreamExecutionEnvironment builder): このジョブのトポロジを構築します。
/**
 * github地址: https://github.com/intsmaze
 * 博客地址:https://www.cnblogs.com/intsmaze/
 * 出版书籍《深入理解Flink核心设计与实践原理》 随书代码
 *
 * @auther: intsmaze(刘洋)
 * @date: 2020/10/15 18:33
 */
public class SimpleClient extends BaseFlink {

    public static void main(String[] args) throws Exception {
        SimpleClient topo = new SimpleClient();
        topo.run(ParameterTool.fromArgs(args));
    }

    @Override
    public String getTopoName() {
        return "SimpleClient";
    }

    @Override
    public String getConfigName() {
        return "topology-base.xml";
    }

    @Override
    public String getPropertiesName() {
        return "config.properties";
    }

    @Override
    public void createTopology(StreamExecutionEnvironment builder) {

        DataStream<String> inputDataStrem = env.addSource(new SimpleDataSource());

        DataStream<String> processDataStream = inputDataStrem.flatMap(new SimpleFunction());

        processDataStream.print("输出结果");
    }

}

3.4 データソース

カスタム データ ソースを採用するには、ユーザーはカスタム DataSource クラスを作成する必要があります。このクラスは、XXX 抽象クラスを継承し、次のメソッドを実装する必要があります。

  • public abstract void open(StormBeanFactory beanFactory): このジョブの Spring 構成ファイルで構成された Bean オブジェクトを取得します。
  • public abstract String sendMessage(): このジョブのスパウトでデータを生成するメソッドで、ビジネスロジックを記述してソースデータを生成し、生成されたデータをString型で返します。
public class SimpleDataSource extends CommonDataSource {

    private static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
	......

    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        ...//构造读取各类外部系统数据的连接实例
    }

    @Override
    public String sendMess() throws InterruptedException {
        Thread.sleep(1000);
		......
        MainData mainData = new MainData();
        ......//通过外部系统数据的连接实例读取外部系统数据,封装进MainData对象中,然后返回即可。
        return gson.toJson(mainData);
    }
}

3.5 ビジネスロジックの実装

このジョブ計算のビジネス ロジックは Flink 変換演算子に実装されており、一般的に、開発者は flatMap 演算子を実装するだけで、ほとんどの演算子の使用に対応できます。

ユーザーが作成したカスタム クラスは、com.intsmaze.flink.base.transform.CommonFunction 抽象クラスを継承する必要があり、すべて次のメソッドを実装する必要があります。

  • public abstract Stringexecute(String message): このジョブのビジネス ロジックを計算するためのメソッドです。パラメータ メッセージは、Kafka トピックから読み取られるパラメータです。デフォルトのパラメータは String 型です。処理されたデータを Kakfa トピックに送信する必要がある場合は、return を通じて処理されたデータを返す必要があります。
public class SimpleFunction extends CommonFunction {

    private static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
    
    @Override
    public String execute(String message) throws Exception {
        FlowData flowData = gson.fromJson(message, new TypeToken<FlowData>() {
        }.getType());

        String flowUUID = dataService.findUUID(flowData);
        if (StringUtils.isBlank(flowUUID)) {
            flowUUID = UUID.randomUUID().toString();
            flowData.setUuid(flowUUID);
            dataService.insertFlow(flowData);
        }
        return gson.toJson(flowData);
    }
}
共通機能

CommonFunction 抽象クラスでは、デフォルトで、Spring コンテナの dataService インスタンスは、open メソッドの BeanFactory オブジェクトを通じて取得されます。Spring の他のインスタンスについては、SimpleFunction クラスの open メソッドで同じものを取得できます。

public abstract class CommonFunction extends RichFlatMapFunction<String, String> {

    private IntCounter numLines = new IntCounter();

    protected DataService dataService;

    protected ApplicationContext beanFactory;

    @Override
    public void open(Configuration parameters) {
        getRuntimeContext().addAccumulator("num-FlatMap", this.numLines);

        ExecutionConfig.GlobalJobParameters globalJobParameters = getRuntimeContext()
                .getExecutionConfig().getGlobalJobParameters();
        beanFactory = BeanFactory.getBeanFactory((Configuration) globalJobParameters);

        dataService = beanFactory.getBean(DataService.class);
    }

    @Override
    public void flatMap(String value, Collector<String> out) throws Exception {
        this.numLines.add(1);
        String execute = execute(value);
        if (StringUtils.isNotBlank(execute)) {
            out.collect(execute);
        }
    }

    public abstract String execute(String message) throws Exception;

}

状況に応じて open(Configurationparameters) メソッドを書き換えることができますが、同時に、書き換えられた open(Configurationparameters) メソッドの最初の行で、親クラスの open(Configurationparameters) メソッドを呼び出す必要があります。

public void open(Configuration parameters){
	super.open(parameters);
	......
	//获取在Spring配置文件中配置的实例
	XXX xxx=beanFactory.getBean(XXX.class);
}

3.6 クラスタ/ローカル運用

カスタム Topology クラスに Main メソッドを記述し、カスタム Topology オブジェクトを作成した後、オブジェクトの run(…) メソッドを呼び出します。

public class SimpleClient extends BaseFlink {

/**
 * 本地启动参数  -isLocal local
 * 集群启动参数  -isIncremental isIncremental
 */
public static void main(String[] args) throws Exception {
    SimpleClient topo = new SimpleClient();
    topo.run(ParameterTool.fromArgs(args));
}

.......     

おすすめ

転載: blog.csdn.net/hbly979222969/article/details/110621989