KINTOテクノロジーズのブログ - TECH PLAY

TECH PLAY

KINTOテクノロジーズ

KINTOテクノロジーズ の技術ブログ

1113

Introduction My name is Hoang, I am a backend engineer who is responsible for Europe and South America as part of the Global KINTO ID Platform (GKIDP) team at Global Group in KINTO Technologies (KTC). We deal with global problems to authenticate users all over the world. Providing a fast, reliable, and highly available Identity and Access Management (IAM) system is a MUST with GKIDP. In this article, I would like to share my thoughts on how we could do load-balancing/route traffic on any kind of cross-border system. We know that HTTP (or UDP, DNS also) are stateless protocols, which means that each request from clients to servers does not retain any information from the previous request, but why it should be stateless, and what for? The deep reason is a stateless protocol can be load balanced for scale architecture since any request can be routed to any web server without concern about each request state. That makes web servers can be horizontally scalable by spreading servers in global maps for making the system resilient and high-performance. In this article, I would like to introduce two main types of load balancing: DNS Routing and hardware load balancer (a.k.a Load balancer). These two methods are separate from each other but can be mixed to enhance global systems like KINTO vehicle subscription services. DNS Routing When the user types a URL into the browser, the browser will send a DNS query to the DNS server to get the IP address associated with the hostname of the website. The browser will use that IP address and not the domain of the website to access the server. The simplest flow is like the below: ![](/assets/blog/authors/pham.hoang/figure-2.png =600x) Figure 2. DNS Routing In this case, where the system contains multiple servers across regions, the DNS server's responsibility is to route the client to the most appropriate server to improve performance and availability. The way DNS decides where to forward requests is called DNS routing. DNS routing is an easy configuration with a high scalability method because it does not touch user requests. Frequently, it is used to route users among data centers or regions. Some common DNS routing methods are simple Round Robin, and dynamic methods like geo-location-based, latency-based, and health based. DNS routing has drawbacks like outdated DNS cache problems: DNS always returns the same IP address for one domain in TTL (time-to-live) duration even if that server is down. There is a confusion that must be explained here: DNS does not route any traffic, it only responds to the DNS queries the IP address — the location where the user should send traffic. In Fig. 2, from step 3: After getting the server IP address, the client really sends traffic (like HTTP requests) to the target server, and the hardware load balancer takes the place to distribute traffic among multiple backend servers behind it. I will explain in detail the hardware load balancer in the next part. Hardware Load balancer After receiving the translated IP address corresponding to the domain, the client will send the traffic to the target server. From now, the hardware load balancer stands in front of a fleet of backend servers and distributes traffic to these web servers. Indeed, the hardware load balancer is nothing but a reversed proxy — a physical device that takes responsibility as a coordinator of the system. ![](/assets/blog/authors/pham.hoang/figure-3.png =600x) Figure 3. Load balancer as reversed proxy There are 2 main kinds of hardware load balancing: layer 4 load balancing and layer 7 load balancing which occurs in the Transport Layer and Application layer of the OSI model, respectively. Briefly explaining the OSI model, the requests are compressed by 7 layers, like Matryoshka dolls. The deeper (from layer 1 to layer 7) the data is extracted, the more information is revealed. It means that the load balancer in layer 7 has more information about the incoming requests compared to the level 4 load balancer. Take a look at the data on each layer of the OSI model below: ![](/assets/blog/authors/pham.hoang/figure-4.png =600x) Figure 4. Data on each layer of the OSI Model Layer 4 and layer 7 load balancers differ in how deep they interfere with the incoming request. Layer 4 load balancing At layer 4, the load balancer knows little information about incoming requests, only the client IP address and ports. Because it is encrypted data, the load balancer can not understand anything about the content of the request data. That makes load balancing at layer 4 not smart like layer 7 load balancing. Advantages: Simple load balancing No decrypt/lookup on data => Faster, efficient and secure Disadvantages: Only a few load balancing methods (not smart load balancing) No caching, cause you can’t access data. Layer 7 load balancing At layer 7, the load balancer really can access readable data of the incoming request (for example, HTTP request headers, URL, cookie, etc. ). The layer 7 load balancer can distribute traffic much smarter than layer 4, for example, a very convenient strategy is path-based routing. Advantages: Smart load balancing Caching enabled Disadvantages: Decrypts data in middle (TLS termination) => Slower, less secure because load balancer has rights to look at data. Routing/Load balancing methods list There are some routing/load balancing methods that vary in their purposes. Round Robin algorithm: The simplest method to implement: The server address is returned in a random or rotating sequential manner. Weighted-based algorithm: Control the percentage of the requests that go to each server. For example, if you want to introduce a Canary release for a small group of users, so you will set up one small server for the Canary release for getting user feedback, and route only 5% of users to this server. The left 95% of users still go to the stable application version. Latency-based policy (usually on DNS routing): Route to the server that has the least latency close to the client. In case low latency is a priority, this policy is a suitable method. Least connections (usually on load balancer): Traffic is directed to the server having the least traffic. This algorithm helps for better performance during peak hours by preventing big requests converge on one particular server. Health Checks (heartbeats): a.k.a failover. Monitor the health of each server by establishing a live session. The load balancer will check the heartbeat of each server registered with it, and it will stop routing requests to one server if that server’s health is not good, then forward it to another healthy server. IP Hash (usually on load balancer): Assign the client’s IP address to a fixed server for optimal performance (for example, caching) Geo-location-based routing (usually on DNS routing): Based on user location by continent or country then return the appropriate server on each location. Multi-Value (Only for DNS Routing): Return the numbers of IP addresses instead of one. Path-based routing (Only for Layer 7 Load balancer): according to the path of the request, decide which server should handle the request. For example: /processing, LB will forward the request to the processing server, /image, LB will forward to the image server. Before we leave The hardware load balancer and DNS routing can be easily confused with each other. They are not substitutes for each other but are usually mixed with each other. The thing is, they use DNS routing for large scales like between data centers or large regions because it’s much cheaper and faster than a hardware load balancer. Following that are hardware load balancers, which often distribute traffic inside that data center or region. DNS routing deals with DNS query, while hardware load balancer deals with traffic. Understanding these 2 definitions are essential for scaling a global system with high performance and availability. References https://medium.com/@phamduchoang.eee/but-what-is-osi-model-29578b795f0c https://iq.opengenus.org/layer-4-layer-7-load-balancing https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy-edns0.html
こんにちは。CIO室 人事採用チームの丸山と申します。 普段は大阪拠点(Osaka Tech Lab といいます)にて、採用や採用広報を担当しています。 最近キンクマハムスターを家族に迎え入れ、日々愛ででおります🐹 2つのアドベントカレンダー🎅 KINTOテクノロジーズは2022年2つのアドベントカレンダーを掲載いたします。 技術記事 グループ紹介記事(本記事はこちら側です!) なぜグループ紹介記事?🤔 2022年12月現在、KINTOテクノロジーズは14グループ・2プロジェクトチームで構成されています。 今年1年で社員数はおよそ1.5倍と急拡大しているので、来年はもっと増えているかもしれません。(楽しみ!) それぞれのグループによって関わるプロダクトやプロジェクト、それに伴って開発体制も様々です。 2023年も多くのメンバーにテックブログを通して技術情報を発信いただく中で、各グループの紹介記事があると、前提情報が共有でき、読者の方により解像度の高い情報をお届けできるのではと思い、アドベントカレンダーで掲載することにしました。 各グループのマネージャー / リーダーが記事を執筆しております。 記事を通して、会社やグループ、メンバーについても知っていただき、KINTOテクノロジーズで働くイメージも伝えられると嬉しいです! こんな記事もあるよ👀 KINTOテクノロジーズ。実は、80%以上がエンジニア・デザイナーで構成されています💻 そんなメンバーの方々が参加する部活動や勉強会、個性的なデスク紹介など、KINTOテクノロジーズのなかみについて知っていただける記事がアップされていきます。 ぜひクリスマスまでの時間をアドベントカレンダーと一緒にお楽しみいただけますと幸いです🎄✨
自己紹介 はじめまして、KINTOテクノロジーズでモビリティマーケットの開発・運用を担当しているリナです。 普段はフロントエンジニアとして、主にNext.jsを用いて実装しています。 最近のマイブームは、ガンプラを組み立てることです! Advent Calendarとは 12月1日~25日にかけて、クリスマスまでの期間をカウントダウンするカレンダーのことです。 IT業界では、期間中に1日1記事投稿することで、日頃の取り組みや情報を発信するイベントとして毎年楽しまれています。 弊社でアドベントカレンダーを実施するのは、今年で2回目です! 昨年の記事は こちら からご覧ください。 Advent Calendar 2022の記事 今年のアドベントカレンダーは、テックブログの開設を記念して2本立てで公開します✨ 1. 技術記事 インフラ・モバイル開発・QA・デザインなど、多岐にわたる分野の技術記事を公開する予定です。 記事を通して、KINTOテクノロジーズのエンジニアやデザイナーが、日々どんな業務を遂行しているか垣間見ることができます。 https://qiita.com/advent-calendar/2022/kinto-technologies 2. グループ紹介記事 KINTOテクノロジーズのオフィスや各グループ(部署)が担う業務内容を紹介します。 また、有志の勉強会や部活動の様子も公開する予定です。 記事を通して、KINTOテクノロジーズの社員の日本国内およびグローバルにおけるKINTOの取り組みや社員の働き方を知ることができます。 https://qiita.com/advent-calendar/2022/kinto-technologies-introduction ぜひ、お楽しみに! さいごに 今年のアドベントカレンダーを通して、少しでも弊社の取り組みや社員の働き方を知っていただけると嬉しいです! そして、KINTOテクノロジーズでは、一緒に働ける仲間を募集しています。詳しくは こちら から 2022年のアドベントカレンダーにご期待ください!
はじめに こんにちは。分析グループでデータエンジニアをしている小池です。新卒入社した前職では主にサービスグロースのための分析を行っていたのですが、現職ではデータ分析基盤の開発をしています。平たくいえば、データアナリストからデータエンジニアへキャリアチェンジしたというわけです。この記事では、私がデータアナリストからデータエンジニアになるまでのお話をしていければと思います。 データアナリストやデータエンジニアとは データアナリストとデータエンジニアの責務がわからないかたもいらっしゃると思いますので、まずはそこから説明します。それぞれの職種の責務は次の図のようになっています。 データエンジニアは、データアナリストが集計・分析するためのデータを用意する役割を担います。具体的な業務内容としては次のようになります。 他システム、別データソースからのデータ取得 1で取得したデータをデータアナリストが使いやすいような形に加工 2で加工したデータにデータアナリストがアクセスできるようデリバリー 対して、データアナリストはデータを集計・分析し、ビジネスをどう改善すればよいか示唆出しをする役割を担っています。具体的な業務内容としては次のようになります。 データエンジニアが用意したデータをSQLなどを用いて集計 1で集計したデータを分析 2で分析した結果を元にビジネスをどう改善すればよいか示唆出し あるいは、次のような業務も行います。 データエンジニアが用意したデータをSQLなどを用いて集計 1で集計したデータをダッシュボードにまとめ、データを定点観測できる環境を整備 なんとなくイメージはつかめたでしょうか? これを踏まえて、この記事では私がデータアナリストからデータエンジニアへとキャリアチェンジし駆け出しデータエンジニアとして駆けてゆくさまをお見せできればと思います。同じくデータエンジニアへキャリアチェンジしようとしているかたがたの参考になれば幸いです。 KINTOテクノロジーズのデータアーキテクチャ データ基盤の開発についての話をする前に、まずは当社のデータアーキテクチャについて説明します。主にAWSのサービスを用いて構成されており、大まかなデータの流れは次のようになっています。 Glueというサービスを用いて外部ソースから取得したデータを変換・加工してS3に保存 Athenaというサービスを用いてS3のデータに対しSQL検索 当社のデータエンジニアは主に1の部分を行い、さまざまなデータをAthenaで集計・分析できるような環境づくりを行っています。 Glueのワークフロー開発 データアーキテクチャについて理解したところで、データアナリストからエンジニアへの第一歩として開発したGlueワークフローについての説明をします。Glueには主に次の3つの機能が搭載されています。 ジョブ : 分析の前処理(データ抽出、変換、ロード)を実行する機能 クローラ : データカタログへメタデータを作成する機能 トリガー : ジョブ、クローラを手動または自動で実行する機能 ジョブは分析の前処理を実行する機能のことです。たとえば、CSVデータを読み込んで加工し出力するといった一連の処理を一つのジョブとして定義できます。クローラはデータカタログへメタデータを作成する機能を持っています。テーブルの入出力形式や列名などのデータ型を定義し、それをデータカタログという箱に入れることができるというイメージです。トリガーはジョブ、クローラを手動または自動で実行する機能のことです。毎日決まった時間に実行させたり、一つ前のジョブが正常終了したときに実行させたりできます。また、これら三つを一連の処理としてまとめて管理しやすくしたものをワークフローといいます。 私は「外部ソースからのデータをAthenaで集計できるようにする」ワークフローを開発することでデータの流れを大まかに理解し、データエンジニアとしての一歩を踏み出すことができました。ところで、前職でデータアナリストをやっていたころはデータエンジニアが整形したデータを集計・分析するという環境だったため、データがどのように作られているかどうかには気を配ることはあまりできていませんでした。しかし、この開発でトリガーやジョブの組み合わせ方などデータの前処理部分の理解を深めることができたのはとても大きな経験になりました。 アナリストとエンジニアのスキルセットの比較 ここまでデータエンジニアの業務について述べてきましたが、私の考えるデータアナリストとデータエンジニアそれぞれに必要なスキルセットを整理してみます。 データアナリストのスキルセット 分析設計 集計 分析 分析結果の説明 まず、データアナリストに必要なスキルとして分析設計の能力が挙げられます。たとえば、マーケターに「このデータがほしい」と言われたとします。言われるがままにそのデータを出すこともできますが、それだと手戻りが発生してしまうこともあります。そのため、そのデータを出したい理由は何なのかを質問することで元々の目的を明確にし、どんなデータを出して分析すればその目的が達成できるかを定めるといったことが必要になります。これが分析設計です。 続いて、集計する能力です。これは、SQLなどを用いてほしいデータを抽出することを指します。SQLを書いて抽出したデータにミスがないかをチェックするための検算や、ミスが起きにくいSQLの書き方を身につけるのは意外と難しいです。 次に、分析する能力です。ベースとなるのは、主観を入れず論理的に物事を考えられる能力です。ここに、統計や機械学習などの知識が必要になる場合があります。 最後に、分析結果を説明する能力です。いくら高度な分析を行ったとしても、その分析結果がビジネスに活かせなければ価値があるとは言えません。意思決定者に適切な説明を行い、理解してもらうところまでできて初めて価値が出てきます。 データエンジニアのスキルセット データパイプラインの設計 コードの設計 データ加工 まずは、データパイプラインの設計能力です。本記事で説明したことと照らし合わせると、データ加工のワークフローをどのように構成すれば求めているデータを作れるかどうかを見定める力といえばよいでしょうか。 続いてはコードの設計能力です。これはデータエンジニアだけではなくすべてのエンジニアに共通することだと思いますが、コードは書いて終わりではなく、のちのち修正する必要が出てくる可能性があります。そのため、いかに保守運用しやすいコードを書くかということは重要です。 最後に、データ加工の能力です。主にSQLやPythonを使うため、これらを満足に扱える能力が必要になってきます。 以上がデータアナリストとデータエンジニアのスキルセットの比較です。 今後の展望 ここまで、データアナリストからデータエンジニアへキャリアチェンジしてからの半年間についてお伝えしてきました。振り返ってみると、データエンジニアとしてのスキルを少しずつつけることができていますが、今度は開発に集中しすぎてデータアナリストとしての視点を失いつつあるような気がしています。そこで、今後の展望としては「利用者が使いやすい基盤を作る」ことを意識できればと考えています。開発者にとってどんなに美しいデータ基盤を作ったとしても、データアナリストが適切にビジネスサイドへアウトプットしていかないとビジネス的な価値があるとは⾔えません。そうならないために、データアナリストとしての経験もデータエンジニアとしての経験も活かして一気通貫でデータを価値につなげられるような人材になれるよう日々邁進していきます!
By Ikki Ikazaki, MLOps/Data Engineer at Analysis Group This is the last part in a multi-part series on how KINTO Technologies Corporation(KTC) developed a system and culture of Machine Learning Operations(MLOps). Please have a look at Part1( How We Define MLOps in KTC ), Part2( Training and Prediction as Batch Pattern ), and Part3( Metadata Management or Experiment Tracking Using SageMaker Experiments ). Situation The previous post (Part1) discussed the goal and scope of MLOps and I tried to gain understanding from my colleagues. However, just talking about the concept is not enough for engineers and ML practitioners. People establish their skills once they understand both the idea and how. For software engineers, it seemed to be easy to understand the concept and techniques of the B part of Reliable System Integration while for data scientists A part of Project Management With Speed. This difference in understanding and interests makes it difficult to have better communication and thus a bridge over the gap between them was needed. Task The bridge is an opportunity to let them understand each other's interests and methodologies by making an effort together. Conducting a study session on the common ML platform, SageMaker, was expected to be such an opportunity. The goals of study session was set up as follows: To build a good relationship between software engineers and data scientists. To form a common understanding on MLOps and SageMaker. Action I didn't make a presentation but just focused on organizing the study session by planning how we proceed. The basic flow was as follows. Define a scope of contents. Assigned who takes charge of the contents. Give the material to be studied. Prepare for the session by creating slides and notebook in two weeks. Hold the study session. Back to 2) and continue until all the topics have been discussed. First of all, I outlined the study contents. SageMaker is a huge platform and we don't need to catch up on everything about it. The outlined contents are the below seven. The basics of SageMaker and SageMaker Studio SageMaker's Training Job Batch prediction and Endpoints SageMaker Processing SageMaker Experiments SageMaker Pipelines SageMaker Projects (CI/CD) Then, I proposed to colleagues at both my team (Analysis Group) and another team (Platform Group) about the study session. There were four presenters who come together — one is a data scientist and the other three are infrastructure or DevOps Engineers — and I assigned them the above contents. Because of the difference in interests of each role, I took care of who will be in charge of the contents so that all attendees understand the contents without a lot of preparation. Especially, some contents are targeted at engineers such as SageMaker Processing and Projects while some contents are for data scientists such as SageMaker's Training Job and Experiments. About the study contents, since I've read through the entire developer's guide on SageMaker before and this guide is really well-written, I let the presenter read as well by specifying a scope and executing the relevant notebooks. I believe this way of preparation saves a lot of time for presenters to summarize the information and ensures the quality of the sessions because it is already offered by AWS. To be honest, I just wanted to let them know how well the developer guide is prepared. Result All seven sessions were held bi-weekly from November to January. I hope this study session contributed to building common knowledge about SageMaker and understanding about each other's roles. Through the sessions, it was good that one of the DevOps engineers understood how to deploy SageMaker Pipelines and actually he incorporated it into the internal CI/CD program which is based on GitHub Actions. I hope we can talk about how we developed the CI/CD pipeline of SageMaker with GitHub Actions someday. The study session was a really good way to build a shared culture for both software engineering and data science. How about the four-part series of blog posts on how KINTO Technologies Corporation developed the system and culture of MLOps? Follow our Tech Blog for future posts to stay up to date.
自己紹介 KINTOテクノロジーズにてCIO室セキュリティチームのチームリーダーを担当している森野です。 趣味は子ども時代を過ごした埼玉県大宮市(現さいたま市)のサッカーチームである大宮アルディージャの応援です。 最近は機動戦士ガンダム 水星の魔女にハマっていて毎週日曜日午後5時の放映を楽しみにしています。 本記事では先日初参加した 情報セキュリティワークショップin越後湯沢2022 のセッションの中から印象に残った講演を幾つか紹介させて頂きます。 情報セキュリティワークショップin越後湯沢とは 情報セキュリティワークショップin越後湯沢は1998年から年次で開催されている非常に歴史の長い情報セキュリティワークショップです。 2022年は10月7日(金)、10月8月(土)の2日間、デイタイムセッション会場は湯沢町公民館、デイタイムセッション中継・ナイトセッション会場は湯沢グランドホテルで行われました。 越後湯沢と言えばナイトセッション 越後湯沢の名物と言えば美味しい日本酒と温泉。。ではなくナイトセッションです。 例年チケット争奪戦が激しく、私もナイトセッションのチケットが取れず参加を諦めていましたが、幸いにも直前にチケットを譲ってくれる方が現れ参加することができました! コロナ以前は講演者と参加者が車座となり議論を交わしていたそうですが、今年はコロナが収まっていないため講演者と参加者の距離を置いたセッションとなりました。 しかし、セッション中は参加者から講演者に対して活発に質疑応答が交わされていました。 帰ってきた!セキュリティのアレ in 越後湯沢 私も毎回配信を楽しみにしているポッドキャスト セキュリティのアレ を配信している方々によるナイトセッション。 SBテクノロジー株式会社 プリンシパルセキュリティリサーチャー 辻 伸弘 氏 インターネットイニシアティブ(IIJ) セキュリティ本部 セキュリティ情報統括室長 根岸 征史氏 セキュリティインコ兼協力研究インコ piyokango 氏 piyokangoさんからは突然発生するサイバー攻撃に翻弄されないように天気予報のように攻撃を予兆することをやりたいというお話がありました。 汎用的なものは難しいかもしれませんが、例えばフィッシング犯罪はフィッシングサイトが実際に立ち上がる前にフィッシングサイトに使用するドメイン取得や証明書取得が行われます。 その活動を捕捉できればフィッシング犯罪の天気予報のようなことが行えるのではとお話を伺いながら思いました。 根岸さんからはCVSS(Common Vulnerability Scoring System)のスコアの高低だけで脆弱性対応の緊急度を判断するのではなく、実際にサイバー攻撃に使用されているのか否かを考慮するべきという問題提起がありました。 CVSSは名前の示す通り情報システムの脆弱性の深刻さを数値化する仕組みです。 参考:IPA 共通脆弱性評価システムCVSS概説 日々、脆弱性情報を収集し自社システムへの影響を判断する者としては算出されたスコアから脆弱性対応の緊急度を計ることができるため大変便利です。 しかし、スコアが低いものでもサイバー攻撃に使用されることがあるため注意が必要とのことでした。 アメリカのCISA(CyberSecurity&Infrastructure Security Agency)がサイバー攻撃に使用された脆弱性を 公開 し随時更新しているので、このような情報を脆弱性対応の判断基準に加えることで、より安心・安全なシステムを提供できそうです。 辻さんは。。途中、他のセッションに参加したため聞き逃してしまいました。。辻さん、ごめんなさい。 フィッシングハンターもたまには温泉で休まナイト 日々フィッシングサイトと格闘している方々によるナイトセッション。 自称イケメンフィッシング詐欺ハンター にゃん☆たく 氏 ozuma5119 氏 KesagataMe 氏 サイバー侍KAZUMI 氏 講演者の皆さんがフィッシングに引っかかる人が一人でも減るようにSNS等で拡散して欲しいと依頼されていたスライドをこのブログにも添付させて頂きました。 SMSやメールのリンクがフィッシングなのか否か判断することは非常に困難であるため、SMSやメールのリンクはクリックせず、ブラウザのブックマークや検索エンジンの検索結果から目的のサイトに移動しましょう。 若年層のネット活用の現状と、我々ができること 株式会社ラック サイバー・グリッド・ジャパン ICT利用環境啓発支援室 七條 麻衣子 氏 私には中学生の子どもがいるためとても興味深く講演を拝聴しました。 子ども達が専用のスマートフォンを持つ時期ですが9歳の時点で3割に達し13歳の時点では9割に達するそうです。私の想像より遥かに割合が高く驚きました。 若年層のネット活用の特徴について私の知らなかった点は以下の通りですが、共有に関して、スマートフォンアプリを使用してお互いの位置情報を共有するだけではなく、スマートフォンの電池残量まで共有していることには非常に驚きました。 チャット・メッセージでの長文はNG 長文は画像で(メモ帳をスクショ) アカウントの使い分け 高校生の約半数がSNSでは実名登録(仮名だと友だちに見つけて貰えないため) 実況&動画で情報と時間の共有 お話を伺って理解できない使い方や危なっかしい使い方だと感じる点が多々ありました。しかし、理解できないと子どもに伝えるのは禁句で、それを伝えた瞬間に子どもは心を閉ざしてしまうそうです。理解はできなくてもありのままの現実を受け入れなさいとのことでした。 講演後に子どものSNSの使用について相談させて頂いたところ、危ないからといって禁止しても親に隠れて使用するだけで却って危険なため、親の監視の下、安全な使い方を教えながら使用させた方が良いとのアドバイスを頂きました。 脆弱性対応と情報共有~社内バグバウンティ制度の取り組みを通じて見えた事~ エヌ・ティ・ティ・コミュニケーションズ株式会社 林 郁也 氏 / 塚越 さくら 氏 バグバウンティ制度とはソフトウエアの脆弱性を発見した方に対して報奨金を支払う制度のことです。 社外の方々に対してバグバウンティ制度を提供する場合、脆弱性を報告してくれた方が信頼できる方なのか否か判断することは非常に難しい問題です。 そこでエヌ・ティ・ティ・コミュニケーションズ株式会社では従業員を対象にバグバウンティ制度を提供することにしたそうです。従業員なら身元が確かなためです。 結果、ユーザの権限昇格が可能な深刻度の高い脆弱性が見つかるなど実際にシステムのセキュリティ強化に役立ったそうです。 副次的な成果として、自発的にグループが結成され勉強会が行われたり、エンジニア職以外から報奨金を得る方が現れるなど、従業員の新たな才能を発見する機会にもなったそうです。 当社でも社内バグバウンティ制度を取り入れてみたいなと感じました。 おわりに 日常業務から離れ様々な略歴を持った方々の講演を拝聴したり、ワークショップで出会った方々とお話させて頂いたことはとても刺激になりました。 記事の中で言及させて頂いた脆弱性対応の緊急度の判断方法はすぐにでも当社の業務に反映していきたいと考えています。社内バグバウンティ制度についてもすぐには難しいかもしれませんが当社にも導入できたら良いなと考えています。 越後湯沢以外にも温泉兄弟と呼ばれる兄弟ワークショップが各地で開催されています。皆さんも参加を検討してみては如何でしょうか。 サイバー防衛シンポジウム熱海 サイバー犯罪に関する白浜シンポジウム サイバーセキュリティシンポジウム道後 九州サイバーセキュリティシンポジウム
こんにちは。分析グループ(分析G)でMLOps/データエンジニアしてます伊ヶ崎( @_ikki02 )です。 こちらは「KINTOテクノロジーズ株式会社にてどのようにMLOpsを適用していくのか」というテーマでの連載最終回です。1本目の記事「 KINTOテクノロジーズのMLOpsを定義してみた 」、2本目の記事「 SageMakerを使った学習&推論のバッチパターン 」および3本目の記事「 SageMaker Experimentsを用いた実験管理 」はそれぞれのリンクよりご確認ください。 背景(Situation) 1本目の記事では、MLOpsの定義とスコープについて紹介しましたが、一緒に働くメンバーと理解をすり合わせる活動にも取り組んできました。 エンジニアやデータサイエンティストといった異なる職掌がいる中で共通理解を得られるように布教するのは実際難しかったです。勉強会開始時点では、1本目の記事で紹介した図で言うと、ソフトウェアエンジニアは「(B) 信頼性を高めるシステム連携」の項目(推論基盤やIaC、CI/CDなど)が得意な一方、データサイエンティストは「(A) PJ管理・高速化」の項目(学習基盤、メタデータ管理(実験管理)など)に対する前知識があったように思います。このような背景や興味関心の違いは、ワードチョイスに微妙な違いがあったり、議論が右往左往してしまうことに繋がったりするように感じました。概念や用語の共通認識とそれを実装する方法を共有し、お互いの認識の差異を吸収する機会が必要だったように思います。 業務(Task) その機会として勉強会を企画しました。共通の機械学習基盤たるSageMakerについてお互いが学び合う機会となることを期待したのでした。 ゴールとしては以下のように設定しました。 MLOpsを進めるにあたって関係者の関係構築 MLOpsおよびSageMakerに対する共通理解の形成 やったこと(Action) 私個人としては企画とファシリテーションに集中したかったのと、コンテンツの習熟をメンバーに促す趣旨から、コンテンツの準備に焦点を当てました。具体的な勉強会開催の流れは以下の通りです。 勉強会のスコープ策定 各勉強会の担当者割振。担当分のコンテンツ共有 勉強会用スライドおよびノートブックの作成準備(隔週開催) 勉強会開催 2に戻る まず「勉強会のスコープ策定」を実施しました。SageMaker全体をスコープにすると膨大な量になるため、以下の7つの項目に絞りました。 SageMaker全体像およびStudioの概要 訓練ジョブの作成 推論の実行(バッチ推論と推論エンドポイント) SageMaker Processing (ETL特化のジョブ) SageMaker Experiments (実験管理) SageMaker Pipelines (パイプライン) SageMaker Projects (CI/CD) 上記スコープを分析グループおよびプラットフォームグループのメンバーに提案し、4名のプレゼンター(データサイエンティスト1名、インフラ&DevOpsエンジニア3名)が集まりました。バックグラウンドの異なるメンバーが集まった中、なるべく準備に負担をかけずに一定の品質を担保したかったので、それぞれの得意領域を意識して、各勉強会の担当者を割振るようにしました。具体的には、「訓練ジョブ」や「SageMaker Experiments」はデータサイエンスの業務プロセスの理解が必要だったためデータサイエンティストへ割当て、「SageMaker Processing」や「SageMaker Projects」はコンテナ周りやCI/CDの知識が背景に求められるためエンジニアにお願いしました。 また、勉強会のコンテンツとしては、AWS公式のドキュメントである「 developer guide 」とそこに掲載されている「 SageMaker関連のサンプルノートブック 」を土台として作成を依頼しました。公式のドキュメントは画面のスクリーンショットやサンプルコードの掲載など、本当によくできているので( 日本語の機械翻訳が面白いことがあるのはご愛嬌 )、イチから新たに作り直すというよりは、そこにある内容を各個人の理解に合わせて切り貼りしてまとめてもらうのが良いと考えています(個人的にはdeveloper guideの良さを布教しつつ、一次ソースの引用癖を付つけていくのも狙いでした)。 結果(Result) 上記の内容で、2021年11月〜2022年1月までの期間で隔週開催しました。嬉しかったのは、勉強会後、参加メンバーがSageMaker Pipelinesのデプロイ方法を習熟し、社内で開発運用しているGitHubActionsのCI/CDのSageMaker版を構築したことでした(この連載でも触れたバッチパターンのCI/CD基盤としても活用しており、SageMaker Projectsとの差別化のお話などもいつかこちらのテックブログでご紹介できればいいなと思います)。 個人の想いとしては、ソフトウェアエンジニアリングとデータサイエンスという様々な知識や役割を超えて共通認識を構築していく勉強会は改めて大切な取組みだなと感じており、この勉強会が目的通り共通認識の形成と関係構築に少しでも貢献できていたらよいなと思います。 いかがでしたでしょうか? 本掲載にて「KINTOテクノロジーズ株式会社にてどのようにMLOpsを適用していくのか」というテーマでの連載は一旦最終回を迎えますが、プロジェクト的にも組織的にもまだまだ変化の多いフェーズのため、MLOpsも進化を続けなければなりません。プロダクト開発に機械学習を組込む取組み、そして価値提供を改善し続けていく取組みはまだまだ始まったばかりなので、引続きアップデートをお伝えしていければと思います(本テックブログのTwitterもありますのでフォローしてくれると嬉しいです)。
こんにちは。分析グループ(分析G)でMLOps/データエンジニアしてます伊ヶ崎( @_ikki02 )です。 こちらは「KINTOテクノロジーズ株式会社にてどのようにMLOpsを適用していくのか」というテーマでの連載最終回です。1本目の記事「 KINTOテクノロジーズのMLOpsを定義してみた 」、2本目の記事「 SageMakerを使った学習&推論のバッチパターン 」および3本目の記事「 SageMaker Experimentsを用いた実験管理 」はそれぞれのリンクよりご確認ください。 背景(Situation) 1本目の記事では、MLOpsの定義とスコープについて紹介しましたが、一緒に働くメンバーと理解をすり合わせる活動にも取り組んできました。 エンジニアやデータサイエンティストといった異なる職掌がいる中で共通理解を得られるように布教するのは実際難しかったです。勉強会開始時点では、1本目の記事で紹介した図で言うと、ソフトウェアエンジニアは「(B) 信頼性を高めるシステム連携」の項目(推論基盤やIaC、CI/CDなど)が得意な一方、データサイエンティストは「(A) PJ管理・高速化」の項目(学習基盤、メタデータ管理(実験管理)など)に対する前知識があったように思います。このような背景や興味関心の違いは、ワードチョイスに微妙な違いがあったり、議論が右往左往してしまうことに繋がったりするように感じました。概念や用語の共通認識とそれを実装する方法を共有し、お互いの認識の差異を吸収する機会が必要だったように思います。 業務(Task) その機会として勉強会を企画しました。共通の機械学習基盤たるSageMakerについてお互いが学び合う機会となることを期待したのでした。 ゴールとしては以下のように設定しました。 MLOpsを進めるにあたって関係者の関係構築 MLOpsおよびSageMakerに対する共通理解の形成 やったこと(Action) 私個人としては企画とファシリテーションに集中したかったのと、コンテンツの習熟をメンバーに促す趣旨から、コンテンツの準備に焦点を当てました。具体的な勉強会開催の流れは以下の通りです。 勉強会のスコープ策定 各勉強会の担当者割振。担当分のコンテンツ共有 勉強会用スライドおよびノートブックの作成準備(隔週開催) 勉強会開催 2に戻る まず「勉強会のスコープ策定」を実施しました。SageMaker全体をスコープにすると膨大な量になるため、以下の7つの項目に絞りました。 SageMaker全体像およびStudioの概要 訓練ジョブの作成 推論の実行(バッチ推論と推論エンドポイント) SageMaker Processing (ETL特化のジョブ) SageMaker Experiments (実験管理) SageMaker Pipelines (パイプライン) SageMaker Projects (CI/CD) 上記スコープを分析グループおよびプラットフォームグループのメンバーに提案し、4名のプレゼンター(データサイエンティスト1名、インフラ&DevOpsエンジニア3名)が集まりました。バックグラウンドの異なるメンバーが集まった中、なるべく準備に負担をかけずに一定の品質を担保したかったので、それぞれの得意領域を意識して、各勉強会の担当者を割振るようにしました。具体的には、「訓練ジョブ」や「SageMaker Experiments」はデータサイエンスの業務プロセスの理解が必要だったためデータサイエンティストへ割当て、「SageMaker Processing」や「SageMaker Projects」はコンテナ周りやCI/CDの知識が背景に求められるためエンジニアにお願いしました。 また、勉強会のコンテンツとしては、AWS公式のドキュメントである「 developer guide 」とそこに掲載されている「 SageMaker関連のサンプルノートブック 」を土台として作成を依頼しました。公式のドキュメントは画面のスクリーンショットやサンプルコードの掲載など、本当によくできているので( 日本語の機械翻訳が面白いことがあるのはご愛嬌 )、イチから新たに作り直すというよりは、そこにある内容を各個人の理解に合わせて切り貼りしてまとめてもらうのが良いと考えています(個人的にはdeveloper guideの良さを布教しつつ、一次ソースの引用癖を付つけていくのも狙いでした)。 結果(Result) 上記の内容で、2021年11月〜2022年1月までの期間で隔週開催しました。嬉しかったのは、勉強会後、参加メンバーがSageMaker Pipelinesのデプロイ方法を習熟し、社内で開発運用しているGitHubActionsのCI/CDのSageMaker版を構築したことでした(この連載でも触れたバッチパターンのCI/CD基盤としても活用しており、SageMaker Projectsとの差別化のお話などもいつかこちらのテックブログでご紹介できればいいなと思います)。 個人の想いとしては、ソフトウェアエンジニアリングとデータサイエンスという様々な知識や役割を超えて共通認識を構築していく勉強会は改めて大切な取組みだなと感じており、この勉強会が目的通り共通認識の形成と関係構築に少しでも貢献できていたらよいなと思います。 いかがでしたでしょうか? 本掲載にて「KINTOテクノロジーズ株式会社にてどのようにMLOpsを適用していくのか」というテーマでの連載は一旦最終回を迎えますが、プロジェクト的にも組織的にもまだまだ変化の多いフェーズのため、MLOpsも進化を続けなければなりません。プロダクト開発に機械学習を組込む取組み、そして価値提供を改善し続けていく取組みはまだまだ始まったばかりなので、引続きアップデートをお伝えしていければと思います(本テックブログのTwitterもありますのでフォローしてくれると嬉しいです)。
こんにちは。Woven Payment Solution開発グループの小野です。 私達のチームは Toyota Woven City で使われる予定の決済プラットフォームの開発を行っています。少し古い内容ですが、私達のやっていることについてはこちらをご覧ください。 20220422 Woven City Tech Meetup Tech Talk by Rie Ono 今回は私達の決済システムを設計する際に利用したDDDのモデリング手法の一つ EventStorming を使っています。まだ研究途中なのですが、現時点で分かったことをご紹介しようと思います。 EventStorming とは Alberto Brandolini さんが提唱したシステムをモデリングするためのワークショップ形式の手法です。 EventStorming のサイトを参照すると、以下のように書かれています。 EventStorming is a flexible workshop format for collaborative exploration of complex business domains. (意訳)Eventstormingとは複雑なビジネスドメインを協業的に探求するための柔軟なワークショップフォーマットです。 また、 Learning Domain-Driven Design のChapter 12.EventStorming には以下のように書かれています。 EventStorming is a low-tech activity for a group of people to brainstorm and rapidly model a business process. In a sense, EventStorming is a tactical tool for sharing business domain knowledge. (意訳)EventStormingはメンバーからアイデアを引き出し素早くビジネスプロセスのモデルを形作るためのローテクなアクティビティです。もう一方ではEventStorming はビジネスドメインの知識を共有する戦術的なツールです。 つまり、以下のような目的のためのワークショップです。 難しくないやり方でドメイン知識を有識者から引き出す ステークホルダーへドメイン知識を共有する ドメインモデルを設計する EventStormingのための準備 誰に参加してもらうのか? 上記の Learning Domain-Driven Design には参加者の人数は10人以下が望ましいと書かれています。人数が多すぎると発言に躊躇したり、意見をまとめにくかったりするかもしれません。 また異なったバックグラウンドの人を集めることでいろいろな発見があるかもしれない、と書かれています。それらを踏まえると、参加する人を選ぶのが最初の難しい課題になるかもしれません。 ファシリテーター フェーズごとに時間を区切ったり、途中で話が広がりすぎたりしないように調整するファシリテーターがいると良いです。私達の場合は、設計を行うエンジニア自身が担当しました。 エンジニア アプリケーションを設計・開発するエンジニア。 私達の場合は当チームのメンバーに加え、ネイティブアプリを開発するアプリチームのメンバーにも、ドメイン知識を共有する目的で参加していただきました。 ドメインエキスパート ドメインエキスパートは対象のドメインについて深い知識を持つ人です。既存のシステムや他社のビジネス、その分野に詳しい人を集めましょう。EventStormingの目的としてはソフトウェアの設計のための他に、ドメインエキスパートの人たちから知識を吸い出すことにもあります。 私達の場合、幸いなことにビジネスチームには決済業務に携わってきたメンバーが多く在籍しており、協力していただけることになりました。 また、私達のチームをリードしている亀井は過去に決済分野に携わっており、決済とエンジニアリングの両方の視点から指摘ができる方です。 UI/UXデザイナー、QAエンジニア 今回は実現できなかったのですが、できればアプリケーションの開発に関わるUI/UXデザイナーとQAエンジニアも含まれていると良いと思います。業務知識を共有してUI/UXやQAの設計の効率化が図れます。 準備するもの EventStormingは時間がかかります。事前の準備をすることでスムーズに進行できるようにしましょう。 参加者のスケジュール確保 参加者の時間をできれば1日か半日は抑えたいところです。いろいろなチームから人を呼ぶので、全員が参加できるスケジュールを押さえるのが困難とおもいますが、重要です。 場所 やはりオフラインだと発言がしやすい気がします。 いろいろな色の付箋 図のような色の付箋を準備します。 ホワイトボード・マーカー 付箋を貼っていく大きいホワイトボードとマーカーを準備しましょう。 リラックスのためのお菓子や飲み物 を準備…したかったのですが、感染症対策のため断念しました。 前提の知識 EventStormingを開始する前や、事前のテキストコミュニケーションとして、今回作ろうとしているシステムの目的、前提、すでに決まっている事項など、を共有し、ある程度の前提知識を持ってもらいました。 また、初対面同士の参加者が発言しやすいように、それぞれの簡単な自己紹介時間を用意しました。 今回は英語でEventStormingを行ったので、ファシリテーションのやり方やドメイン知識についての英単語を事前に調べておきました。 感染症予防のため対面時間を短縮する方法を考えてみた Alberto Brandoliniさんは Remote EventStorming で、リモートで行うのは難しいという旨を書かれています。ですがこのご時世なので、オンラインでもできないか試してみました。 オフラインで実施する場合は、感染症対策のために、密にならない程度に広く、それでいて集中できる会議室や広場を準備しましょう。 オンラインで実施する場合は Miro が便利でした。 使いやすいテンプレートがあります。 Judith Birmoser's Event Storming template | Miroverse 対面時間を短くするために、少人数メンバーで後述のPhase2までたたき台をつくっておきました。実施時には全参加者にレビューしてもらい、足りない箇所を追加してもらったり、間違っている箇所を指摘してもらいます。 やってみた ここからはEventStormingをどのように進めたかを書いていきます。 Phase1 : Big picture まずはビジネスプロセス全体を明らかにするため、Big Pictureをつくっていきます。 ブレインストーミングしながらドメインイベントをオレンジ色の付箋に書き出していきます。例:「決済が行われた」 各ドメインイベントについて意見を出した人に説明してもらい、重複したものを取り除いたり、正しい理解かをドメインエキスパートに確認したりして、リファインメントし、時系列に並べなおしていきます。 Phase2: Process Modeling 次に、Event間のプロセスをモデリングしてきます。 洗い出したEventに以下の付箋を追加していきます。 Actorを黄色で追加します。 誰が、または何がコマンドを実行するのかを考えます。 Eventの原因となるコマンドを青色で追記します。 View modelができるならばを緑色に書き出します。 Policyを紫色で書き出します。このPolicyの考えが私としては難しいと感じています。コマンドの前提や条件を書き出すみたいです。 なにか疑問やリスクになりうる事項があれば、赤色の付箋に書き出しておきます。 ドメインエキスパートには、イベントの内容や時系列が正しいかチェックしていただいたり、質問に答えていただきます。 Phase3: Software Design 次に、まとめられそうなコンテキストについて詳細に考えて行き、コーディングが始められる状態にしていきます。 ビジネスドメインとしてデータの整合性が保てる範囲としてまとめられそうな箇所をAggrigate(山吹色)としてまとめてみます。 外部システムを介す場合はピンク色で追加します。 サブドメインとしてひとまとまりにできそうな箇所を区切ってみます。 この時点でUIが定義できそうならば、ペーパープロトタイプを作ってみるのも良いと思います。 だいたい出来上がって来たら、赤色の付箋について詳細にディスカッションしてみるか、すぐに結論が出せないならば、そこを別の機会に深堀りEventStormingします。 その後 ここまできたら、抜け漏れがないか、逆順にたどっていきます。 Software design as a cooperative game with EventStorming また、私達の場合は全体のドメインを洗い出したあと、スコープを絞って更にEventStormingを行ったりしました。 やってみた感想 以下は、EventStormingをやってみてよかった点です。 業務を知っているであろう人に、個々にヒアリングに行って要求や仕様を作成するよりも網羅的、偏らない、事業把握ができる。かえって時間がかからないかもしれません。 いっぺんで数人のメンバーへ知識の共有・確認ができるのも良い点だと思いました。 一度やってみて、ゼロから何かを作るときにやると効果が大きいだろうな、と思ったのですが、考えているものの答え合わせという効果もあると感じました。 副産物として、 モデリングをするうちに、忘れていた・見えなかった課題が見つかった その業務内容を初めて知るメンバーによる初心者目線での疑問が課題提起となる場合があった 普段、あまり顔を合わせることのないメンバー間でのつながりを作ることができた 以下は難しかった点です。 時間がかかるので、メンバーのスケジュールを抑えること、加えて、集中力を持続させるのが難しいと感じました。 ファシリテーションが難しい。これは慣れの問題であるので、回数を重ねていけば解決するかもしれません。 また、自分としては英語でファシリテーションをしたりディスカッションをするのも大変で、練習していきたいと思っています。特にドメインエキスパートの方々は日本の商習慣に特化した決済についての説明を英語で行うのは、かなり大変だったと思います。 これからの課題 これからもEventStormingができる機会があれば、回数を重ねてエンジニアメンバーがEventStormingをファシリテートできるようになれば良いと思っています。 また、このEventStormingで洗い出せたドメインを実際のコードに落としていくステップをもう少し研究したいです。 例: ドメイン記述ミニ言語 に落としてみる イベントソーシング への応用 以上、EventStormingをやってみた感想でした!
By Ikki Ikazaki, MLOps/Data Engineer at Analysis Group This is the third part in a multi-part series on how KINTO Technologies Corporation(KTC) developed a system and culture of Machine Learning Operations(MLOps). Please take a look at Part1( How We Define MLOps in KTC ) and Part2( Training and Prediction as Batch Pattern ). The fourth and final post will discuss "Benkyo-kai", a series of internal study sessions, to form the common knowledge about SageMaker and MLOps with other departments. Situation As we have already gone through the reason why metadata management is needed in Part1, this chapter will focus on the situation in KTC. Since it has been only four years since the establishment of KINTO Corporation, it was urgent to build relationships between the business and data science teams by presenting a clear output quickly. Sometimes this leads to sacrificing the code quality or documentation, which causes the data science process to be essentially a black box. This approach is not bad at the initial phases of a project, but now the situation has changed and the number of data science projects and members are increasing. We started to look for a better way of management. Task The key concepts of metadata management are "sharable format" and "easy tracking". Since there are a few data scientists in our team, we need to have a common format so that the team can manage their work in a standardized way. The aim of having a common format is that every data scientist can reproduce the model building process and its results. This means they need to track the development environment, the data they use, code scripts, ML algorithm, hyperparameters, etc. There is a trade-off between a common format and easy tracking because the more you leave the records for others to easily understand, the more effort is needed. It is ideal if the information that shows up repeatedly such as the container image name, execution time, data storage path, and more is recorded automatically. With SageMaker Experiments, once you write down the definition of SageMaker Pipelines, the information about the development environment is automatically integrated and so the data scientists can focus on the metrics they really want to track. The way of tracking is possible by a few lines of code using SageMaker SDK, so the effort for implementing the tracking is minimum. Action Naming Convention It is a good start to introduce the managed service for metadata management, but just using it is not enough. SageMaker Experiments is actually composed by small fragments called Experiment and Trial where Experiment is a group of Trials which usually represents a specific use case while Trial stands for each iteration of ML processings. Then, a proper naming convention is required to manage those components so that data scientists can refer to each other's projects or iterations. The below table of naming convention about SageMaker Experiments is used in our team. We consider that metadata management is required mainly on occasions: Experiment of pipeline and Experiment of EDA(Exploratory Data Analysis). Experiment of pipeline is used to track the information about every step of pipeline used in production, so it offers the possibility to reproduce when the pipeline fails somehow. By following the naming convention above, you can find the environmental information at 1.1's Trial — SageMaker Pipelines automatically creates this trial —, and analytical information at 1.2's Trial — you need to create this trial on your own in the pipeline. Also, it is often the case that data scientists want to track their experimental code and model outcomes outside of the production pipeline. Then Experiment of EDA allows them to track the information flexibly. The naming convention of this type is also flexible compared to the Experiment of pipeline, but it may be updated in the future once we find the pattern in experiments. Result Utilizing the managed service is good because there is the benefit of "Standing on the shoulders of giants". SageMaker Experiments provides us with the way of metadata management and analysis on it. By looking up 1.2's trial of Experiments of pipeline, you can inspect the metrics of the model building pipeline. You can even create pandas DataFrame of the Experiments and analyze the time series of its trials. For example, if you track the precision rate at every pipeline execution, you can make a line chart to see the historical change in the metrics. It is useful to detect what is called "model drift" in advance. The sooner you detect some type of anomalies, the faster the ML continuous training process begins. What do you think about this article? Next time, the last post of this four-part series will introduce "Benkyo-kai" and how we share technical knowledge in our company( now available ). Please follow the KTC Tech Blog for future posts to stay up to date.
Introduction As someone who grew up living between two cultures -Spain and Japan-, I have always been passionate about cross-cultural communication. My name is Maya Sakakibara and as the lead of language localization at KINTO Technologies, the topic I would like to introduce to you in two parts is precisely that: localization. The objective of these two articles is to share with you the importance of it through my studies and current experience, hopefully making you a little bit more interested on this topic in the process. In this first part, I will go through key concepts and how we tackle language localization in our company, and on the second part, I will delve deeper into what we have been up to so far at KINTO Technologies. What are translation, localization, and internationalization? You will find many definitions of translation , but one of many that resonates with me is the following from Hatim and Mason (1997) who considers translation as "an act of communication which attempts to relay, across cultural and linguistic boundaries, another act of communication." Localization (l10n) on the other hand, is adapting the way messages, stories, and ideas feel natural to the intended audience's local language. But to be able to do so in the context of software development, we first need to prepare the code or make all the product and development decisions needed to accept variations so that terms can be easily adapted and localized later to any language. This process is what we call internationalization (i18n). My task is to take care of the wording aspect, but it is worth noting that localization in the broader sense of the term also encompasses the design aspect. Due to this, what we do internally is to work closely with UI/UX writers, designers, and engineers to bring the best experience possible to our target audiences. ![](/assets/blog/authors/Maya.s/20221027/Esquema1.png =900x) If you want a fun example of word-unrelated localization you can check how certain smartphone apps will shift their date format, layouts and icons when you change your default language from English to Arabic. Localization in KINTO Here at KINTO, we are trying daily to apply kaizen (improvement) principles and think of better ways to maintain a collaborative environment. It is important for us to integrate the translations into the overall CI/CD (continuous integration and continuous delivery) process. In slightly more detail, I would like to explain a bit about how language localization is done for our products by first applying i18n. Take the below English screen of our app : ![](/assets/blog/authors/Maya.s/20221027/PPT&C_en.png =300x) The premise is to have a base language implemented and deployed; in our case it's English. Up next is to determine how to manage the data. The data type of software translations, such as the ones for an app or webpage is often stored as a key-value pair. For the sentences used in this screen (the logo and the copy on top are excluded from our localization scope), the data of the English terms will look as below in our English "localizable.strings" file for iOS: <string name="agreement_description">By using our app, you acknowledge our Terms and Conditions and Privacy Policy.</string> <string name="agreement_accept_all">Accept all</string> To localize we will create separate files for each display language, away from the code. As of October 2022, we have Japanese, Thai, and Arabic files for the app, and those files will all contain the same translation keys[^1], but with the terms in the corresponding languages. For instance, our Arabic "localizable.strings" file has its homologous data stored as follows: [^1]: Bodrov-Krukowski, Ilya (2020), Translation keys: naming conventions and organizing. < Translation keys: naming conventions and organizing - Lokalise Blog > <string name="agreement_description">باستخدام تطبيقنا، فإنك توافق على الشروط‏ والأحكام و سياسة الخصوصية الخاصة بنا.</string> <string name="agreement_accept_all">قبول الكل</string> As you can see, the keys are the same if you compare them both. By specifying keys as the first parameter, this method allows the app to pull the corresponding value from the localization file and display the localized value according to the language that the user specified. For our example, when switching the language setting from English to Arabic, our previous screen will be shown as such: That is in essence the mechanism of how we proceed with language localization, regardless of file type and platform. If you would like to keep reading about what the localization team has been up to, please check out my next article! See you in the next one! References and further recommended readings Hatim, B., & Mason, I. (1997), The Translator as Communicator. London, Routledge Khokhar, Sahil (2021), Connecting the dots '96 Web Accessibility through Internationalization and Localization < Connecting the dots '96 Web Accessibility through Internationalization and Localization > Lokalise Academy (2022), Crash course in localization < Crash course in localization >
はじめに グローバル開発グループの森です。普段は Global KINTO Web のPdM 兼 グローバル開発Gでの個人データ関連法の窓口を担当しています。 KINTOは日本国内のみではなく、関連会社やパートナーによって、世界中30か国以上にサブスクリプションやレンタカーなど様々なサービスが展開されています。 Global KINTO Web ではその一覧をご確認いただけますので、ぜひご確認ください🔎今回の記事はサービスをグローバルに展開する上で避けては通れない各国の個人データ関連法に対応したお話です。 ※グローバル開発グループはKINTOテクノロジーズの所属ですが、開発した製品は親会社である トヨタファイナンシャルサービス株式会社 のアセットとなるため、本法令対応はトヨタファイナンシャルサービスとして対応しています。 背景 KINTOは「Ever Better Mobility For All」をブランドプロミスとして、世界中の方々にシームレスな移動体験を提供すべく、日々製品・サービスの開発を行っております。世界中のKINTOサービスをシームレスにご利用いただけるよう、各サービスのIDを連携させる仕組み 「Global KINTO ID Platform (GKIDP)」 を提供しています。詳細について本記事では割愛しますが、このGKIDPを利用することで、A国のKINTOユーザーがB国のKINTOサービスを同じIDで利用できるようになります。つまりあらゆる国の間でKINTOユーザーの氏名やメールアドレス等、個人データの移転が発生します。 尚、「個人データ」とは、国によって定義が異なり、例えばGDPR上の「個人データ」は以下のように定義されます。 個人情報保護委員会は「識別された自然人又は識別可能な自然人(「データ主体」)に関する情報」と訳しています。 氏名のように単体で個人を識別できるものだけでなく、組み合わせることで、個人を識別できるデータも対象になります。 引用: 【用語解説】GDPRとは?個人データを守るための重要ポイント|CX Clip by KARTE また、欧州経済領域 (EEA、以下、欧州)のGDPR (General Data Protection Regulation)や、米国ではカリフォルニア州のCCPA (California Consumer Privacy Act)等、各国で強力な個人データ関連法が制定されており、日本国内でも2022年4月に改正個人データ関連法が全面施行されるなど、個人データ保護を強化する動きは世界中で加速しております。欧州を中心に規制当局によって名だたる企業が法令違反の指摘を受け、高額な制裁金を科されています。 参考: 高まるプライバシー保護の重要性--GDPR違反による高額な制裁金を振り返る こういった世界中の動きの中、各国KINTOサービスへGKIDPを提供する上で各国の個人データ関連法への対応をすることとなりました。 GDPR準拠とグローバル展開時の課題 1. Data Transfer Agreement Data Transfer Agreement (DTA) とは、個人データを別の管轄区域や組織に送受信する際の条件を定めたAgreementで、サインした事業体間の個人データ処理およびグローバルなデータ転送をカバーすることを目的としております。今回、我々はグローバルに個人データを送受信することを想定し、”Global Data Transfer Agreement (GDTA)"のフレームワークを整備しました。 GDTAの構成 内容 Agreementのスコープ Projectの説明とGDTAの範囲を記載 各事業体の役割と責任 役割の定義と責任の範囲を記載 附従契約条項 他のKINTOサービス提供者がGDTAに参画することを認める条項 別紙 想定される役割と処理のシナリオをカバーする条項を含む GKIDPに参画する各社はこれにサインせねばならず、新しい事業体がGKIDPに参画する場合に以下のステップが必須となります。 ✅ 各事業体の役割を特定し、GDTAにサイン ✅ ユースケースを考慮した個人データのグローバル移転に関するリスクレベルの評価 ✅ 適切なデータ転送メカニズムの適用 2. 役割の定義 個人データを処理する上でGDPR上では以下の定義がされており、各事業体はそれぞれの役割を定義した上で適切な契約が必要です。 役割 定義 管理者 (Controller) 単独または共同で個人データ処理の目的と手段を決定する 管理者はデータ処理の適法性の責任を負いGDPR違反に対する責任を負う 処理者 (Processor) 管理者を代理して、個人データの処理を行う GKIDPの場合は以下のような整理から、GKIDPに関わる全ての事業体を 「共同管理者 (Joint Controller)」 と位置付けます。 各KINTOサービスを展開する事業体(各国KINTOサービス提供者) GKIDPを開発し、ユーザーデータを管理する事業体 (トヨタファイナンシャルサービス) 3. ユースケースとデータ移転 個人データを移転するにはその国が十分な規制を持っているかなどの評価が必要です。例えばGDPRのケースでは、 欧州から見て十分な法令を所持していると認定(十分性認定)された国 はその認定をデータ移転の根拠とすることができます。一方で、認定を有していない国に関しては別途Standard Contractual Clausesを締結するなどの処置が必要です。 EU域内から域外へ個人データを移転するには、 十分な個人データ保護の保障 (欧州委員会が、データ移転先の国が十分なレベルの個人データ保護を保障していることを決定) BCR(Binding Corporate Rules:拘束的企業準則)の締結 (企業グループで1つの規定を策定し、データ移転元の管轄監督機関が承認) SCC(Standard Contractual Clauses:標準契約条項)の締結 (データ移転元とデータ移転先との間で、欧州委員会が認めたひな形条項による契約の締結) 明確な本人同意 等、一定の条件を満たさなくてはなりません。 引用: GDPR |個人情報保護委員会 その上で、今回我々は各ユースケースごとに以下の整理としました。 ユースケース 移転根拠 欧州域内の事業体間 欧州域外にデータ移転が無いため、GDTAに参画するのみ 欧州→十分性認定の ある 国 十分性認定を根拠として、欧州域外へのデータ移転が可能 ※ 欧州の十分性認定がある国一覧: GDPR |個人情報保護委員会 欧州→十分性認定の ない 国 GDPRに基づいて、GDTAに付随する形でStandard Contractual Clauses(SCC) ^1 とTransfer Impact Assessment (TIA) ^2 にサインをした上でデータ移転が可能 4. 欧州GDPRに基づくSCCとTIA 欧州から「十分な法令を有していない=十分性認定が無い」と判断される国は、欧州のデータを自国に移転させるためにStandard Contractual Clauses (SCC)を締結した上で、さらにそのデータ移転をTransfer Impact Assessment(TIA)にて評価する必要があります。GKIDPに参画いただく事業体にも、この必要性を説明した上でそれぞれサインするように動いています。 今回は詳細は割愛しますが、機会があれば別の記事でお話します。 参考: 個人データの第三国への移転のための標準契約条項に関する2021年6月4日付欧州委員会実施決定(EU)2021/914 今後の課題 上記1~4のステップを踏み、それぞれサインをしてようやくデータ移転が可能となります。このプロセスを形にするために、GDPRの当事者としてイタリアと実際のGDTAのドラフトを含んで1年近くかかりました。今後はこのステップに則ってGKIDP参画事業体との契約を進めます。 上記はあくまでGDPRを基準にして記載しましたが、他の国にもデータをグローバルに移転させる上で必要な文書が存在する可能性があります。連携サービスが増える度、それぞれの法令とGDPRの差分を調査し、対応を進めて参りました。今後、KINTOがEver Better Mobility For Allを世界中に提供できるようになるためには、更に多くの国へ導入が必要となりますので、それぞれの国が持つ法令への遵守します。 さいごに このプロジェクトには入社したての頃にアサインされ、それまでGDPRはおろかプライバシーポリシーすら流し読み程度でした。そんな私が今ではグローバル開発グループの個人データ関連法窓口として、内部メンバーの質問に答えたり、社内のセキュリティチームなどの有識者と専門的な会話ができたりするようになったのは、「自ら知識を得ようとする人を歓迎・評価する風土」がKINTOテクノロジーズ内にあったからです。これからもこのような風土の中で個人データ以外にも自身のスキルアップに努めたいです。 尚、GDPRについての詳細は、インターネット上でも様々な記事が公開されておりますが、私は以下を参考にしていました。情報がまとまっていてとてもわかりやすいです。もちろん、素人だけで対応するのは危険なので、有識者からの意見は大事です 👨‍⚖️ 出典: 牧野総合法律事務所弁護士法人 / 合同会社LEGAL EDGE (2019) 図解入門ビジネス 最新GDPRの仕組みと対策がよ~くわかる本 個人情報保護委員会 An official website of the European Union
はじめに モバイル開発グループの日野森、木下、中口で、 iOSDC Japan 2022 に参加しました。2年ぶりにオフラインイベントが開催して、オンライン配信とオフラインのハイブリッドでしたので、それぞれの状況に合わせて参加しました。 本記事では参加した感想、印象に残ったトークを紹介します。 感想 日野森 ​ まず初めに、僕は今年で5年目の参加になりますが、毎年ノベルティがすごいですね! パンフレットも年々分厚くなってるので、時間がある時にゆっくり眺めたいと思います。 定番のTシャツは今年もおしゃれなデザインで早速家着として着倒しています。 ノベルティ パンフレット ![ノベルティ](/assets/blog/authors/HiroyaHinomori/IMG_1407.jpg =400x) ![パンフレット](/assets/blog/authors/HiroyaHinomori/IMG_1487.jpg =400x) 今年は3年ぶりのオフラインとオンラインの同時開催でしたが、 育児世代の僕は休日に1日外出は厳しいので、泣く泣くオンラインで試聴しました。 ​ (ニコニコ生放送での視聴期間は 2022/10/12(水) 23:59 までのようなので、未試聴の方は忘れずに。) ​ 今回も気になるセッション盛りだくさんでしたが、今回はSwiftUI周りのセッションの話をしていきたいと思います。 ​ ウーニャ、しってる。みんなふんいきでSwiftUIをつかってる。 Viewの分割のケーススタディがとても参考になりました。ルールをドキュメント化するのは大事ですが、ドキュメントが見やすいところにあるかも大事なのかなと思いました。 SwiftUI Navigation のすべて pointfreeさんのswiftui-navigationの話はとても良い情報でした。NavigationStackまでの繋ぎで使えそうな感じがします。 UIKit ベースの大規模なプロジェクトへの SwiftUI 導入 すでにリリースされているアプリをUIKitからSwiftUIに切り替える辛みが伝わる内容でした。iOS13初期バージョンはやはり鬼門ですね。 SwiftUIとUIKitを仲良くさせる UIKitとSwiftUIが混ざった状態での実装の注意点や対応方法についてのお話でしたね。まだまだUIKit <-> SwiftUIを行き来することが多いので、参考になりました。 ​ iOS16がリリースされ、多くのアプリの最低動作OSがiOS14に上がり、本格的にSwiftUIを使用する事を検討するタイミングだと思うので、関係するセッションも多く見掛けられました。 弊社でもこれからどんどんSwiftUIへシフトチェンジしていく予定ですが、やはり、過去のOSバージョンを加味するとフルSwiftUIでアプリを作成するには色々と乗り越えないといけない課題がある様なので、まだまだ注意が必要ですが、今回得た知見を元に弊社でも知見を増やしていきたいですね。 木下 iOSDCには、練馬で開催されたときから毎年参加していて、今年のナレーションもとても豪華でした。例の声を聞くと、帰ってきたなと思い出に浸れました。 今回のiOSDCで、個人的に覚えているセッションは以下になります。 Unreal EngineとiPhoneを使って始めるリアルタイムAR配信 頭のスッキリとした朝に視聴したことや、日々の先行開発としてPoCを回している業務中でUnityのライブラリを使ってUaal with Flutterを試していたこともあり、このセッションが記憶に残りました。Uaal with Flutterについては、今回は深く触れず、機会があれば別のブログ記事で紹介できればと思います。 セッションの発表者の記事や資料は、以下の登壇者の方のブログ記事にあります。 iOSDC 2022に登壇しました 様々なプラットフォームで実績のあるUnityではなく、Unreal Engineを用いた事例だったため珍しく、とても興味深かったです。 冒頭のリアルタイムAR合成のデモシーンでは、きれいに投影されていてニコ動のコメントも盛り上がってました。 3Dレンダリングソフトをモバイルに組み込んで扱いやすくするという情報は、少ない割に需要があると個人的には感じます。 Uaal with Flutterでアプリを作成しているときも、情報にあまり触れることがなかったこともあり、Unreal Engineができるなら試したかったので、もっと早く知れたらなと思いながら視聴していました。 世間的にメタバースがもっと盛り上がってきて、どんどんこの辺りの知見が溜まって、共有されていったら面白いと思いました。 また今回のiOSDCでは、会場でお弁当や飲み物の提供はなかったので、早くコロナが収まって、どぶ漬けが復活してくれることを願ってます。 会場の参加者と恒例のアレを片手に乾杯できるiOSDCが戻ってくることを楽しみに待っています。 運営スタッフの皆様、今年もお疲れさまでした。 また来年もよろしくお願いします! 中口 iOSエンジニアとしてのキャリアは 約2年で、iOSDCに本格的に参加したのは今回が初めてとなります。最近、ようやくMVVMやCombineに慣れてきたところだったので次のステップとしてSwiftUIやConcurrencyを勉強していきたいなと考えていたところでした。今回のiOSDCでは、それらの内容のセッションが多く大変参考になりました。書籍や技術記事など文字ベースのものだけではなかなか理解しにくい部分も多くいのですが、発表で聞くとクリアになる部分もありました。今後も、発表を復習してさらに理解を深められたらと思っています。 ウーニャ、しってる。みんなふんいきでSwiftUIをつかってる こちらのセッションでは、SwiftUIの中でも特に分割に関する内容を発表されておりました。 どのように分割していくかは絶対的な正解があるわけではないからこそ、非常に難しく悩ましい部分かと思いますので大変参考になりました。 また、非常に大事だなと感じた考え方として「言語化する」、「プロジェクトごとにルールをドキュメント化する」といったことを挙げられており、みんなが悩む部分だからこそしっかりと明示する必要があるのだなと感じました。 Swift Concurrency時代のリアクティブプログラミングの基礎理解 上記で述べた通り、Concurrencyに関しては勉強を始めたばかりということもありそもそもの有用性のようなものがあまり理解できていませんでした。 こちら発表ではいわゆるモバイルアプリのリアクティブプログラミングからConcurrencyに置き換えることができる場所とそうでない場所を明示していただけたので、Concurrencyの使い所が明確になりとてもスッキリしました。 Concurrencyは、可読性の高さからなるべく取り入れていけたらと思うのでこちらの発表を参考にしていきたいと思います。 おわりに iOSDC Japan 2022は、とても楽しかったです! iOSDC Japan 2023年に皆さん、またお会いしましょう! 2023年まで待てない方は、ぜひ KINTOテクノロジーズの採用情報 をご覧ください。 エンジニアに限らず、絶賛募集中です。 入社して会えるのも待ってます!
こんにちは。分析グループ(分析G)でMLOps/データエンジニアしてます伊ヶ崎( @_ikki02 )です。 こちらは「KINTOテクノロジーズ株式会社にてどのようにMLOpsを適用していくのか」というテーマでの連載3本目です。1本目の記事「 KINTOテクノロジーズのMLOpsを定義してみた 」および2本目の記事「 SageMakerを使った学習&推論のバッチパターン 」はそれぞれのリンクよりご確認ください。次回最終回となる記事では、他部署も巻き込んで開催した勉強会のお話を予定しています。 背景(Situation) 連載1本目にて「メタデータ管理(実験管理)」がなぜ必要なのか一般的な背景を記載しました。この記事ではKINTOテクノロジーズでの状況をより深掘りして見ていきたいと思います。 KINTOという会社およびサービスがトヨタグループで立上がってから4年目というまだまだ若いこともあって、ビジネスサイドとデータサイエンスサイドの関係性構築が求められていました。立上げ期特有のスピード感においては、コードの品質や文書化などの管理コストを多少犠牲にしてでも、迅速なアウトプットが重要であり、価値検証に比重が置かれます。 サービスの立上げ期においてこのアプローチは悪くないですが、順調にサービスも伸びてきて人も増えてくると、今度は管理コストの重要性が相対的に増してきます。特にデータサイエンスという分野は、組織的に管理するための方法論がソフトウェア開発のそれに比べるとまだまだ成熟していないと個人的に感じており、ブラックボックスになりがちです。そのため、データサイエンスプロジェクトの管理について方法論を模索し始めたフェーズでもありました。 業務(Task) データサイエンスプロジェクトの管理について、「メタデータ管理(実験管理)」という概念があります。以降、この記事では簡便のため、実験管理という表現で統一しようと思います。 実験管理の重要なポイントは、「シェアビリティ」と「記録の容易さ」「再現性」だと考えています。分析グループにはデータサイエンティストが4名在籍しており(2022/9時点)、各々のプロジェクトもあれば、複数人で共通の大型プロジェクトもあり、情報の共有に際しては共通のフォーマットがあると便利です。理想形は、データサイエンティストの誰がやってもモデル構築のプロセスと結果を再現できるよう、実行環境の情報や利用した具体的なデータ、コードスクリプト、機械学習のアルゴリズム、ハイパーパラメータなどの情報を記録しておくことです。しかし、「シェアビリティ」と「記録の容易さ」は実際にはトレードオフの関係にあり、他の人が結果を再現できるよう情報を記録すればするほど、記録の負荷はあがると言えます。そのため、記録の負荷をなるべく上げないためにも、繰返し記録することになる情報(例えば、実行環境のコンテナイメージ、処理開始&終了時間、データの置き場所、など)は一度きりの記述で自動的に連携されるような仕組みがあると望ましいです。 SageMaker Experimentsを用いれば、パイプラインの定義スクリプトにコードを一度書けば、その情報が自動的に記録されるので、データサイエンティストは記録したい実験に関する指標のみに集中すればよいことになります。また、任意で記録したい指標のコーディングについては、SageMaker SDKを使えば以下のように数行レベルで済むので、記録について最低限の負荷で済むと言えそうです。 やったこと(Action) 命名規則の整理 コンセプト的にマッチしているマネージドサービスを導入していくのは良いアプローチだと思いますが、それだけでは十分に活用できません。SageMaker ExperimentsはExperimentとTrialという小概念があります。 概念 簡単な説明 Experiment Trialを一定の粒度で集めた概念。分析PJや特定のプロダクトなど、何か特定の事例を表すことが多い。 Trial 機械学習プロセスの個別の処理。 概念が細分化されているため、それぞれの命名規則や使い方をうまく整理しなければ、各データサイエンティストがばらばらの使い方をしてしまい、情報のシェアビリティが落ちてしまいます。そこで、以下のように命名規則を整理してみました。 実験管理にあたって、まず用途を考え、大きく2種類の用途を想定しました。「パイプラインの実験管理」および「EDAの実験管理(※)」です。 ※ EDAは「探索的データ分析」のこと。 「パイプラインの実験管理」では、本番稼働しているパイプラインの情報を記録し、失敗した時など何らかの理由でパイプラインの結果を再現する必要があるときにそのプロセスを再現できるようにします。上図の「trialの命名」欄にある命名規則に従った①のTrialを見れば、実行環境に関する情報について、SageMaker Pipelinesが自動で作ってくれた情報を確認することができ、②の命名規則に沿ったTrialを見れば、データサイエンティストが任意で記録した各種指標を確認することができます。 一方で、本番稼働のパイプラインとは別で、モデルをより良くするために実験を都度実施し、その結果も記録して後で参照できるようにしたいというケースもあります。「EDAの実験管理」ではまさにそういったニーズに対応できるように、命名規則をあえて緩く設定しており、「debug-」とついたExperimentに関しては、Trial名はデータサイエンティストの実験の意図に応じて自由に決められるようにしています(実験パターンがある程度存在するようならそれに応じて設定を改めて検討するかもしれません)。 結果(Result) 上記の命名規則も併せてSageMaker Experimentsを使うことで実験管理を行うだけでなく、実施した実験(および本番稼働のパイプライン)の結果の分析もできます。過去のパイプラインの分析に関する指標をサクッと確認したいときは②の命名規則に沿ったTrialをGUIで確認できますが、本番稼働しているパイプラインの結果の推移を追いたいときなど、複数の実験結果を比較して分析したいときは、SageMaker Experimentsの結果をpandasのDataFrameにして分析したりすることができます。例えば、日次実行しているパイプラインの適合率について、折れ線グラフ上で推移を表示して確認したりできます。結果の可視化を行うことで、本番稼働しているパイプラインがモデルドリフトを起こしていないか確認したりできるでしょう。運用を通じてフィードバックを迅速に得ることで、モデルの再開発や微調整、継続的学習といったプロセスを素早く開始することも期待できます。 いかがでしたでしょうか。最終回となる次回の連載では、社内で実施した勉強会のお話を通じて、どのように知識を共有しているか、ご紹介したいと思います。引続きご覧いただける際は「 SageMaker勉強会と文化醸成(4/4) よりご覧ください。また、Tech Blogのツイッターもやっているので、本ページ最下部からフォローいただけると嬉しいです。
こんにちは。分析グループ(分析G)でMLOps/データエンジニアしてます伊ヶ崎( @_ikki02 )です。 こちらは「KINTOテクノロジーズ株式会社にてどのようにMLOpsを適用していくのか」というテーマでの連載3本目です。1本目の記事「 KINTOテクノロジーズのMLOpsを定義してみた 」および2本目の記事「 SageMakerを使った学習&推論のバッチパターン 」はそれぞれのリンクよりご確認ください。次回最終回となる記事では、他部署も巻き込んで開催した勉強会のお話を予定しています。 背景(Situation) 連載1本目にて「メタデータ管理(実験管理)」がなぜ必要なのか一般的な背景を記載しました。この記事ではKINTOテクノロジーズでの状況をより深掘りして見ていきたいと思います。 KINTOという会社およびサービスがトヨタグループで立上がってから4年目というまだまだ若いこともあって、ビジネスサイドとデータサイエンスサイドの関係性構築が求められていました。立上げ期特有のスピード感においては、コードの品質や文書化などの管理コストを多少犠牲にしてでも、迅速なアウトプットが重要であり、価値検証に比重が置かれます。 サービスの立上げ期においてこのアプローチは悪くないですが、順調にサービスも伸びてきて人も増えてくると、今度は管理コストの重要性が相対的に増してきます。特にデータサイエンスという分野は、組織的に管理するための方法論がソフトウェア開発のそれに比べるとまだまだ成熟していないと個人的に感じており、ブラックボックスになりがちです。そのため、データサイエンスプロジェクトの管理について方法論を模索し始めたフェーズでもありました。 業務(Task) データサイエンスプロジェクトの管理について、「メタデータ管理(実験管理)」という概念があります。以降、この記事では簡便のため、実験管理という表現で統一しようと思います。 実験管理の重要なポイントは、「シェアビリティ」と「記録の容易さ」「再現性」だと考えています。分析グループにはデータサイエンティストが4名在籍しており(2022/9時点)、各々のプロジェクトもあれば、複数人で共通の大型プロジェクトもあり、情報の共有に際しては共通のフォーマットがあると便利です。理想形は、データサイエンティストの誰がやってもモデル構築のプロセスと結果を再現できるよう、実行環境の情報や利用した具体的なデータ、コードスクリプト、機械学習のアルゴリズム、ハイパーパラメータなどの情報を記録しておくことです。しかし、「シェアビリティ」と「記録の容易さ」は実際にはトレードオフの関係にあり、他の人が結果を再現できるよう情報を記録すればするほど、記録の負荷はあがると言えます。そのため、記録の負荷をなるべく上げないためにも、繰返し記録することになる情報(例えば、実行環境のコンテナイメージ、処理開始&終了時間、データの置き場所、など)は一度きりの記述で自動的に連携されるような仕組みがあると望ましいです。 SageMaker Experimentsを用いれば、パイプラインの定義スクリプトにコードを一度書けば、その情報が自動的に記録されるので、データサイエンティストは記録したい実験に関する指標のみに集中すればよいことになります。また、任意で記録したい指標のコーディングについては、SageMaker SDKを使えば以下のように数行レベルで済むので、記録について最低限の負荷で済むと言えそうです。 やったこと(Action) 命名規則の整理 コンセプト的にマッチしているマネージドサービスを導入していくのは良いアプローチだと思いますが、それだけでは十分に活用できません。SageMaker ExperimentsはExperimentとTrialという小概念があります。 概念 簡単な説明 Experiment Trialを一定の粒度で集めた概念。分析PJや特定のプロダクトなど、何か特定の事例を表すことが多い。 Trial 機械学習プロセスの個別の処理。 概念が細分化されているため、それぞれの命名規則や使い方をうまく整理しなければ、各データサイエンティストがばらばらの使い方をしてしまい、情報のシェアビリティが落ちてしまいます。そこで、以下のように命名規則を整理してみました。 実験管理にあたって、まず用途を考え、大きく2種類の用途を想定しました。「パイプラインの実験管理」および「EDAの実験管理(※)」です。 ※ EDAは「探索的データ分析」のこと。 「パイプラインの実験管理」では、本番稼働しているパイプラインの情報を記録し、失敗した時など何らかの理由でパイプラインの結果を再現する必要があるときにそのプロセスを再現できるようにします。上図の「trialの命名」欄にある命名規則に従った①のTrialを見れば、実行環境に関する情報について、SageMaker Pipelinesが自動で作ってくれた情報を確認することができ、②の命名規則に沿ったTrialを見れば、データサイエンティストが任意で記録した各種指標を確認することができます。 一方で、本番稼働のパイプラインとは別で、モデルをより良くするために実験を都度実施し、その結果も記録して後で参照できるようにしたいというケースもあります。「EDAの実験管理」ではまさにそういったニーズに対応できるように、命名規則をあえて緩く設定しており、「debug-」とついたExperimentに関しては、Trial名はデータサイエンティストの実験の意図に応じて自由に決められるようにしています(実験パターンがある程度存在するようならそれに応じて設定を改めて検討するかもしれません)。 結果(Result) 上記の命名規則も併せてSageMaker Experimentsを使うことで実験管理を行うだけでなく、実施した実験(および本番稼働のパイプライン)の結果の分析もできます。過去のパイプラインの分析に関する指標をサクッと確認したいときは②の命名規則に沿ったTrialをGUIで確認できますが、本番稼働しているパイプラインの結果の推移を追いたいときなど、複数の実験結果を比較して分析したいときは、SageMaker Experimentsの結果をpandasのDataFrameにして分析したりすることができます。例えば、日次実行しているパイプラインの適合率について、折れ線グラフ上で推移を表示して確認したりできます。結果の可視化を行うことで、本番稼働しているパイプラインがモデルドリフトを起こしていないか確認したりできるでしょう。運用を通じてフィードバックを迅速に得ることで、モデルの再開発や微調整、継続的学習といったプロセスを素早く開始することも期待できます。 いかがでしたでしょうか。最終回となる次回の連載では、社内で実施した勉強会のお話を通じて、どのように知識を共有しているか、ご紹介したいと思います。引続きご覧いただける際は「 SageMaker勉強会と文化醸成(4/4) よりご覧ください。また、Tech Blogのツイッターもやっているので、本ページ最下部からフォローいただけると嬉しいです。
Introduction Hello. My name is Shiode, and I'm in charge of payment-related back-end development at the Woven Payment Solution Group. Our group uses Kotlin for development, and we use Ktor as the web framework. Ktor requires a separate JSON library to process JSON request bodies and return JSON responses. At the beginning, we used Gson as a JSON library, but we encountered problems using Gson, so we switched to Moshi. Today, I'm going to describe why we chose Moshi, the problems we faced when we used Moshi with Ktor, and how we solved them. The version of Ktor used in this article is the 2.x series. Switching from Gson to Moshi Issues with Gson Initially, we were using Gson as a Ktor JSON library. However, when receiving request bodies, we discovered that problems would occur if a necessary key was missing. For example, think about an endpoint that processes input as follows. data class Input ( val required: String, val optional: String? = null, ) post("/") { val input = call.receive<Input>() call.respondText("required was ${input.required}", status = HttpStatusCode.OK) } Since String type is required for the Input class, null is not permitted. However, null is permitted with optional . This endpoint is a simple one that receives the above Input as a request body and returns the required of the received body. With this endpoint, a NullPointerException (commonly known as Nullpo) will occur if you send an empty JSON {} that does not have a required . It would be preferable for an exception to occur during deserialization so as not to affect later processing, but an exception ends up occurring when accessing that variable, in this case call.respondText() . As a solution, there may be a way to make the Input class required a nullable type and perform a null check. However, since we're using Kotlin, we wanted to express it as a type where nulls are not allowed as far as possible, and write processing that is suitable for Kotlin. Therefore, it became necessary to select a JSON library that would throw an exception during deserialization. Why Did We Choose Moshi? This project is developed with a schema base that uses OpenAPI, and the generation of interacting classes depends on the OpenAPI Generator. Also, since the client also uses the one generated by the OpenAPI Generator, a JSON library supported by OpenAPI was brought up as a replacement candidate. The JSON libraries supported by OpenAPI Generator are shown below. Gson is excluded. Moshi Jackson kotlinx.serialization Jackson can support null safe by enabling Option, but when we looked at the relevant source code , performance was described as being affected. We decided to eliminate it as a candidate without comparing performance. Meanwhile, kotlinx.serialization is a library developed by JetBrains, and the fact that it's native to Kotlin and compatible with Ktor made it is a good candidate. However, Moshi has twice as many stars as kotlinx.serialization (at time of writing, Moshi: 8.5K, kotlinx.serialization: 4.1K), and Moshi is Gson v3 , so we decided to adopt Moshi. Problems Using Moshi with Ktor According to Ktor's PR#2004 , there is no Ktor support for Moshi at the time of writing. Also, according to PR#2005 , there seems to be no policy to provide Moshi as a core feature of Ktor in the future, either. On the other hand, it seems that Ktor is planning to provide a Marketplace , so there is a possibility that in the future a third party will provide a Ktor plugin that will allow Moshi to be used. But there is no support for it right now, so you'll have to make your own Ktor plugin to be able to use Moshi. Note that there is no information yet about the Marketplace at the time of writing. We're looking forward to hearing more about it. Solution Create a Ktor Plug-in to Enable Use of Moshi The following are the classes required for using Moshi with Ktor. This implementation is almost the same as GsonConverter for Ktor. class MoshiConverter( private val moshi: Moshi = Moshi::Builder().build(), ) : ContentConverter { override suspend fun serialize( contentType: ContentType, charset: Charset, typeInfo: TypeInfo, value: Any ): OutgoingContent? { return TextContent( moshi.adapter(value.javaClass).toJson(value), contentType.withCharsetIfNeeded(charset) ) } override suspend fun deserialize(charset: Charset, typeInfo: TypeInfo, content: ByteReadChannel): Any? { return withContext(Dispatchers.IO) { val body = content.toInputStream().reader(charset).buffered().use { it.readText() } moshi.adapter(typeInfo.type.java).fromJson(body) } } } It is used as shown below. install(ContentNegotiation) { register(ContentType.Application.Json, MoshiConverter()) } Compatibility with Moshi ArrayList When we use the above Ktor plugin, it deserializes as a JAVA type instead of a Kotlin type when deserializing. For example, it will deserialize as an ArrayList even though you want to store it in a List . Moshi doesn't support ArrayList deserialization by default, so an exception will be thrown when you try to deserialize a List . To support any type in Moshi, you need to prepare an Adapter for that type. Since we want to support ArrayList this time, we must prepare a Moshi adapter for ArrayList ourselves. The following adapters support ArrayList . This is almost identical to Moshi's CollectionJsonAdapter implementation. abstract class ArrayListJsonAdapter<C : MutableCollection<T?>, T> private constructor( private val elementAdapter: JsonAdapter<T> ) : JsonAdapter<C>() { abstract fun newCollection(): C override fun fromJson(reader: JsonReader): C { val result = newCollection() reader.beginArray() while (reader.hasNext()) { result.add(elementAdapter.fromJson(reader)!!) } reader.endArray() return result } override fun toJson(writer: JsonWriter, value: C?) { writer.beginArray() for (element in value!!) { elementAdapter.toJson(writer, element) } writer.endArray() } override fun toString(): String { return "$elementAdapter.collection()" } companion object Factory : JsonAdapter.Factory { override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? { if (annotations.isNotEmpty()) return null return when (type.rawType) { ArrayList::class.java -> { newArrayListAdapter<Any>(type, moshi).nullSafe() } Set::class.java -> { newLinkedHashSetAdapter<Any>(type, moshi).nullSafe() } else -> null } } private fun <T> newArrayListAdapter(type: Type, moshi: Moshi): JsonAdapter<MutableCollection<T?>> { val elementType = Types.collectionElementType(type, Collection::class.java) val elementAdapter = moshi.adapter<T>(elementType) return object : ArrayListJsonAdapter<MutableCollection<T?>, T>(elementAdapter) { override fun newCollection(): MutableCollection<T?> = ArrayList() } } private fun <T> newLinkedHashSetAdapter(type: Type, moshi: Moshi): JsonAdapter<MutableSet<T?>> { val elementType = Types.collectionElementType(type, Collection::class.java) val elementAdapter = moshi.adapter<T>(elementType) return object : ArrayListJsonAdapter<MutableSet<T?>, T>(elementAdapter) { override fun newCollection(): MutableSet<T?> = LinkedHashSet() } } } } Verifying Operation After creating a Ktor plug-in for using Moshi with Ktor and a Moshi adapter for deserializing ArrayList with Moshi, the next step is to verify operation. In order to use the one I just described, we need to write the following install(ContentNegotiation) { register(ContentType.Application.Json, MoshiConverter( moshi = Moshi::Builder().add(ArrayListJsonAdapter.Factory) )) } Then, let's try sending an empty JSON {} to the endpoint introduced in the first example in this article. Here's that endpoint again. data class Input ( val required: String, val optional: String? = null, ) post("/") { val input = call.receive<Input>() call.respondText("required was ${input.required}", status = HttpStatusCode.OK) } At first, nullpo was generated when accessing required , but now the following exception occurs for call.receive<Input>() during deserialization, as expected. com.squareup.moshi.JsonDataException: Required value ‘required’ missing at $ Conclusions Nullpo can occur when using Gson with Ktor. If you don't want nullpo to occur, you should choose another JSON library. To use Moshi with Ktor, you need to create your own Ktor plugin by yourself. If you do that, you need to make a Moshi adapter to deserialize ArrayList . References "Gson is deprecated," so try Moshi How to serialize ArrayList<float[]> using Moshi JSON library for Android
こんにちは、KINTO テクノロジーズ (以下 KTC) で DBRE をやっていますあわっち( @_awache ) です。 今回は僕が KTC で実現したい Database のガードレール構想についてお話ししたいと思います。 ガードレールとは ガードレールとは Cloud Center of Excellence (CCoE) の活動の中でよく表現される言葉です。 一言でガードレールを表現すると「可能な限り利用者の自由を確保しつつ、望ましくない領域のみ制限、または発見するためのソリューション」です。 ガバナンスを重視することを求められる Database 領域を取り扱うという役割の特性上、DB エンジニアは時に「ゲートキーパー」として作用してしまい、企業活動のアジリティを損なってしまうこともあります。 そこで DBRE の活動にこの「ガードレール」の考え方を取り入れてアジリティとガバナンスコントロールを両立させようと考えています。 ガードレールの種類 ガードレールは下記の 3種類に分類できます。 種類 役割 概要 予防的ガードレール 制限 対象の操作を出来ないような制限の適用 発見的ガードレール 検知 望ましくない操作を行った、された場合、それを発見、検知する仕組み 訂正的ガードレール 修正 望ましくない設定がなされた場合に自動で修正する仕組み 予防的ガードレール ![予防的ガードレール](/assets/blog/authors/_awache/20221004/preventive_guardrail.png =720x) 発見的ガードレール ![発見的ガードレール](/assets/blog/authors/_awache/20221004/heuristic_guardrail.png =720x) 訂正的ガードレール ![訂正的ガードレール](/assets/blog/authors/_awache/20221004/revise_guardrail.png =720x) ガードレール構想 導入当初の段階から予防的ガードレールによって強い制限を適用してしまうとこれまでできていたことや、やりたいことができなくなることで現場のエンジニアの反発や疲弊に繋がる可能性があります。 逆に訂正的ガードレールによって自動修復を行ってしまうと何が不適切だったのか、不適切な設定をどのように直していくのかを考えるというエンジニアのスキル向上の機会を失わせてしまうこともあるかと思います。 だからこそ現在は可能な限り利用者の自由を確保し、ガバナンスコントロールを実現するための地盤固めのフェーズだと思っています。その上で「発見的ガードレール」を取り入れることが望ましいと考えています。 現在 KTC では DEV/STG/PROD の 3ステージ制を導入しているため発見的ガードレールによってリスクを検知の周期を Daily で回したとしても、多くの場合本番に適用される前に気付ける状態にあります。発見的ガードレールで不適切な設定を定期的に検知し、それを受け取った現場のエンジニアが修正して適用する、というサイクルを継続的に回すことでサービスレベルの底上げに繋げられればこの仕組みの価値も上がっていきます。 もちろん発見的ガードレールは提供して終わりではなく、そこで検知されるルールを現場の状況に合わせてアップデートし続けることも大切です。現場のエンジニアと伴走し KTC の実態にあったガードレールを提供することで、この仕組み自体も KTC と一緒に成長していく必要があります。 Executive Sponsor の強力な後ろ盾 「ガードレールで検知されたものはエラーレベルに応じて対応する」ということが浸透しなければ狼アラートを増やすだけです。また個別のサービスの事情に応じてこのルールは対応しない、ということを許容してしまうこともアンチパターンだと考えます。 そこで大切にするべきことは「KTC としてサービスを提供する以上最低限守るべきルールだけを盛り込むこと」です。 細か過ぎるルールは定義せず、ガードレールでアラートが上がったらエラーレベルに応じて対応をする、の一点を KTC 内の全てのエンジニアに対して共通認識化、浸透させることができなければこの仕組みの価値がありません。 そこで最後の後押しをしてくれるのは、活動を後押ししてくれる Executive Sponsor です。Executive Sponsor は経営層、CxO など、企業としての方向性を示してくれる役割の方が望ましいです。 最初はどれだけ気を遣ったとしても現場のエンジニアにルールを強制する、という本質的なことは変わらないので、この活動が Executive Sponsor を通じて経営でコミットされているということは彼らが協力的に動く一つの理由やモチベーションとして作用するはずです。 責任分界点 KTC の DBRE は横断組織でありサービスを直接運用しているわけではありません。そのためどこからどこまでが DBRE の責任でどこからどこまでは現場のエンジニアの責任なのか、を明確にする必要があります。 僕はこれをDMAIC というフレームワークを用いて考えました。DMAIC については 「 【DMAICとは:定義、測定、分析、改善、定着】業務フロー改善プロジェクトの必勝パターン(リーンシックスシグマ) 」に非常に分かりやすくまとまっていると思いますのでこちらをご覧ください。 この5段階の手順にざっくりと誰が責任を持つのか、そしてそこでやるべきこと、を当てはめると下記のようになります。 定義 内容 作業 最終責任 Define 計測/評価の範囲や内容の定義 文書化 Script 化 DBRE Measure 計測/評価を実施して結果を収集 Script の実行 DBRE Analyze 原因の分析/レポーティング 組織全体の可視性を高める DBRE Improve 不具合の改善/改善計画の作成 問題に対してスムーズな対応を実施 プロダクト Control 成果を確認し、定着を目指す サービスとして健全な状態が継続されている プロダクト ![責任分界点](/assets/blog/authors/_awache/20221004/DemarcationPointOfResponsibility.png =720x) この図はそれぞれ役割を明確にしつつも、 全てのステップでお互いに相談や改善、など連携しながら最終的な責任をどこが持つのか、ということを表しています。例えば DBRE は現場の改善や定着に向けた動きを一切手助けしないということではない、ということを補足させていただきます。 どのようにガードレールを構築するのか ここまで長々とガードレールを構築するまでの考え方を記載させていただきましたがここから具体的な取り組みについて説明させていただきます。 [Define] エラーレベルの定義 最初にエラーレベルを定義することは最も重要です。 エラーレベルとはこのガードレールが KTC に提供する価値そのものです。DBRE としてどれだけ Must でやるべきことと考えたとしても定義されたエラーレベルに合ってなければ Notice もしくは対象外になります。設定したルールを定義に照らし合わせることを僕自身も徹底することで現場のエンジニアに対する説明責任を果たすことや、「何でも Critical」としたい欲求などをコントロールすることができます。 具体的な定義は下記の通り設定しました。 Level 定義 対応速度 Critical セキュリティ事故に直結する可能性があるもの クリティカルな異常に気付けない状態になっているもの 即時対応を実施 Error サービスの信頼性やセキュリティに関係する事故が発生する可能性があるもの Database 設計上の問題でおよそ 1年以内に悪影響を及ぼす可能性のあるもの 2 ~ 3営業日対応を実施 Warning それだけではサービスの信頼性やセキュリティ事故に直結しないもの セキュリティリスクを含むが影響が限定的なもの Database 設計上の問題でおよそ 2年以内に悪影響を及ぼす可能性があるもの 計画的対応を実施 Notice 正常に動作しているが記録しておきたい重要なもの 必要に応じて対応 [Define] 具体的な内容整理 続いて定義したルールの中でガイドライン作成を検討することになるのですが、最初から Database 全体を見ようと思うと失敗してしまいます。そのため僕は最初のステップではガードレールの範囲を「おおよそ自力でできる範囲」と置いています。おおよそ自力でできる範囲、とは今動いているサービスに対する深いドメイン知識がなくてもできる範囲、例えば Database クラスター(KTC ではメインの DB は Amazon Aurora MySQL を使用しています) の設定や、DB 接続ユーザーの作成、Schema、Table、Column の定義、がそこにあたります。逆に現段階でガードレールで手を出さないところはスキーマ設計やデータ構造、Query などになります。 特にここでのポイントは 「Slow Query が発生した場合の対処」をガードレールに設定していないこと、です。Slow Query は非常に重要な指標になりうるものですが、サービス単位の深いドメイン知識がなければ対応は困難です。もし現段階で大量に出ていたとしたらどこから手をつけたらいいのか、そしてそれをエラーレベルに応じた期限通りに確実に対処し続けることも難しい状態です。 Slow Query に関してはまずはガードレールではなく、Slow Query を可視化し誰でも状況が確認できるようにする、そしてそれを対処することを SLO として定義し、 DBRE から個別に提案してみる、という動きをもって段階を踏んで考えていきたいと思っています。 ガードレールで確認する領域イメージ ![Responsibility](/assets/blog/authors/_awache/20221004/Responsibility.png =720x) [Define] ガイドラインの設定/スクリプト化の実施 定義したエラーレベルや、手を出す範囲を決めた上でガイドラインに落とし込みます。そこで合意を得たものに関して自動的に検出できるようにします。 こうして作成したガイドラインを一部紹介します。 チェック項目 Error Level 理由 Database に対する Backup 設定が有効である Backup が設定されてなかった場合には Error となります Backup は自然災害、システム障害、または外部からの攻撃などによるデータ消失のリスクに対する有効な対策です バックアップ保持期間が十分な期間である Backup 保持期間が 7 未満の場合には Notice となります。 重大な損失から復旧するためには一定の期間を必要とします。 どの程度あれば十分なのか、一概な定義はありません。そのため AWS の自動スナップショット機能のデフォルトを設定しています。 Audit Log の出力が有効である Audit Log の設定がされていなかった場合には Critical となります Database に対して、いつ、誰が、何をおこなったのかをログとして残すことでデータ消失やデータ漏洩のリスクに正しく対応することができます Slow Query Log の出力が有効である Slow Query の設定がされていなかった場合には Critical となります Slow Query の設定が有効でなかった場合、サービス障害の起因となる Query を特定できない可能性があります Schema、Table、Column の文字コードに utf8(utf8mb3) で構成されたオブジェクトが存在しない Schema、Table、Column の文字コードに utf8(utf8mb3) で構成されたオブジェクトが存在した場合、 Warning となります utf8(utf8mb3) では格納できない文字列が存在してしまいます また近いうちに MySQL のサポートからも対象外となることが 明記 されています 全てのテーブルに Primary Key が存在している 主キーのないテーブルを利活用していた場合、 Warning となります そのスキーマの主体は何か、機械的にレコードを一意に特定するためには主キーが必要になります Schema、Table、Column の名前に予約語となる文字列だけで構成されたものがない 予約語だけで構成された名前が存在した場合、 Warning となります 予約語だけで構成された名前は将来的に使えなくなる、もしくは必ずバッククオート(`)で囲う必要があることが予定されています。 予約語一覧は 9.3 キーワードと予約語 を確認しましょう これらは AWS の API や Information Schema (一部 mysql Schema や Performance Schema) だけの情報から取得可能な範囲にしています。 ![Point of Automation](/assets/blog/authors/_awache/20221004/PointOfAutomation.png =720x) これらの情報を取得した上でスクリプト化します。例えば 「Schema、Table、Column の文字コードに utf8(utf8mb3) で構成されたオブジェクトが存在しない」を調べたければ下記のクエリを実行することで取得できます。 SELECT SCHEMA_NAME, CONCAT('schema''s default character set: ', DEFAULT_CHARACTER_SET_NAME) FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys', 'tmp') AND DEFAULT_CHARACTER_SET_NAME in ('utf8', 'utf8mb3') UNION SELECT CONCAT(TABLE_SCHEMA, ".", TABLE_NAME, ".", COLUMN_NAME), CONCAT('column''s default character set: ', CHARACTER_SET_NAME) as WARNING FROM information_schema.COLUMNS WHERE TABLE_SCHEMA NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys', 'tmp') AND CHARACTER_SET_NAME in ('utf8', 'utf8mb3') ; その他のステップ(Measure/Analyze/Improve/Control) 上記のようなクエリなどガイドラインを満たすための情報取得をスクリプト化したものを定期的に実行し、その結果が適切でないと判断された場合にはアラートを送る、それをガードレールとして機能させる Platform を構築します。そして取得した結果の可視性を高めるための Dashboard を用意し現場のエンジニアに対応してもらう、このサイクルを回すことが当面の僕の DBRE としての活動軸になると考えています。 このガードレールの仕組みの良い点は、例えば 「1秒以上 Slow Query のうち、フロントエンドからの Query が 1ヶ月の 99パーセンタイルで 0 になること」が KTC 内で必要とされるようになった場合には、そのルールを加えればそれだけで KTC で管理している全てのサービスに適用できることです。逆に不要になったルールを外すことも一括で可能となります。 これが僕の考えるスケールする Database ガードレールの構想です。 まとめ いかがでしたでしょうか?今回は僕が KTC の DBRE としてスケールし、継続的な価値提供を生み出していくための一つの軸として考えている DBRE ガードレールについて紹介させていただきました。 まだまだ構築段階ですがこれまでのように Database 技術 を用いているわけではなく、その技術をどのように効果的に KTC に適用するのか、そしてビジネス価値に繋げるところまで考えた DBRE 組織を作っているところです。そう言った意味でも今はチャレンジの時期でアプリケーションエンジニアリングからクラウドエンジニアリングまで幅広く行なっています。 こういったことを一歩一歩積み重ねて継続して皆さんにアウトプットしていこうと思っていますので引き続きよろしくお願いします! またこの活動に少しでも興味を持ったり話を聞いてみたい、と思った方はお気軽に Twitter DM 等でご連絡いただければと思います。
By Ikki Ikazaki, MLOps/Data Engineer in Analysis Group This is the second part in a multi-part series on how KINTO Technologies Corporation(KTC) developed a system and culture of Machine Learning Operations(MLOps). The first part was How We Define MLOps in KTC . The two subsequent posts will be about SageMaker Experiments to track the experiments conducted by data scientists, and "Benkyo-kai", a series of internal study sessions, to form the common knowledge about SageMaker and MLOps with other departments. Situation In this post, we are focusing on batch implementation of ML training and serving process using SageMaker Pipelines. We will refer to "Batch training pattern" and "Batch pattern" as defined by Mercari, inc. Before getting into details of the technical explanation, let us introduce an analysis backgroud briefly about demand forecast for our service: KINTO ONE. KINTO ONE is an all-inclusive lease solution that gives you all the benefits of driving a new vehicle with a transparent monthly fee. Our Marketing & Planning Department and Analysis Group tries to understand the customer demand for KINTO ONE in Japan and check the dashboard weekly where they can see all the important figures and KPIs. Those numbers or its analytical data are generated by subsequent data and ML pipelines' regular processing, and thus it is important to organize the whole relevant systems of the dashboard to securely monitor and operate. ↑ TOYOTA car lineup KINTO ONE offers(As of July 2022) Task As described above, we need to implement the system so that we can check the latest information, but the question is how often the data should be updated. Launching a serving endpoint for real time prediction incurs unnecessary cost even when we don't need it while updating the prediction result less frequently causes the stale data and even misunderstanding among the business analysts. In our case, they are supposed to check the dashboard weekly and sometimes look up the specific values or KPIs once they come up with some analytical hypotheses. Therefore, it would be enough to update the dashboard daily and that they can check the values based on the data of the previous day. Then, batch system which is triggered by time-based schedule of cron syntax seems good for our use case. Also, since we have the software program of KINTO ONE on top of AWS, it becomes easier to build the ML pipeline using AWS managed service. Action The whole architecture of ML pipeline is depicted as below. SageMaker Pipelines SageMaker is a managed IDE for ML developers and provides us the capability to design, develop, and operate the whole ML-related processes. To implement batch pattern for our usecase, one of its features, SageMaker Pipelines, is the best fit solution. You can implement the ML pipeline with it by combining each pipeline's step which is in turn built as SageMaker Processing, the managed data processing component of SageMaker. Through configuring the pipeline's definition, you can also visualize it in the format of Directed Acyclic Graph(DAG) like below. The following is the brief description about each step. Step Name Brief Description Extract Data extraction step using AWS Athena to query. PreProc Data preprocess step for time series analysis. Train Model building step using the dedicate SageMaker SDK. TrainEvaluation Evaluation step about whether the model performance and objective metrics meet the criteria. Predict Prediction step using the trained model and future data to be predicted. PostProc Data postprocess step for the integration with data platform. You can flexibly design the pipeline like above with your imagination and the important thing here is that you can execute the pipeline as a batch process. Because SageMaker Pipelines is natively integrated with Amazon EventBridge, you can initiate SageMaker Pipelines when the schedule of cron expression triggers the EventBridge. EventBridge can also be used for monitoring. It is important to track whether the daily pipeline was executed successfully or not to ensure the latest dashboards. The execution status of SageMaker Pipelines including each step's status is transmitted to CloudWatch and EventBus without any settings and EventBridge can target SNS Topic to notify the execution status in real time. And while the pipeline is stable most of the time, we do have a Slack channel to monitor the daily status execution in order to handle the issues as soon as the pipeline execution fails. QuickSight At the last step of the above pipeline, the prediction result is registered into Glue Catalog Table so that it can be queried through Athena. Specifically speaking, it adds the daily partition for the prediction result — which brings you another benefit by making the pipeline idempotent that you can just re-run the failed execution to fix the bug. From the consumer perspective, it becomes easier and cheaper to extract the prediction result as it is partitioned and the consumer just specify the data range they need. QuickSight, a managed BI dashboard AWS offers, also extracts data through Athena and displays the dashboards by aggregating the prediction results. Actually, "Athena type" of QuickSight's Datasets can import the queried data to SPICE, its in-memory calculation engine, based on the schedule you set so that the dashboards reflect the latest information. The only trick in the entire system is just to orchestrate the schedules of ML pipeline and dashboard's refresh timing. Since it takes time to finish the ML pipeline execution, we need a buffer time before the dashboard refreshes. One thing we were not expecting is that SageMaker Pipelines take 5-10 minutes to initiate a computing instance at each step. As illustrated above, there are 5 steps in serial, so all in all the pipeline initialization takes almost an hour to finish. Fortunately, there were no fast refresh requirements this time and the extra an hour doesn't cause serious problem for the entire system. Result The orchestration of SageMaker Pipelines and QuickSight can be seen as one of batch implementation of prediction system. The benefit by applying a batch system rather than having endpoints for real-time prediction is to make the operation easy to manage — please also visit my previous post where I described that one of main goals of MLOps is "PJ Management With Speed". Imagine if you deploy a new version on prediction endpoint, you need another deployment system such as Kubernetes Deployment to not cause or reduce downtime. On the other hand, if you implemented an idempotent batch system, the desired outcome can be obtained just by re-running it even if you failed the deployment or found any bugs on the new version. Also, operating the batch pattern prediction costs relatively less compared to having the endpoints simply because batch pattern costs only pay-as-you-go. The cheaper you develop and operate, the higher the chances to increase your return on investment(ROI). In addition, it enables you to assign a dedicated role to each technical component such that ML engineers look after SageMaker Pipelines while BI engineers take care of QuickSight's dashboards, which leads you to a more smoother operation and collaboration. BI engineers always pay attention to dashboards and their values, and notice some abnormalities once the displayed values show anomalies. It may take some time to fix the bug on the ML pipeline side, but BI engineers can handle the issues by themselves by, for example, using the past queried data to compensate the null data or simply not showing the dashboards. This post introduced about batch pattern prediction using SageMaker Pipelines, but there's still a lot more to talk about. MLOps is a huge topic! Next time, we will explain about how we track the model performance of the pipeline every day as metadata management. Follow KTC Tech Blog for future posts to stay up to date. Part 3 is available from here . Reference Shibui, Y., Byeon, S., Seo, J., & Jin, D. (2020). ml-system-design-pattern[GitHub Pages]. Retrieved from https://mercari.github.io/ml-system-design-pattern/
はじめに こんにちは。Woven Payment Solution Groupで決済関係のバックエンド開発を担当している塩出です。 本Groupでは開発にKotlinを使用しており、webフレームワークにはKtorを使用しています。KtorではJSONのリクエストボディーを処理したり、JSONのレスポンスを返却するために、JSONのライブラリが別途必要となります。 当初、JSONライブラリとしてGsonを使用していましたが、Gsonを使う上で問題に直面したのでMoshiに切り替えました。 今回はなぜMoshiを選んだのか、KtorでMoshiを使う際の問題点とその解決方法についてまとめました。 なお、この記事で使用しているKtorのバージョンは2.x系です。 GsonからMoshiへの切り替え Gsonの問題点 当初はKtorのJSONライブラリとしてGsonを使っていました。しかしリクエストボディーを受け取る際、必須キーが抜けている場合に問題が発生することが分かりました。 例として、以下のようなinputを処理するエンドポイントを考えます。 data class Input ( val required: String, val optional: String? = null, ) post("/") { val input = call.receive<Input>() call.respondText("required was ${input.required}", status = HttpStatusCode.OK) } Input classの required は String 型なのでnullを許容しません。一方 optional はnull許容型です。 このエンドポイントはリクエストボディーとして上記 Input を受け取り、受け取ったbodyの required を返却する、単純なものです。 このエンドポイントに対して required がない空JSON {} を送信するとNullPointerException(通称ぬるぽ)が発生します。後の処理に影響を与えないように、デシリアライズ時に例外が発生してほしいところですが、その変数へのアクセス時、ここでは call.respondText() に例外が発生してしまいます。 解決策としてInput classの required をnull許容型にしてnullチェックをする方法もあるかもしれません。しかしKotlinを使っている以上nullを許容したくないところはなるべく型で表現して、Kotlinっぽく処理を書きたいところです。 したがって、デシリアライズ時に例外を発生させてくれるJSONライブラリの選定が必要になりました。 なぜMoshiを選んだか このプロジェクトではOpenAPIを使用したschema baseで開発しており、やりとりするclassの生成はOpenAPI Generatorに依存しています。またclientもOpenAPI Generatorで生成されるものを使用しているので、乗り換え候補としてOpenAPIが対応しているJSON ライブラリが挙がりました。 OpenAPI Generatorが対応しているJSONライブラリは以下の通りです。Gsonは除外しています。 Moshi Jackson kotlinx.serialization JacksonはOptionを有効にすることでnull safeに対応できますが、 該当するソースコード を見るとパフォーマンスに影響がある、という記述がありました。パフォーマンスの比較は行っていませんが、候補からは外すことにしました。 kotlinx.serializationはJetBrainsが開発しているライブラリであり、KotlinネイティブかつKtorとの相性も良さそうで候補としては良いと思います。しかし、Moshiの方がstar数がkotlinx.serializationよりも倍くらい多く(執筆時でMoshi: 8.5k, kotlinx.serialization: 4.1k)、また MoshiがGson v3である とのことだったので、Moshiを採用することにしました。 KtorでMoshiを使う際の問題点 Ktorの PR#2004 によれば、執筆時点ではKtorによるMoshiのサポートはありません。また PR#2005 によれば今後ともKtorのcore機能としてMoshiを提供する方針は今の所ないようです。 一方で、Ktorで Marketplace なるものを提供する予定があるようなので、将来的に3rdパーティーからMoshiを使えるようにするKtorのプラグインが供給される可能性はあります。しかし今はサポートがないので、Moshiを使えるようにするためのKtorプラグインを自分で作る必要があります。 なお、執筆時点ではまだMarketplaceの情報はありませんでした。続報に期待したいと思います。 解決方法 Moshiを使用可能にするKtorプラグインの作成 以下はKtorでMoshiを使用するために必要なクラスです。この実装はKtorの GsonConverter とほぼ同じです。 class MoshiConverter( private val moshi: Moshi = Moshi::Builder().build(), ) : ContentConverter { override suspend fun serialize( contentType: ContentType, charset: Charset, typeInfo: TypeInfo, value: Any ): OutgoingContent? { return TextContent( moshi.adapter(value.javaClass).toJson(value), contentType.withCharsetIfNeeded(charset) ) } override suspend fun deserialize(charset: Charset, typeInfo: TypeInfo, content: ByteReadChannel): Any? { return withContext(Dispatchers.IO) { val body = content.toInputStream().reader(charset).buffered().use { it.readText() } moshi.adapter(typeInfo.type.java).fromJson(body) } } } 使い方は以下のようになります。 install(ContentNegotiation) { register(ContentType.Application.Json, MoshiConverter()) } MoshiのArrayList対応 上記のKtorプラグインを使用すると、デシリアライズ時にKotlin typeではなく JAVA typeとしてデシリアライズしてしまいます。例えば、 List に格納したいのに、 ArrayList としてデシリアライズが動いてしまうということになります。 Moshiはデフォルトで ArrayList のデシリアライズに対応していないので、 List をデシリアライズしようとしたときに例外が発生してしまいます。 Moshiで任意の型に対応するためには、その型のAdapterを用意する必要があります。今回は ArrayList に対応したいので、 ArrayList 用のMoshi adapterを自分で用意しないといけません。 以下は ArrayList に対応するadapterです。これはMoshiの CollectionJsonAdapterの実装 とほぼ同じです。 abstract class ArrayListJsonAdapter<C : MutableCollection<T?>, T> private constructor( private val elementAdapter: JsonAdapter<T> ) : JsonAdapter<C>() { abstract fun newCollection(): C override fun fromJson(reader: JsonReader): C { val result = newCollection() reader.beginArray() while (reader.hasNext()) { result.add(elementAdapter.fromJson(reader)!!) } reader.endArray() return result } override fun toJson(writer: JsonWriter, value: C?) { writer.beginArray() for (element in value!!) { elementAdapter.toJson(writer, element) } writer.endArray() } override fun toString(): String { return "$elementAdapter.collection()" } companion object Factory : JsonAdapter.Factory { override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? { if (annotations.isNotEmpty()) return null return when (type.rawType) { ArrayList::class.java -> { newArrayListAdapter<Any>(type, moshi).nullSafe() } Set::class.java -> { newLinkedHashSetAdapter<Any>(type, moshi).nullSafe() } else -> null } } private fun <T> newArrayListAdapter(type: Type, moshi: Moshi): JsonAdapter<MutableCollection<T?>> { val elementType = Types.collectionElementType(type, Collection::class.java) val elementAdapter = moshi.adapter<T>(elementType) return object : ArrayListJsonAdapter<MutableCollection<T?>, T>(elementAdapter) { override fun newCollection(): MutableCollection<T?> = ArrayList() } } private fun <T> newLinkedHashSetAdapter(type: Type, moshi: Moshi): JsonAdapter<MutableSet<T?>> { val elementType = Types.collectionElementType(type, Collection::class.java) val elementAdapter = moshi.adapter<T>(elementType) return object : ArrayListJsonAdapter<MutableSet<T?>, T>(elementAdapter) { override fun newCollection(): MutableSet<T?> = LinkedHashSet() } } } } 動作確認 KtorでMoshiを使えるようにするためのKtorのプラグインと、Moshiで ArrayList をデシリアライズするためのMoshi adapterが作成できたので、動作確認します。 上記で紹介したものを使うには以下のように記述する必要があります。 install(ContentNegotiation) { register(ContentType.Application.Json, MoshiConverter( moshi = Moshi::Builder().add(ArrayListJsonAdapter.Factory) )) } その上でこの記事の最初の例で紹介したエンドポイントに対して、空JSON {} を送信してみます。 そのエンドポイントを再掲します。 data class Input ( val required: String, val optional: String? = null, ) post("/") { val input = call.receive<Input>() call.respondText("required was ${input.required}", status = HttpStatusCode.OK) } 最初は required にアクセスする際にぬるぽが発生していましたが、今度は期待通りにデシリアライズ時の call.receive<Input>() のところで次の例外が発生するようになりました。 com.squareup.moshi.JsonDataException: Required value ‘required’ missing at $ まとめ KtorでGsonを使用するとぬるぽが発生することがあります ぬるぽの発生を嫌うのであれば別のJSONライブラリを選択する必要があります KtorでMoshiを使用するために、自分でKtorのpluginを作る必要があります その場合、 ArrayList をデシリアライズするためのMoshi adapterを作る必要があります 参考 「Gson is deprecated.」らしいのでMoshiを試してみる How to serialize ArrayList<float[]> using Moshi JSON library for Android
こんにちは。分析グループ(分析G)でMLOps/データエンジニアしてます伊ヶ崎( @_ikki02 )です。 こちらは「KINTOテクノロジーズ株式会社にてどのようにMLOpsを適用していくのか」というテーマでの連載2本目です。1本目の記事「 KINTOテクノロジーズのMLOpsを定義してみた 」はリンクよりご確認ください。後続の記事では、SageMaker Experimentsを用いた実験管理、そして、他部署も巻き込んで開催した勉強会のお話などをしていければと考えています。 背景(Situation) 2本目のこの記事では、SageMaker Pipelinesを用いたバッチパターンの学習および推論の実装に焦点を当てていきたいと思います。バッチパターンとは、メルカリ社が公開している ml-system-design-pattern にて「Batch training pattern」および「Batch pattern」として紹介されている内容(2022/8時点)を参考にしています。 実装の詳細に入る前に、当社のKINTO ONEにおける需要予測について、簡単に紹介します。KINTO ONEはトヨタの新車を自動車保険や自動車税なども込みで定額で利用できるサービスです。 マーケティング部門と分析グループにおいて、ユーザーの申込状況や各種主要KPIをダッシュボードで定期的に確認しています。その数値はデータ基盤のETL処理や機械学習のMLパイプラインを通して生成されるため、ダッシュボードの運用管理には、それらシステムの全体をうまくオーケストレーションする必要があります。 ↑(2022/7時点のKINTO ONEサイトの車種ラインアップページ) 業務(Task) ダッシュボード上で最新の情報を確認できるように、更新頻度をうまく設定する必要があります。データの更新を常時行えるようにしようとすると、任意のタイミングで更新リクエストを投げられるエンドポイントを起動する必要がありますが、リクエストがないときはインスタンスの起動分無駄なコストがかかり続けます。一方で、更新頻度が少なすぎると、古い情報を参照することになり、意思決定プロセスに影響を与えることが懸念されます。 今回の事例では、ダッシュボードの確認頻度は、基本的に週次の定例か、アナリストの突発的な閃きを随時確認するといったケースがほとんどなため、ダッシュボードの更新頻度は日次で前日分のデータを見ることができれば問題ないという要件でした。そのため、実装すべき更新プロセスはcron形式の日次スケジュールで起動できれば要件を満たせそうです。 なお、このバッチの実装に際しては、KINTO ONEのソフトウェアがAWS上で稼働しているということもあり、データ更新パイプラインもAWSのマネージドサービスを使うことで容易な連携が期待できました。 やったこと(Action) データ更新における、機械学習部分のアーキテクチャは以下の図の通りです。 SageMaker Pipelinesについて SageMakerはAWSが提供する機械学習のマネージドな統合開発環境で、バッチ処理の実装に際しては、SageMaker Pipelinesという組込み機能を使うと良さそうでした。 SageMaker Pipelinesは、SageMaker ProcessingというETL処理に特化した別の組込み機能を機械学習パイプラインのステップとして実装することができ、そのステップをDAG(有向非巡回グラフ)として繋ぎ合わせることで機械学習パイプラインを実装することができます。DAGはもちろん可視化することもでき、以下のように表示できます。 実装は自由に作り込めますが、上図では各ステップを次のような責務で実装しています。 ステップ名 簡単な説明 Extract AWS Athenaを用いてデータを抽出するステップ PreProc 時系列データ用の加工をする前処理ステップ Train SageMaker SDKを用いて、学習し、モデルを構築する学習ステップ TrainEvaluation 学習済みモデルの目的変数が基準を満たしているか評価する評価ステップ Predict 学習済みモデルと推論用データを用いて推論を行う推論ステップ PostProc 推論したデータをデータ基盤に連携できるよう加工する後処理ステップ このパイプラインをバッチとして実行するには、SageMaker Pipelinesとネイティブに組込みされているEventBridgeを活用することができます。EventBridgeはAWSの各リソースが生成するイベントに基づいてターゲットを起動するイベント駆動型のトリガーか、cron形式で定義されたスケジュールに基づいてターゲットを実行する方法から選択することができ、今回は日次のスケジュールを指定しています。以下の図のように起動が確認できます。 また、EventBridgeは監視の目的でも利用しています。「SageMaker Pipelinesの実行ステータス(成功、失敗、など)」および「SageMaker Pipelinesを構成する各ステップの実行ステータス」をイベントとして検知することができ、そのイベントをSNSトピックに飛ばすことで機械学習パイプラインの実行ステータスをリアルタイムで確認しています。ダッシュボードが最新の状態に保たれているかどうかはこの監視機構を通じてslackチャンネルに通知しており、もし何らかの理由で失敗すればすぐにパイプラインの実行ログを確認して対応できるようにしています。 QuickSightについて 上述のパイプラインの最後のステップではデータ基盤への連携を行っています。具体的には、推論結果のデータをGlueのカタログテーブルとして読み込めるようにテーブルスキーマを整え、Athenaで推論結果をクエリできるようにしています。パイプラインは日次で実行されるので、Glueのカタログテーブルのパーティションに日付単位で追加されるようにしています。このようにすることで、パイプラインを実行日指定で冪等に実装でき、パイプラインが失敗してもその日の推論結果について再実行すれば直るようにしています(同じ実行日については繰り返し実行しても結果が上書き更新されるだけで処理自体は変化しません)。 また、クエリを書くアナリスト視点では、必要な実行日分の推論結果にのみクエリすることで、クエリ処理時間および費用の削減に繋げています。 このようにAthena経由で推論結果を取得できるので、ダッシュボードとしてはQuickSightを使って更新しています。QuickSightはAWSが提供するマネージドなBIダッシュボードで、QuickSightが読み込むデータセットを"Athena"に指定することでSPICEというインメモリの集計エンジンに日次でデータを取込むことができます。ただし、このQuickSightの日次取込みは、上述の機械学習パイプラインとは別のスケジュールで起動するため、2つのスケジュールをうまく合わせる必要があります。 SageMaker Pipelinesを使って想定外だったのが、SageMaker Pipelinesの各ステップのインスタンス起動に都度5~10分ほどかかるため、上述のパイプラインのように、ステップが5つ同期的に繋がったパイプラインでは、インスタンスの起動と終了だけで1時間弱の実行時間を予め見積もっておく必要があります(上図のElapsed timeが該当します)。今回の要件としては、日次で実行できればよく、実行スケジュールに余裕があったため、特に問題にはなりませんでしたが、要件次第ではSageMaker Pipelinesのクセとして気を付ける必要がありそうです。 結果(Result) SageMaker PipelinesとQuickSightを組み合わせたダッシュボード更新ロジックは、全体として一つのバッチとして見なすことができ、学習および推論のバッチパターンとしてみなすことができると考えています。バッチパターン採用の大きなメリットの一つは、管理を容易にできることです( 前回の記事 にて、MLOpsの目的のひとつは「PJ管理・高速化」だと紹介しました)。例えば、バッチではなくリアルタイム推論が可能な推論エンドポイントを用意する場合、新しいバージョンをデプロイし直す際には、ダウンタイムが発生しない、またはなるべくダウンタイムを短くするための別の仕組み(kubernetesのDeploymentなど)が必要になってきます。一方で、バッチの場合、冪等でさえあれば、デプロイに失敗したり動作がおかしくても、動作確認済みのバッチを再実行するだけで対処することができます。 バッチパターンはコスト削減も期待できます。常時稼働する推論エンドポイントに比べると、バッチパターンの実装は処理にかかった時間単位の課金で済むからです(サーバーレス)。 また、今回の実装においては、職掌別の責務に応じて運用を切分けできるメリットもあります。具体的には、推論データの更新を担う機械学習パイプラインの運用は機械学習エンジニアが担当し、QuickSightのダッシュボードの運用はBIエンジニアが担当するという棲分けができています。BIエンジニアは常にダッシュボードを管理しているので、推論データに異常があった際はすぐに気づくことができますが、大元の機械学習パイプラインの修正が難しかったりします。しかし、棲分けができているということは、例えば当日の更新処理が失敗していても、BIエンジニア自身が過去の推論結果を参照させることで暫定対応をすることができたり(機械学習エンジニアが機械学習パイプラインの修正をするまでの時間を稼ぐことができる)、ダッシュボード自体の公開を控えたりといった対応が可能になっています。 いかがでしたでしょうか。この記事では、SageMaker Pipelinesを用いた学習&推論システムのバッチパターンを紹介してきました。しかし、上述はあくまで定期実行部分のお話にすぎず、MLOpsとしてはまだまだ説明することがあります。次回の連載では、このパイプラインの定期実行の管理を含め、メタデータ管理(実験管理)についてご紹介していきたいと思います。引続きご覧いただける際は「 SageMakerExperimentsを用いた実験管理 (3/4) 」よりご覧ください。また、最新記事やその他情報発信については、本ページ最下部のTech Blogのツイッターをフォローいただけると嬉しいです。 Reference Shibui, Y., Byeon, S., Seo, J., & Jin, D. (2020). ml-system-design-pattern[GitHub Pages]. Retrieved from https://mercari.github.io/ml-system-design-pattern/