Slide 1

Slide 1 text

1 Copyright © Acroquest Technology Co., Ltd. All rights reserved. サーバーレスをJavaで組むための Spring Cloud Function入門 2019-07-18 Acroquest Technology株式会社 阪本 雄一郎 関ジャバ’19 7月度

Slide 2

Slide 2 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 2 阪本 雄一郎 @phonypianist アクロクエストテクノロジー株式会社 シニアアーキテクト 兼 大阪事業所所長 • IoT、サーバーレスアーキテクチャ - 社会インフラ向け制御システム - 公共交通向け設備管理システム • BCI • 「Java本格入門」執筆

Slide 3

Slide 3 text

Acroquestのミッション・ビジョン Copyright © Acroquest Technology Co., Ltd. All rights reserved. 3 テクノロジストチームとして ビジネスの革新的価値創出に挑戦する ビジョン Acroquestの創り出す技術で 地球を感動で進化させる ミッション

Slide 4

Slide 4 text

「働きがいのある会社(GPTW)」 ランキング(従業員25~99人部門) 1位 を 3回 受賞 1位 1位 1位

Slide 5

Slide 5 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 5 はじめに

Slide 6

Slide 6 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 6 タイトルに「サーバーレス」 と書きましたが、 今回のポイントはサーバーレス ではありません

Slide 7

Slide 7 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 7 Spring Cloud Functionは、 あらゆる処理を 抽象化した「Function」として 統一的に扱うことにより システムを構築可能にすること です

Slide 8

Slide 8 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 8 Functionを実装しましょう。

Slide 9

Slide 9 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 9 おわり。

Slide 10

Slide 10 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 10 といったら史上最速で終わってしまうので・・・

Slide 11

Slide 11 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 11 イメージしやすいサーバーレスから 入っていくことにします

Slide 12

Slide 12 text

①Serverless Architectureのおさらい ②Spring Cloud Functionとは ③Hello Spring Cloud Function! ④Spring Cloud Function 「入門」 ⑤まとめ Copyright © Acroquest Technology Co., Ltd. All rights reserved. 12 目次

Slide 13

Slide 13 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 13 Serverless Architecture のおさらい ①

Slide 14

Slide 14 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 14 Serverless Architecture とは

Slide 15

Slide 15 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 15 サーバ管理を考慮しなくてよい アーキテクチャ

Slide 16

Slide 16 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 16 クラウドベンダーが管理 クラウドベンダーが管理 開発者は 業務ロジックのみに集中 Function

Slide 17

Slide 17 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 17 そうは問屋が卸さない

Slide 18

Slide 18 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 18 1. クラウドベンダー依存のコード 2. アプリケーションのライフサイクル がアンコントローラブル

Slide 19

Slide 19 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 19 AWS Lambdaの例 https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/get-started-step4-optional.html より引用 public class Hello { public String myHandler(int myCount, Context context) { LambdaLogger logger = context.getLogger(); logger.log("received : " + myCount); return String.valueOf(myCount); } }

Slide 20

Slide 20 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 20 Azure Functionsの例 https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-java より引用 public class Function { public String echo(@HttpTrigger(name = "req", methods = {"post"}, authLevel = AuthorizationLevel.ANONYMOUS) String req, ExecutionContext context) { return String.format(req); } }

Slide 21

Slide 21 text

public class Function { public String echo(@HttpTrigger(name = "req", methods = {"post"}, authLevel = AuthorizationLevel.ANONYMOUS) String req, ExecutionContext context) { return String.format(req); } } Copyright © Acroquest Technology Co., Ltd. All rights reserved. 21 Azure Functionsの例 https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-java より引用 java.util.Functionと 同じ名前はやめよう これはいったい・・・ 型が合ってない

Slide 22

Slide 22 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 22 レビューしたいわけじゃない

Slide 23

Slide 23 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 23 AWS Lambdaと Azure Functionsで 書き方が違う

Slide 24

Slide 24 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 24 AWS Lambdaの例 public String myHandler(int myCount, Context context) { public String echo(@HttpTrigger(name = "req", methods = {"post"}, authLevel = AuthorizationLevel.ANONYMOUS) String req, ExecutionContext context) { Azure Functionsの例

Slide 25

Slide 25 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 25 クラウドベンダー依存の関数 ロジックもそれに引きずられる テストや動作確認がしづらくなる アジリティの低下

Slide 26

Slide 26 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 26 違いを気にせず書きたい 意識を「処理」に集中させたい テストしやすくしたい

Slide 27

Slide 27 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 27 そこで Spring Cloud Function

Slide 28

Slide 28 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 28 Spring Cloud Function とは ②

Slide 29

Slide 29 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 29 Spring Cloud Functionとは ロジックをすべて「Function」として 記述できるようにしたもの

Slide 30

Slide 30 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 30 Spring Cloud Functionの特徴 1. クラウド非依存な書き方 (呼び出し部分) 2. API提供 3. 定義による構築 勝手に選んだ

Slide 31

Slide 31 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 31 Spring Cloud Functionの特徴 1. クラウド非依存な書き方 (呼び出し部分) 2. API提供 3. 定義による構築

Slide 32

Slide 32 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 32 Spring Cloud Function 業 務 ロ ジ ッ ク (Function) AWS 基盤 Azure 基盤 クラウドに依存しない 関数定義 Open whisk 基盤 AWS Adapter Azure Adapter Openwhisk Adapter クラウド依存部分を 吸収

Slide 33

Slide 33 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 33 Spring Cloud Functionの特徴 1. クラウド非依存な書き方ができる (呼び出し部分) 2. API提供 3. 定義による構築

Slide 34

Slide 34 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 34 Function (Supplier/Consumer) はAPI公開される

Slide 35

Slide 35 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 35 FunctionでAPI部品を構築する

Slide 36

Slide 36 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 36 Spring Cloud Function 業 務 ロ ジ ッ ク (Function) curl POST http://localhost:8080/function {"message": "hello"} Bean名 Controller不要

Slide 37

Slide 37 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 37 Spring Cloud Function 業 務 ロ ジ ッ ク (Supplier) curl GET http://localhost:8080/supplier Bean名 Controller不要

Slide 38

Slide 38 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 38 Spring Cloud Function 業 務 ロ ジ ッ ク (Consumer) curl POST http://localhost:8080/consumer {"message": "hello"} Controller不要 Bean名

Slide 39

Slide 39 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 39 Spring Cloud Functionの特徴 1. クラウド非依存な書き方ができる (呼び出し部分) 2. API提供 3. 定義による構築

Slide 40

Slide 40 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 40 spring-cloud-function-compiler を追加することで、 application.ymlに Functionを定義できる

Slide 41

Slide 41 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 41 アプリケーション起動時に コンパイル→Bean登録 ※クラウドのサーバーレス基盤 (AWS Lambda/Azure Functions)は JREのため、この機能は使用できない

Slide 42

Slide 42 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 42 定義で記述されたFunctionも 普通のFunctionと同じ API公開される

Slide 43

Slide 43 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 43 Spring Cloud Function application.yml の upper 定 義 curl POST http://localhost:8080/upper {"message": "hello"} 定義名 (Bean名)

Slide 44

Slide 44 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 44 spring-cloud-function-task を追加することで、 application.ymlに Functionのタスクフローを定義できる

Slide 45

Slide 45 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 45 consumer function supplier function

Slide 46

Slide 46 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 46 ロジックを細分化し Functionに分離することで、 抽象度・独立性を高める

Slide 47

Slide 47 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 47 Hello Spring Cloud Function! ③

Slide 48

Slide 48 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 48 @SpringBootApplication public class Application { public static void main(String... args) { SpringApplication.run(Application.class, args); } } メインクラス(ローカル起動用) 普通のSpringBoot アプリと同じ

Slide 49

Slide 49 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 49 @Component("echo") public class EchoFunction implements Function, Flux> { @Override public Flux apply(Flux requestParam) { return requestParam.map( param -> new EchoResponse(param.getMessage())); } } java.util.Functionを実装 Supplier/ConsumerもOK reactor.core.publisher.Flux 業務ロジック

Slide 50

Slide 50 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 50 MANIFEST.MFのStart-Classに Applicationクラスを指定する spring-boot-maven-pluginと maven-shade-pluginがやってくれる

Slide 51

Slide 51 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 51 AWS Lambda 基 盤 SpringBootApiGateway RequestHandler EchoFunction API Gateway Lambda Spring Cloud Function SQSの場合は SpringBootRequestHandler 業務ロジック

Slide 52

Slide 52 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 52 テストは2通り 1. Springを使わない場合 2. Springを使う場合

Slide 53

Slide 53 text

class EchoFunctionTest { @Test void echo() { EchoFunction echoFunction = new EchoFunction(); EchoRequest echoRequest = new EchoRequest(); echoRequest.setMessage("foo"); EchoResponse echoResponse = echoFunction.apply(echoRequest); assertThat(echoResponse.getMessage()).isEqualTo("foo"); } } Copyright © Acroquest Technology Co., Ltd. All rights reserved. 53 1. Springを使わない場合

Slide 54

Slide 54 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 54 class EchoFunctionTest { @Test void echoWithSpring() { System.setProperty("function.name", "echo"); try (SpringBootApiGatewayRequestHandler requestHandler = new SpringBootApiGatewayRequestHandler(Application.class)) { APIGatewayProxyRequestEvent requestEvent = new APIGatewayProxyRequestEvent().withBody("{¥"message¥":¥"foo¥"}"); APIGatewayProxyResponseEvent responseEvent = (APIGatewayProxyResponseEvent) requestHandler.handleRequest( requestEvent, null); assertThat(responseEvent.getBody()).isEqualTo("{¥"message¥":¥"foo¥"}"); } } } 呼び出す関数を指定 (デフォルトはfunction) 2. Springを使う場合 (API Gateway)

Slide 55

Slide 55 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 55 Springのライブラリを使ってみる

Slide 56

Slide 56 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 56 @SpringBootApplication public class Application { public static void main(String... args) { SpringApplication.run(Application.class); } @Bean WebClient webClient() { return WebClient.create(); } } SpringのWebClientを使ってみる SpringBootアプリと同じく Bean定義

Slide 57

Slide 57 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 57 SpringのWebClientを使ってみる @Component("dispatch") public class DispatchFunction implements Function, Flux> { private final WebClient webClient; private final Environment environment; public DispatchFunction(WebClient webClient, Environment environment) { this.webClient = webClient; this.environment = environment; } @Override public Flux apply(Flux requestParam) { String uri = environment.getProperty("app.echo.uri"); return requestParam.flatMap(param -> webClient .post().uri(uri).body(BodyInserters.fromObject(param)) .retrieve().bodyToMono(EchoResponse.class)); } } SpringBootアプリと同じく Autowired

Slide 58

Slide 58 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 58 Componentが増えると 初期化が遅くなる 自前で登録する

Slide 59

Slide 59 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 59 Componentを自前で登録する @SpringBootApplication public class Application implements ApplicationContextInitializer { public static void main(String... args) { SpringApplication.run(Application.class, args); } Function echo() { return new EchoFunction(); } @Override public void initialize(GenericApplicationContext context) { context.registerBean("echo", FunctionRegistration.class, () -> new FunctionRegistration<>(echo()) .type(FunctionType.from(EchoRequest.class).to(EchoResponse.class))); } } class EchoFunctionからは @Componentを削除しておく Functionを1つずつ登録

Slide 60

Slide 60 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 60 spring-cloud-function-compiler を使って Functionをapplication.ymlに定義

Slide 61

Slide 61 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 61 spring.cloud.function: compile: upper: type: function inputType: dto.Message outputType: dto.Message lambda: message -> new dto.Message(message.getText().toUpperCase()) Bean名 supplier/function/consumer application.yml FunctionをLambda式で記述

Slide 62

Slide 62 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 62 spring-cloud-function-task を使って タスクフローを定義

Slide 63

Slide 63 text

spring.cloud.function: compile: textGenerator: type: supplier outputType: Flux lambda: () -> Flux.fromIterable(List.of(new dto.Message("hoge"), new dto.Message("fuga"), new dto.Message("piyo"))) upper: type: function inputType: dto.Message outputType: dto.Message lambda: message -> new dto.Message(message.getText().toUpperCase()) decorator: type: function inputType: dto.Message outputType: dto.Message lambda: message -> new dto.Message("[" + message.getText() + "]") Copyright © Acroquest Technology Co., Ltd. All rights reserved. 63 application.yml printer: type: consumer inputType: dto.Message lambda: System.out::println task: supplier: textGenerator function: upper|decorator consumer: printer supplier/function/consumerと関連付ける 「|」を使って複数のFunctionをつなげる

Slide 64

Slide 64 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 64 アプリケーション起動直後に タスクフローが実行される

Slide 65

Slide 65 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 65 ロジックを細分化してFunctionに Queueから読み取り順次処理 用途例

Slide 66

Slide 66 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 66 もう使いこなせますよね!

Slide 67

Slide 67 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 67 Spring Cloud Function 「入門」 ④

Slide 68

Slide 68 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 68 「入門」=門に入る

Slide 69

Slide 69 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 69 Spring Cloud Function 宅にお邪魔します

Slide 70

Slide 70 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 70 AWS Lambda 基 盤 SpringBoot RequestHandler EchoFunction API Gateway Lambda Spring Cloud Function どこでFluxに? Spring Contextの初期化は?

Slide 71

Slide 71 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 71 人ん家を物色して盗むべし ソースを読んで理解すべし

Slide 72

Slide 72 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 72 public Object handleRequest( E event, Context context) { initialize(); Object input = convertEvent(event); Publisher output = apply(extract(input)); return result(input, output); } SpringBootRequestHandler エントリーポイント 初期化 →親クラスの SpringFunctionInitializerへ 関数呼び出し

Slide 73

Slide 73 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 73 protected void initialize() { if (!this.initialized.compareAndSet( false, true)) { return; } logger.info("Initializing: " + this.configurationClass); SpringApplication builder = springApplication(); this.context = builder.run(); context.getAutowireCapableBeanFactory() .autowireBean(this); String name = context.getEnvironment() .getProperty("function.name"); if (name == null) { name = "function"; } if (this.catalog == null) { if (context.containsBean(name)) { this.function = getAndInstrumentFromContext(name); } } else { SpringFunctionInitializer SpringBoot 初期化 呼び出すFunction名 の取得

Slide 74

Slide 74 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 74 Springの初期化は 関数が初めて呼び出された 「直後」に行われる ※呼び出される直前ではない

Slide 75

Slide 75 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 75 public Object handleRequest( E event, Context context) { initialize(); Object input = convertEvent(event); Publisher output = apply(extract(input)); return result(input, output); } protected Object convertEvent(E event) { return event; } private Flux extract(Object input) { if (input instanceof Collection) { return Flux.fromIterable((Iterable) input); } return Flux.just(input); } private Object result( Object input, Publisher output) { List result = new ArrayList<>(); for (Object value : Flux.from(output).toIterable()) { result.add(convertOutput(value)); } if (isSingleValue(input) && result.size() == 1) { return result.get(0); } return result; } SpringBootRequestHandler コレクションから Fluxに変換 Fluxからリストに 変換

Slide 76

Slide 76 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 76 API Gatewayの場合、 Fluxの効果はない

Slide 77

Slide 77 text

@Override protected Object convertEvent(KinesisEvent event) { List payloads = deserializePayloads(event.getRecords()); if (functionAcceptsMessage()) { return wrapInMessages(payloads); } else { return payloads; } } Copyright © Acroquest Technology Co., Ltd. All rights reserved. 77 SpringBootKinesisEventHandler レコードのリストを取得 →Flux化 SpringBootRequestHandlerのサブクラス

Slide 78

Slide 78 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 78 Kinesis Data Streamの場合、 Fluxの効果はありそう

Slide 79

Slide 79 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 79 SpringFunctionInitializer SpringBootRequestHandler SpringBootApiGateway RequestHandler SpringBootKinesisEventHandler SpringApplication FunctionalSpringApplication 継承 依存 手抜きクラス図

Slide 80

Slide 80 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 80 まとめ ⑤

Slide 81

Slide 81 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 81 1. Spring Cloud Functionで、 ロジックを「Function」という形で抽象化して 扱える 2. Reactorが使える、ただし効果の有無は注意 3. お宅訪問重要! https://github.com/phonypianist/spring-cloud-function-example サンプルコードはここに置きました。

Slide 82

Slide 82 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 82 Enjoy Spring Cloud Function & Code Reading! Evolve the Earth with Emotion of Technology