{"id":402018,"date":"2024-06-29T16:14:14","date_gmt":"2024-06-29T16:14:14","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=402018"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=402018","title":{"rendered":"<span>Lightbend Cloudflow. \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u043e\u0432 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u043e\u0432 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 (\u043e\u0442 \u0430\u043d\u0433\u043b. Streaming Data Pipelines) \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 Lightbend Cloudflow:<\/p>\n<ul>\n<li>\n<p>\u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u0439 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431\u0440\u0430\u0442\u0438\u043c\u0441\u044f \u043a \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 demo-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0435\u0433\u043e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Scala.<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0442\u0435\u043a:<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p><a href=\"https:\/\/cloudflow.io\"><u>Cloudflow<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/akka.io\/\"><u>Akka<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/flink.apache.org\/\"><u>Apache Flink<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/spark.apache.org\/\"><u>Apache Spark<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/kafka.apache.org\/\"><u>Kafka<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/scala-lang.org\/\"><u>Scala<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.scala-sbt.org\/\"><u>Sbt<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/avro.apache.org\/\"><u>Apache Avro<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/lightbend\/config\"><u>Hocon<\/u><\/a><\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<h2>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Cloudflow?<\/h2>\n<p>Cloudflow \u2013\u00a0 \u044d\u0442\u043e open-source \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043e\u0442 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438<a href=\"https:\/\/www.lightbend.com\/\"> <u>Lightbend<\/u><\/a>, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0438\u0439 \u0432 \u0441\u0435\u0431\u0435 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0438 \u043d\u0430\u0431\u043e\u0440 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439<a href=\"https:\/\/kubernetes.io\/\"> <u>Kubernetes<\/u><\/a>.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u2013\u00a0 \u044d\u0442\u043e software development kit, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u041d\u0430\u043c \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c \u0434\u0432\u0438\u0436\u043a\u0430\u043c \u0434\u043b\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a: Akka, Flink \u0438 Spark, \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u2013\u00a0 Kafka.<\/p>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u2013\u00a0 \u0432\u043e\u043b\u0448\u0435\u0431\u043d\u0430\u044f \u043f\u0430\u043b\u043e\u0447\u043a\u0430 \u0434\u043b\u044f \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Kubernetes. <em>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e \u043d\u0435\u043c \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u0448\u0438\u0445 \u043a\u043e\u043b\u043b\u0435\u0433 \u0438\u0437 Ops \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435.<\/em><\/p>\n<h3>\u0417\u0430\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0444\u0438\u0442<\/h3>\n<blockquote>\n<p><strong>Disclaimer. <\/strong>\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u0430\u044f \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u043b\u044c\u043d\u044b\u043c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u043e\u043c \u0430\u0432\u0442\u043e\u0440\u0430 \u0441 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u0430\u0439\u0442\u0430 Lightbend Cloudflow.<\/p>\n<\/blockquote>\n<p>\u0417\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435, \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0443 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0441 <em>\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043d\u0435\u0434\u0435\u043b\u044c<\/em> \u0434\u043e <em>\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0447\u0430\u0441\u043e\u0432<\/em>. \u0418 \u0432\u043e\u0442 \u0437\u0430 \u0441\u0447\u0435\u0442 \u0447\u0435\u0433\u043e:<\/p>\n<ul>\n<li>\n<p><strong>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430.<\/strong> \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0435 \u0438 \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u0431\u043e\u0440\u043a\u0430<\/strong>. \u0411\u043e\u0433\u0430\u0442\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0441\u0440\u0435\u0434\u0441\u0442\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043e\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e;<\/p>\n<\/li>\n<li>\n<p><strong>\u0420\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435<\/strong>. \u041d\u0430\u0431\u043e\u0440 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 Kubernetes \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0430\u044e\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/p>\n<\/li>\n<\/ul>\n<h3>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f<\/h3>\n<h4>Schema-first \u043f\u043e\u0434\u0445\u043e\u0434  <\/h4>\n<p>\u0414\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f pipeline\u2019\u043e\u0432 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d \u043f\u043e\u0434\u0445\u043e\u0434, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u0441\u0445\u0435\u043c\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0432 \u0441\u0445\u0435\u043c\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Apache Avro \u0438\u043b\u0438 <a href=\"https:\/\/developers.google.com\/protocol-buffers\/\"><u>Google Protobuf<\/u><\/a>. \u041e\u0431\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f Kafka, \u0430 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 Avro-\u0441\u0445\u0435\u043c \u0432 Scala-\u043a\u043b\u0430\u0441\u0441\u044b \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0438\u043c\u0435\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0435 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0441\u0431\u043e\u0440\u043a\u0438. \u0427\u0442\u043e \u043d\u0435\u043c\u0430\u043b\u043e\u0432\u0430\u0436\u043d\u043e, Avro-\u0441\u0445\u0435\u043c\u044b \u0438\u043c\u0435\u044e\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438.<\/p>\n<blockquote>\n<p><strong>Attention!<\/strong> \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Google Protobuf \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u2013\u00a0 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.  <\/p>\n<\/blockquote>\n<h4>Streamlet<\/h4>\n<p>Streamlet -\u2013 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 Cloudflow. \u0412 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043d\u0438\u0436\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439, \u043a streamlet\u2019\u0443 \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043a \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0443.<\/p>\n<p><strong>\u0421\u0442\u0440\u043e\u0433\u043e \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432\u0445\u043e\u0434\u044b \u0438 \u0432\u044b\u0445\u043e\u0434\u044b<\/strong><\/p>\n<p>Streamlet\u2019\u044b \u0438\u043c\u0435\u044e\u0442 inlet\u2019\u044b \u0438 outlet\u2019\u044b, \u0438\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u2013\u00a0 \u0432\u0445\u043e\u0434\u044b \u0438 \u0432\u044b\u0445\u043e\u0434\u044b. \u0412 \u043a\u043e\u0434\u0435 \u043e\u043d\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 Avro-\u0441\u0445\u0435\u043c\u043e\u0439.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/867\/893\/8a2\/8678938a2941eb0df86e11638cd42d8e.jpg\" alt=\"\" title=\"\" width=\"1186\" height=\"417\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/867\/893\/8a2\/8678938a2941eb0df86e11638cd42d8e.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0421\u0442\u0440\u043e\u0433\u0430\u044f \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u044f \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f streamlet\u2019\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 pipeline. \u0427\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c &#8212; \u043f\u0440\u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"#verifyBlueprint\"><u>Blueprint<\/u><\/a>.<\/p>\n<p><strong>\u0424\u043e\u0440\u043c\u044b \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/strong><\/p>\n<p>\u0424\u043e\u0440\u043c\u0430 streamlet\u2019\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0435\u0433\u043e \u0432\u0445\u043e\u0434\u043e\u0432 \u0438 \u0432\u044b\u0445\u043e\u0434\u043e\u0432, \u0430 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u044f \u043c\u0435\u0436\u0434\u0443 streamlet\u2019\u0430\u043c\u0438 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Kafka.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/608\/7d1\/e38\/6087d1e385e3fc459f1633c2d4f58ddd.jpg\" width=\"1184\" height=\"417\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/608\/7d1\/e38\/6087d1e385e3fc459f1633c2d4f58ddd.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0418\u0437 \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442, \u0447\u0442\u043e producer\u2019\u044b \u0438 consumer\u2019\u044b \u0432 streamlet\u2019\u0430\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c\u0438 \u043d\u0430\u043c inlet\u2019\u0430\u043c\u0438 \u0438 outlet\u2019\u0430\u043c\u0438. \u0412 \u043a\u043e\u0434\u0435 \u0443 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0442\u0430\u043a\u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u043a\u0430\u043a: <em>name<\/em>, <em>uniqueGroupId<\/em>, <em>partitioner<\/em>, <em>errorHandler<\/em>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/6fb\/5f2\/3f3\/6fb5f23f3f06bdd5022b3c78dc1d72f1.jpg\" width=\"1186\" height=\"417\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6fb\/5f2\/3f3\/6fb5f23f3f06bdd5022b3c78dc1d72f1.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p><strong>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b<\/strong><\/p>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 streamlet\u2019\u0430, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u0438\u0437 \u0442\u0440\u0435\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0445 \u0441\u0440\u0435\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0443 Cloudflow \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438: <code>AkkaStreamlet<\/code>, <code>FlinkStreamlet<\/code> \u0438 <code>SparkStreamlet<\/code> \u0441\u043e \u0432\u0441\u0435\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u043e\u0431\u0432\u044f\u0437\u043a\u043e\u0439. \u0414\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438\u0437\u0431\u0435\u0436\u0430\u0432 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 <abbr title=\"\u0411\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442 (\u0441\u043e\u043a\u0440. \u043e\u0442 \u0430\u043d\u0433\u043b. boilerplate code) - \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434.\">\u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0430<\/abbr>.<\/p>\n<pre><code class=\"scala\">\/*The Synthetic Streamlet Example*\/  class MyFlinkProcessor extends FlinkStreamlet { val in    = AvroInlet[Data](\"in\")   val out   = AvroOutlet[Simple](\"out\", _.name)   val shape = StreamletShape(in, out)    override def createLogic() = new FlinkStreamletLogic {   override def executeStreamingQueries = {     \/\/ do logic     }   } }<\/code><\/pre>\n<h4>Blueprint<\/h4>\n<p>Blueprint &#8212; \u044d\u0442\u043e \u0447\u0435\u0440\u0442\u0435\u0436, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 <abbr title=\"Human-Optimized Config Object Notation\">HOCON<\/abbr>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c \u0446\u0435\u043b\u0435\u0432\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f streamlet\u2019\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 pipeline. \u0413\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/bbf\/9d3\/b04\/bbf9d3b042f1672a02f82a4987794c49.jpg\" width=\"1330\" height=\"630\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bbf\/9d3\/b04\/bbf9d3b042f1672a02f82a4987794c49.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0410 \u0442\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430 blueprint.conf:<\/p>\n<pre><code class=\"scala\">blueprint {   streamlets {     transiever = dope.nathan.movement.data.transceiver.Transceiver     converter = dope.nathan.movement.data.converter.Converter     collector = dope.nathan.movement.data.collector.Collector   }    topics {     transiever_sensor-data-got {       producers = [transiever.sensor-data-got-out]       consumers = [converter.sensor-data-got-in]     }      converter_track-made {       producers = [converter.track-made-out]       consumers = [collector.track-made-in]     }   } }<\/code><\/pre>\n<p><a class=\"anchor\" name=\"verifyBlueprint\" id=\"verifyBlueprint\"><\/a><\/p>\n<p>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e sbt-\u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>verifyBlueprint<\/code><em> <\/em>\u043f\u043b\u0430\u0433\u0438\u043d\u0430 Cloudflow<em> <\/em>\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f streamlet&#8217;\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 pipeline. \u0414\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 &#8212; \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0437\u0430\u044f\u0432\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u0447\u0435\u0440\u0442\u0435\u0436\u0443. \u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u0442\u0435\u0441\u0442\u0430\u043c.<\/p>\n<blockquote>\n<p><strong>Note.<\/strong> \u041a\u043e\u043c\u0430\u043d\u0434\u0430 <code>verifyBlueprint<\/code><em> <\/em>\u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043f\u043e \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044e, \u0442\u0430\u043a \u0438 \u0432 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>runLocal<\/code>(\u0441\u043c. \u0440\u0430\u0437\u0434\u0435\u043b <a href=\"#sandbox\"><u>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/u><\/a>).<\/p>\n<\/blockquote>\n<h2>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430<\/h2>\n<h3>\u0410\u043d\u0430\u043b\u0438\u0437<\/h3>\n<h4>\u0411\u0438\u0437\u043d\u0435\u0441 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435  <\/h4>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c, \u0447\u0442\u043e \u043a \u043d\u0430\u043c \u043e\u0431\u0440\u0430\u0442\u0438\u043b\u0441\u044f<a href=\"https:\/\/pleistocenepark.ru\/ru\/\"> <u>\u041f\u043b\u0435\u0439\u0441\u0442\u043e\u0446\u0435\u043d\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043a<\/u><\/a>. \u0423\u0447\u0435\u043d\u044b\u0435 \u0432 \u0431\u043e\u0440\u044c\u0431\u0435 \u0441 \u0442\u0430\u044f\u043d\u0438\u0435\u043c \u0432\u0435\u0447\u043d\u043e\u0439 \u043c\u0435\u0440\u0437\u043b\u043e\u0442\u044b \u0437\u0430\u0434\u0443\u043c\u0430\u043b\u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043b\u0435\u0434\u043d\u0438\u043a\u043e\u0432\u043e\u0433\u043e \u043f\u0435\u0440\u0438\u043e\u0434\u0430 \u043d\u0430 \u0442\u0435\u0440\u0440\u0438\u0442\u043e\u0440\u0438\u0438 \u0440\u0435\u0441\u043f\u0443\u0431\u043b\u0438\u043a\u0438 \u0421\u0430\u0445\u0430 (\u042f\u043a\u0443\u0442\u0438\u044f) \u0432 \u0420\u043e\u0441\u0441\u0438\u0438. \u041e\u043d\u0438 \u0437\u0430\u0432\u0435\u0437\u043b\u0438 \u0431\u0438\u0437\u043e\u043d\u043e\u0432 \u0438\u0437 \u0414\u0430\u043d\u0438\u0438 \u043d\u0430 \u0442\u0435\u0440\u0440\u0438\u0442\u043e\u0440\u0438\u044e \u043f\u0430\u0440\u043a\u0430, \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0434\u043b\u044f \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u0441\u043b\u0435\u0434\u0438\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u043f\u043e\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c GPS-\u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432.  <\/p>\n<h4>\u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435<\/h4>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c MVP \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043d\u0430 \u0432\u0445\u043e\u0434 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 GPS-\u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432, \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c.   <\/p>\n<blockquote>\n<p><strong>Note.<\/strong> \u0421 \u043f\u043e\u043b\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c demo-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/nathandope\/movement-data-pipeline\/tree\/habr\"><u>GitHub<\/u><\/a>.<\/p>\n<\/blockquote>\n<h4>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430<\/h4>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/e0d\/862\/1b8\/e0d8621b8599b275ddf7a6061fd0a01b.jpg\" width=\"1099\" height=\"751\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e0d\/862\/1b8\/e0d8621b8599b275ddf7a6061fd0a01b.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<h3>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n<h4>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/h4>\n<p><strong>build.properties<\/strong><\/p>\n<pre><code>sbt.version = 1.5.4<\/code><\/pre>\n<p><strong>cloudflow-plugins.sbt<\/strong><\/p>\n<p>\u0424\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u043e\u043c \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 pipeline \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Cloudflow \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0431\u043e\u0440 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 Sbt, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0443\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438. \u0411\u0430\u0437\u043e\u0432\u044b\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u201csbt-cloudflow\u201d. \u0422\u0430\u043a \u0447\u0442\u043e \u0444\u0430\u0439\u043b <strong>cloudflow-plugins.sbt<\/strong> \u043d\u0430\u0440\u044f\u0434\u0443 \u0441 <strong>build.properties<\/strong> \u2013\u00a0 \u044d\u0442\u043e \u043f\u0435\u0440\u0432\u043e\u0435, \u043e \u0447\u0435\u043c \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0437\u0430\u0431\u043e\u0442\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 Cloudflow.  <\/p>\n<pre><code class=\"scala\">addSbtPlugin(\"com.lightbend.cloudflow\" % \"sbt-cloudflow\" % \"2.1.0\")<\/code><\/pre>\n<p><strong>build.sbt<\/strong><\/p>\n<p>\u0424\u0430\u0439\u043b, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u044c\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439 \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 IDE:  <\/p>\n<pre><code class=\"scala\">\/\/ (1) - Enabling The Cloudflow Plugins  lazy val root = (project in file(\".\"))   .settings(     name := ProjectName,     version := ProjectVersion,     publish \/ skip := true,     CustomSettings.commons   )   .withId(ProjectName)   .aggregate(     pipeline,     datamodel,     transceiver,     converter,     collector   )  lazy val pipeline = appModule(postfix)   .enablePlugins(CloudflowApplicationPlugin)              \/\/ (1)   .settings(     blueprint := Some(\"blueprint.conf\"),     runLocalConfigFile := Some(s\"$ProjectResources\/sandbox\/local.conf\"),     runLocalLog4jConfigFile := Some(s\"$ProjectResources\/sandbox\/log4j.properties\")   )   .dependsOn(datamodel, transceiver, converter, collector)  \/* The auxiliary things are here *\/ lazy val common = appModule(\"common\")   .settings(     libraryDependencies += Logback,     Test \/ parallelExecution := false   )  \/* The Avro-schemas are here *\/ lazy val datamodel = appModule(\"datamodel\")   .enablePlugins(CloudflowLibraryPlugin)                  \/\/ (1)  \/* The Akka Streamlet Module *\/ lazy val transceiver = appModule(\"transceiver\")   .enablePlugins(CloudflowAkkaPlugin)                     \/\/ (1)   .settings(     libraryDependencies ++= commons,     Test \/ parallelExecution := false   )   .dependsOn(datamodel)  \/* The Flink Streamlet Module *\/ lazy val converter = appModule(\"converter\")   .enablePlugins(CloudflowFlinkPlugin)                    \/\/ (1)   .settings(     libraryDependencies ++= commons ++ flinkTestKit,     Test \/ parallelExecution := false   )   .dependsOn(datamodel, common)  \/* The Spark Streamlet Module *\/ lazy val collector = appModule(\"collector\")   .enablePlugins(CloudflowSparkPlugin)                   \/\/ (1)   .settings(     libraryDependencies ++= (commons :+ AkkaSlf4j),     Test \/ parallelExecution := false   )   .dependsOn(datamodel, common)  def appModule(moduleID: String): Project = {   Project(id = moduleID, base = file(moduleID))     .settings(       name := moduleID,       idePackagePrefix := Some(s\"$Company.$namePart1.$namePart2.$moduleID\"),       CustomSettings.commons     )     .withId(moduleID) } <\/code><\/pre>\n<p><strong>blueprint.conf<\/strong> <\/p>\n<p>\u0413\u043e\u0432\u043e\u0440\u044f, \u0447\u0442\u043e blueprint &#8212; \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0435\u0440\u0442\u0435\u0436, \u043c\u044b \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u043b\u0438. \u041f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u0432 \u043d\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 Kafka:<\/p>\n<pre><code class=\"scala\">common-kafka-config = {   producer-config {     linger.ms = 5     batch.size = 131072     max.request.size = 3145728   }   consumer-config {     max.partition.fetch.bytes = 3145728     fetch.max.bytes = 3145728   } }  blueprint {   streamlets {     transiever = dope.nathan.movement.data.transceiver.Transceiver     converter = dope.nathan.movement.data.converter.Converter     collector = dope.nathan.movement.data.collector.Collector   }    topics {     transiever_sensor-data-got = ${common-kafka-config}{       producers = [transiever.sensor-data-got-out]       consumers = [converter.sensor-data-got-in]     }      converter_track-made = ${common-kafka-config}{       producers = [converter.track-made-out]       consumers = [collector.track-made-in]     }   } } <\/code><\/pre>\n<p><strong>local.conf<\/strong><\/p>\n<p>\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b pipeline \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c <em>.conf<\/em>. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 pipeline \u0432 <abbr title=\"sandbox\">\u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0435<\/abbr>:<\/p>\n<pre><code class=\"scala\">cloudflow.streamlets { converter.config-parameters {         auto-watermark-interval = 200ms         track-window-duration = 60s         max-time-delay-of-track-points = 5s         track-window-release-timeout = 30s     } }<\/code><\/pre>\n<p>\u041d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u0432 \u043d\u0430\u0448\u0435\u043c pipeline \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e streamlet\u2019\u0430, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 &#8212; \u0431\u0435\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432.<\/p>\n<p><strong>log4j.properties<\/strong><\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b pipeline \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u044b, \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u043e\u0447\u0435\u0447\u043d\u043e \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043e \u043d\u0430 debug-\u0443\u0440\u043e\u0432\u0435\u043d\u044c.<\/p>\n<pre><code class=\"yaml\"># Root logger option log4j.rootLogger=INFO, stdout  # Direct log messages to stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout log4j.appender.stdout.layout.ConversionPattern=[%p] [%d{HH:mm:ss.SSS}] %c{2.}:%L %m%n  log4j.logger.cloudflow=INFO log4j.logger.dope.nathan=DEBUG log4j.logger.localRunner=DEBUG  # Noisy Exclusions log4j.logger.org.apache.spark=ERROR log4j.logger.org.spark_project=ERROR log4j.logger.kafka=ERROR log4j.logger.org.apache.flink=ERROR <\/code><\/pre>\n<p><strong>*.avsc<\/strong><\/p>\n<p>\u0424\u0430\u0439\u043b\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 Avro-\u0441\u0445\u0435\u043c\u044b \u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043c\u043e\u0434\u0443\u043b\u0435 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c &#171;datamodel&#187;. \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u0430\u043a \u0432 \u0432\u0438\u0434\u0435 Avro-\u0441\u0445\u0435\u043c, \u0442\u0430\u043a \u0438 \u0432 \u0432\u0438\u0434\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 Scala-\u043a\u043b\u0430\u0441\u0441\u043e\u0432 (\u0432 \u043f\u0430\u043f\u043a\u0435 &#171;target&#187;). \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043f\u043b\u0430\u0433\u0438\u043d\u0443 CloudflowLibraryPlugin Avro-\u0441\u0445\u0435\u043c\u044b \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u044e\u0442\u0441\u044f Sbt \u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 Scala-\u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.  <\/p>\n<blockquote>\n<p><strong>Note.<\/strong> \u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0430\u044f \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 Scala-\u043a\u043b\u0430\u0441\u0441\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <em>datamodel\/target\/scala2.12\/scala_avro<\/em>), \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u0430 \u0432 IDE \u043a\u0430\u043a Generated Sources Root.<\/p>\n<\/blockquote>\n<p> \u041f\u0440\u0438\u043c\u0435\u0440 Avro-\u0441\u0445\u0435\u043c\u044b:<\/p>\n<pre><code class=\"json\">{     \"namespace\": \"dope.nathan.movement.data.model\",     \"type\": \"record\",     \"name\": \"Track\",     \"fields\":[             { \"name\": \"id\",     \"type\": \"string\" },             { \"name\": \"carrier\", \"type\": \"string\"},             { \"name\": \"metrics\",              \"type\": \"dope.nathan.movement.data.model.track.Metrics\"             }     ] }<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043b\u0430\u0441\u0441\u0430, \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 Avro-\u0441\u0445\u0435\u043c\u044b:<\/p>\n<pre><code class=\"scala\">import dope.nathan.movement.data.model.track.Metrics  case class Track(var id: String, var carrier: String, var metrics: Metrics)      extends org.apache.avro.specific.SpecificRecordBase { \/\/ the SpecificRecordBase implementation } object Track { \/\/ the companion object logic }<\/code><\/pre>\n<h4>Streamlets<\/h4>\n<p><strong>Transceiver (Akka Server) Streamlet<\/strong><\/p>\n<pre><code class=\"scala\">\/* * (1) - the String parameter is a part of the producer name * (2) - the logic is here * *\/ trait TransceiverOpenings {   val sensorDataGotOut: AvroOutlet[SensorDataGot] =     AvroOutlet(\"sensor-data-got-out\")                 \/\/ (1) }  trait TransceiverBase extends AkkaServerStreamlet with TransceiverOpenings {   import json.SensorDataGotJsonProtocol.SensorDataGotJsonFormat    final override def shape: StreamletShape =     StreamletShape.withOutlets(sensorDataGotOut)    final override def createLogic: AkkaStreamletLogic =     HttpServerLogic.default(this, sensorDataGotOut)    \/\/ (2) }  object Transceiver extends TransceiverBase<\/code><\/pre>\n<p><strong>Transceiver<\/strong> \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e http \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0438\u0445 <strong>Converter\u2019\u0443<\/strong> \u0432 \u0432\u0438\u0434\u0435 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f <code>SensorDataGot.scala<\/code>. \u041f\u0440\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 http-\u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c POST \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443<a href=\"http:\/\/localhost:3000\"> <u>http:\/\/localhost:3000<\/u><\/a>.   <\/p>\n<p>\u0422\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:  <\/p>\n<pre><code class=\"json\">{     \"sensor\": {         \"id\": \"ID-1\",         \"carrier\": \"Bob\",         \"metrics\": {             \"timestamp\": 1630701100,             \"geoposition\": {                 \"coordinates\": {                     \"lat\": 1.0,                     \"lon\": 1.0                 },                 \"direction\": \"N\"             }         }     },     \"eventTime\": 1630706100 }<\/code><\/pre>\n<p><strong>Converter (Flink) Streamlet<\/strong><\/p>\n<pre><code class=\"scala\">\/* * (1) - the parameter is part of the consumer\\producer name * (2) - the logic is here **\/ trait ConverterOpenings {   @transient val sensorDataGotIn: AvroInlet[SensorDataGot] =     AvroInlet(\"sensor-data-got-in\")             \/\/ (1)    @transient val trackMadeOut: AvroOutlet[TrackMade] =     AvroOutlet(\"track-made-out\")                \/\/ (1) }  trait ConverterBase extends FlinkStreamlet with ConverterOpenings {   override def shape(): StreamletShape =     StreamletShape       .withInlets(sensorDataGotIn)       .withOutlets(trackMadeOut)    override def configParameters: Vector[ConfigParameter] =     FlinkConfig.allParameters    override protected def createLogic(): FlinkStreamletLogic =     new ConverterLogic(FlinkConfig.apply)        \/\/ (2) }  object Converter extends ConverterBase<\/code><\/pre>\n<p><strong>Converter<\/strong> \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <code>SensorDataGot.scala<\/code>, \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0435\u0435 \u043e\u0442 <strong>Transceiver\u2019\u0430<\/strong>, \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0432\u044b\u0448\u0435. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0438\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0432 <strong>Converter\u2019\u0435<\/strong> \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0442\u0440\u0435\u043a \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <code>TrackMade.scala<\/code>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d <strong>Collector<\/strong>. (\u0441\u043c.<a href=\"https:\/\/github.com\/nathandope\/movement-data-pipeline\/blob\/habr\/converter\/src\/main\/scala\/logic\/ConverterLogic.scala\"> <u>ConverterLogic.scala<\/u><\/a>)<\/p>\n<p><strong>Collector (Spark) Streamlet<\/strong><\/p>\n<pre><code class=\"scala\">\/* * (1) - the parameter is a part of the consumer name * (2) - the logic is here * *\/  trait CollectorOpenings {   val trackMadeIn: AvroInlet[TrackMade] =     AvroInlet(\"track-made-in\")                \/\/ (1) }  trait CollectorBase extends SparkStreamlet with CollectorOpenings {   override def shape(): StreamletShape =     StreamletShape.withInlets(trackMadeIn)      override protected def createLogic(): SparkStreamletLogic =     new CollectorLogic                        \/\/ (2) }  object Collector extends CollectorBase {   \/\/ to run in the sandbox   System.setProperty(   \"hadoop.home.dir\",     \"C:\\\\Spark\\\\spark-2.4.5-bin-hadoop2.7\"   ) }<\/code><\/pre>\n<p><strong>Collector<\/strong> \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <code>TrackMade.scala<\/code> \u043e\u0442 <strong>Converter\u2019\u0430<\/strong>, \u0434\u043e\u0441\u0442\u0430\u0435\u0442 \u0438\u0437 \u043d\u0435\u0433\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0442\u0440\u0435\u043a \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043b\u043e\u0433. (\u0441\u043c.<a href=\"https:\/\/github.com\/nathandope\/movement-data-pipeline\/blob\/habr\/collector\/src\/main\/scala\/logic\/CollectorLogic.scala\"> <u>CollectorLogic.scala<\/u><\/a>)<\/p>\n<p><a class=\"anchor\" name=\"sandbox\" id=\"sandbox\"><\/a><\/p>\n<h3>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n<p>\u041f\u0435\u0440\u0435\u0434 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c pipeline \u043f\u043e\u0437\u0430\u0431\u043e\u0442\u044c\u0442\u0435\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u0443 \u0432\u0430\u0441 \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0435 \u0431\u044b\u043b \u0437\u0430\u043f\u0443\u0449\u0435\u043d<a href=\"https:\/\/www.docker.com\/\"> <u>Docker<\/u><\/a>. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c Sbt \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <em>runLocal<\/em>.  <\/p>\n<blockquote>\n<p><strong>Note.<\/strong> \u0414\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark Streamlet\u2019\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043d\u0443\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0443\u0442\u044c \u043a \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 Hadoop (\u0441\u043c.<a href=\"https:\/\/github.com\/nathandope\/movement-data-pipeline\/blob\/habr\/collector\/src\/main\/scala\/Streamlet.scala\"> <u>objetc Collector<\/u><\/a>). \u0410\u0440\u0445\u0438\u0432\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 Hadoop \u0438\u0449\u0438\u0442\u0435 <a href=\"https:\/\/archive.apache.org\/dist\/spark\/spark-2.4.5\/\"><u>\u0442\u0443\u0442<\/u><\/a>. \u0414\u043b\u044f Windows \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e hadoop\/bin \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0444\u0430\u0439\u043b <a href=\"https:\/\/drive.google.com\/file\/d\/1q9oEGvQriSSmKPCBVgSj7tAds46DVef1\/view?usp=sharing\"><u>winutils.exe<\/u><\/a> (\u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u043f\u043e\u0441\u043b\u0435 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0430\u0440\u0445\u0438\u0432\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c <a href=\"https:\/\/docs.google.com\/document\/d\/1BOYZeu0IZSDfiZJYJFGsSdc0VQumTJVExnkc7DbWePA\/edit?usp=sharing\"><u>\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d\u0443\u044e \u0441\u0443\u043c\u043c\u0443<\/u><\/a> \u043f\u043e SHA-256).  <\/p>\n<\/blockquote>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u043b\u043e\u0433\u0430\u0445 streamlet\u2019\u043e\u0432, \u0441\u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e POST \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a<a href=\"http:\/\/localhost:3000\"> <u>http:\/\/localhost:3000<\/u><\/a> \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a pipeline \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f. \u0414\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c<a href=\"https:\/\/github.com\/nathandope\/movement-data-pipeline\/tree\/habr\/transceiver\/src\/test\/resources\"> <u>\u0442\u0443\u0442<\/u><\/a>.  <\/p>\n<h2>\u0412\u043c\u0435\u0441\u0442\u043e \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/h2>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a Lightbend Cloudflow \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043d\u0430 \u0435\u0433\u043e \u0431\u0430\u0437\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0443\u044e \u0438\u0437 \u0442\u0440\u0435\u0445 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u0441\u043b\u0430\u0431\u043e\u0439 \u0441\u0432\u044f\u0437\u043d\u043e\u0441\u0442\u044c\u044e \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b;<\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u0441\u043e\u043a\u0438\u043c \u0443\u0440\u043e\u0432\u043d\u0435\u043c \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439;<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u043c\u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430\u043c\u0438 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c\u0438 API \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c \u043c\u0435\u0442\u0440\u0438\u043a;<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f near-real time \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0430\u0436\u043d\u043e: \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043d\u0430\u0431\u043e\u0440\u0443 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 Kubernetes \u043e\u0442 Cloudflow \u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u201c\u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f\u201d \u043a\u0430\u043a \u0435\u0434\u0438\u043d\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430.<\/p>\n<p>\u0420\u0435\u0437\u044e\u043c\u0438\u0440\u0443\u044f:\u00a0 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u0445 Lightbend \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e Fast Data \u0441\u0438\u0441\u0442\u0435\u043c. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434 \u044d\u0442\u0438\u043c \u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043c \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0432<a href=\"https:\/\/github.com\/lightbend\/cloudflow#the-drivers-behind-cloudflow\"><u> Readme.md<\/u><\/a> Cloudflow.  <\/p>\n<hr\/>\n<p>\u0410 \u0442\u0435\u043f\u0435\u0440\u044c, \u0434\u0430\u0432\u0430\u0439\u0442\u0435, \u043f\u043e\u0444\u0430\u043d\u0442\u0430\u0437\u0438\u0440\u0443\u0435\u043c. \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441:<\/p>\n<ul>\n<li>\n<p>\u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 API (\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0431\u0435\u0437 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438);<\/p>\n<\/li>\n<li>\n<p>\u0432\u0441\u0435\u0433\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0443\u043a \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0418\u0422-\u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0434\u0435\u0441\u044f\u0442\u043e\u043a-\u0434\u0440\u0443\u0433\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043f\u0440\u0435\u0441\u0442\u0430\u043d\u043d\u043e \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u044f\u0442 \u043a\u043e\u0434;<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0438, \u0431\u0435\u0437 \u043a\u043e\u043d\u0446\u0430 \u0442\u0440\u0435\u0431\u0443\u044e\u0449\u0438\u0435 \u0440\u0435\u0434\u0435\u043f\u043b\u043e\u044f \u0432\u043e \u0438\u043c\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043f\u0440\u0438 \u0442\u0430\u043a\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 Cloudflow \u2013 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u0435\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<p>\u041d\u043e \u043e\u0447\u0435\u043d\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u0443\u0437\u043d\u0430\u0442\u044c, \u043d\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043b\u0438 \u0443 \u0432\u0430\u0441 \u0434\u043e\u0432\u043e\u0434\u044b \u043f\u0440\u043e\u0442\u0438\u0432? \u0418\u043b\u0438, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0432\u044b \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0435\u0448\u0430\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439?<\/p>\n<p>\u041f\u0438\u0448\u0438\u0442\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, &#8212; \u043c\u044b \u043e\u0442\u043a\u0440\u044b\u0442\u044b \u043a \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u044e. \u0421\u043f\u0430\u0441\u0438\u0431\u043e!<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/580076\/\"> https:\/\/habr.com\/ru\/articles\/580076\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u043e\u0432 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 (\u043e\u0442 \u0430\u043d\u0433\u043b. Streaming Data Pipelines) \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 Lightbend Cloudflow:<\/p>\n<ul>\n<li>\n<p>\u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u0439 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431\u0440\u0430\u0442\u0438\u043c\u0441\u044f \u043a \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 demo-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0435\u0433\u043e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Scala.<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0442\u0435\u043a:<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p><a href=\"https:\/\/cloudflow.io\"><u>Cloudflow<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/akka.io\/\"><u>Akka<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/flink.apache.org\/\"><u>Apache Flink<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/spark.apache.org\/\"><u>Apache Spark<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/kafka.apache.org\/\"><u>Kafka<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/scala-lang.org\/\"><u>Scala<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.scala-sbt.org\/\"><u>Sbt<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/avro.apache.org\/\"><u>Apache Avro<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/lightbend\/config\"><u>Hocon<\/u><\/a><\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<h2>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Cloudflow?<\/h2>\n<p>Cloudflow \u2013\u00a0 \u044d\u0442\u043e open-source \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043e\u0442 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438<a href=\"https:\/\/www.lightbend.com\/\"> <u>Lightbend<\/u><\/a>, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0438\u0439 \u0432 \u0441\u0435\u0431\u0435 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0438 \u043d\u0430\u0431\u043e\u0440 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439<a href=\"https:\/\/kubernetes.io\/\"> <u>Kubernetes<\/u><\/a>.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u2013\u00a0 \u044d\u0442\u043e software development kit, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u041d\u0430\u043c \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c \u0434\u0432\u0438\u0436\u043a\u0430\u043c \u0434\u043b\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a: Akka, Flink \u0438 Spark, \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u2013\u00a0 Kafka.<\/p>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u2013\u00a0 \u0432\u043e\u043b\u0448\u0435\u0431\u043d\u0430\u044f \u043f\u0430\u043b\u043e\u0447\u043a\u0430 \u0434\u043b\u044f \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Kubernetes. <em>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e \u043d\u0435\u043c \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u0448\u0438\u0445 \u043a\u043e\u043b\u043b\u0435\u0433 \u0438\u0437 Ops \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435.<\/em><\/p>\n<h3>\u0417\u0430\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0444\u0438\u0442<\/h3>\n<blockquote>\n<p><strong>Disclaimer. <\/strong>\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u0430\u044f \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u043b\u044c\u043d\u044b\u043c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u043e\u043c \u0430\u0432\u0442\u043e\u0440\u0430 \u0441 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u0430\u0439\u0442\u0430 Lightbend Cloudflow.<\/p>\n<\/blockquote>\n<p>\u0417\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435, \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0443 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0441 <em>\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043d\u0435\u0434\u0435\u043b\u044c<\/em> \u0434\u043e <em>\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0447\u0430\u0441\u043e\u0432<\/em>. \u0418 \u0432\u043e\u0442 \u0437\u0430 \u0441\u0447\u0435\u0442 \u0447\u0435\u0433\u043e:<\/p>\n<ul>\n<li>\n<p><strong>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430.<\/strong> \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0435 \u0438 \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0430;<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u0431\u043e\u0440\u043a\u0430<\/strong>. \u0411\u043e\u0433\u0430\u0442\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0441\u0440\u0435\u0434\u0441\u0442\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043e\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e;<\/p>\n<\/li>\n<li>\n<p><strong>\u0420\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435<\/strong>. \u041d\u0430\u0431\u043e\u0440 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 Kubernetes \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0430\u044e\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/p>\n<\/li>\n<\/ul>\n<h3>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f<\/h3>\n<h4>Schema-first \u043f\u043e\u0434\u0445\u043e\u0434  <\/h4>\n<p>\u0414\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f pipeline\u2019\u043e\u0432 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d \u043f\u043e\u0434\u0445\u043e\u0434, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u0441\u0445\u0435\u043c\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0432 \u0441\u0445\u0435\u043c\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Apache Avro \u0438\u043b\u0438 <a href=\"https:\/\/developers.google.com\/protocol-buffers\/\"><u>Google Protobuf<\/u><\/a>. \u041e\u0431\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f Kafka, \u0430 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 Avro-\u0441\u0445\u0435\u043c \u0432 Scala-\u043a\u043b\u0430\u0441\u0441\u044b \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0438\u043c\u0435\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0435 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0441\u0431\u043e\u0440\u043a\u0438. \u0427\u0442\u043e \u043d\u0435\u043c\u0430\u043b\u043e\u0432\u0430\u0436\u043d\u043e, Avro-\u0441\u0445\u0435\u043c\u044b \u0438\u043c\u0435\u044e\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438.<\/p>\n<blockquote>\n<p><strong>Attention!<\/strong> \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Google Protobuf \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u2013\u00a0 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.  <\/p>\n<\/blockquote>\n<h4>Streamlet<\/h4>\n<p>Streamlet -\u2013 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 Cloudflow. \u0412 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043d\u0438\u0436\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439, \u043a streamlet\u2019\u0443 \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043a \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0443.<\/p>\n<p><strong>\u0421\u0442\u0440\u043e\u0433\u043e \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432\u0445\u043e\u0434\u044b \u0438 \u0432\u044b\u0445\u043e\u0434\u044b<\/strong><\/p>\n<p>Streamlet\u2019\u044b \u0438\u043c\u0435\u044e\u0442 inlet\u2019\u044b \u0438 outlet\u2019\u044b, \u0438\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u2013\u00a0 \u0432\u0445\u043e\u0434\u044b \u0438 \u0432\u044b\u0445\u043e\u0434\u044b. \u0412 \u043a\u043e\u0434\u0435 \u043e\u043d\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 Avro-\u0441\u0445\u0435\u043c\u043e\u0439.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0421\u0442\u0440\u043e\u0433\u0430\u044f \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u044f \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f streamlet\u2019\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 pipeline. \u0427\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c &#8212; \u043f\u0440\u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"#verifyBlueprint\"><u>Blueprint<\/u><\/a>.<\/p>\n<p><strong>\u0424\u043e\u0440\u043c\u044b \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/strong><\/p>\n<p>\u0424\u043e\u0440\u043c\u0430 streamlet\u2019\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0435\u0433\u043e \u0432\u0445\u043e\u0434\u043e\u0432 \u0438 \u0432\u044b\u0445\u043e\u0434\u043e\u0432, \u0430 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u044f \u043c\u0435\u0436\u0434\u0443 streamlet\u2019\u0430\u043c\u0438 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Kafka.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0418\u0437 \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442, \u0447\u0442\u043e producer\u2019\u044b \u0438 consumer\u2019\u044b \u0432 streamlet\u2019\u0430\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c\u0438 \u043d\u0430\u043c inlet\u2019\u0430\u043c\u0438 \u0438 outlet\u2019\u0430\u043c\u0438. \u0412 \u043a\u043e\u0434\u0435 \u0443 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0442\u0430\u043a\u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u043a\u0430\u043a: <em>name<\/em>, <em>uniqueGroupId<\/em>, <em>partitioner<\/em>, <em>errorHandler<\/em>.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p><strong>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b<\/strong><\/p>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 streamlet\u2019\u0430, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u0438\u0437 \u0442\u0440\u0435\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0445 \u0441\u0440\u0435\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0443 Cloudflow \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438: <code>AkkaStreamlet<\/code>, <code>FlinkStreamlet<\/code> \u0438 <code>SparkStreamlet<\/code> \u0441\u043e \u0432\u0441\u0435\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u043e\u0431\u0432\u044f\u0437\u043a\u043e\u0439. \u0414\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438\u0437\u0431\u0435\u0436\u0430\u0432 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 <abbr title=\"\u0411\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442 (\u0441\u043e\u043a\u0440. \u043e\u0442 \u0430\u043d\u0433\u043b. boilerplate code) - \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434.\">e) &#8212; \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434.&#187;>\u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0430<\/abbr>.<\/p>\n<pre><code class=\"scala\">\/*The Synthetic Streamlet Example*\/  class MyFlinkProcessor extends FlinkStreamlet { val in    = AvroInlet[Data](\"in\")   val out   = AvroOutlet[Simple](\"out\", _.name)   val shape = StreamletShape(in, out)    override def createLogic() = new FlinkStreamletLogic {   override def executeStreamingQueries = {     \/\/ do logic     }   } }<\/code><\/pre>\n<h4>Blueprint<\/h4>\n<p>Blueprint &#8212; \u044d\u0442\u043e \u0447\u0435\u0440\u0442\u0435\u0436, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 <abbr title=\"Human-Optimized Config Object Notation\">HOCON<\/abbr>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c \u0446\u0435\u043b\u0435\u0432\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f streamlet\u2019\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 pipeline. \u0413\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0410 \u0442\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430 blueprint.conf:<\/p>\n<pre><code class=\"scala\">blueprint {   streamlets {     transiever = dope.nathan.movement.data.transceiver.Transceiver     converter = dope.nathan.movement.data.converter.Converter     collector = dope.nathan.movement.data.collector.Collector   }    topics {     transiever_sensor-data-got {       producers = [transiever.sensor-data-got-out]       consumers = [converter.sensor-data-got-in]     }      converter_track-made {       producers = [converter.track-made-out]       consumers = [collector.track-made-in]     }   } }<\/code><\/pre>\n<p><a class=\"anchor\" name=\"verifyBlueprint\" id=\"verifyBlueprint\"><\/a><\/p>\n<p>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e sbt-\u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>verifyBlueprint<\/code><em> <\/em>\u043f\u043b\u0430\u0433\u0438\u043d\u0430 Cloudflow<em> <\/em>\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f streamlet&#8217;\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 pipeline. \u0414\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 &#8212; \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0437\u0430\u044f\u0432\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u0447\u0435\u0440\u0442\u0435\u0436\u0443. \u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u0442\u0435\u0441\u0442\u0430\u043c.<\/p>\n<blockquote>\n<p><strong>Note.<\/strong> \u041a\u043e\u043c\u0430\u043d\u0434\u0430 <code>verifyBlueprint<\/code><em> <\/em>\u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043f\u043e \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044e, \u0442\u0430\u043a \u0438 \u0432 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>runLocal<\/code>(\u0441\u043c. \u0440\u0430\u0437\u0434\u0435\u043b <a href=\"#sandbox\"><u>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/u><\/a>).<\/p>\n<\/blockquote>\n<h2>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430<\/h2>\n<h3>\u0410\u043d\u0430\u043b\u0438\u0437<\/h3>\n<h4>\u0411\u0438\u0437\u043d\u0435\u0441 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435  <\/h4>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c, \u0447\u0442\u043e \u043a \u043d\u0430\u043c \u043e\u0431\u0440\u0430\u0442\u0438\u043b\u0441\u044f<a href=\"https:\/\/pleistocenepark.ru\/ru\/\"> <u>\u041f\u043b\u0435\u0439\u0441\u0442\u043e\u0446\u0435\u043d\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043a<\/u><\/a>. \u0423\u0447\u0435\u043d\u044b\u0435 \u0432 \u0431\u043e\u0440\u044c\u0431\u0435 \u0441 \u0442\u0430\u044f\u043d\u0438\u0435\u043c \u0432\u0435\u0447\u043d\u043e\u0439 \u043c\u0435\u0440\u0437\u043b\u043e\u0442\u044b \u0437\u0430\u0434\u0443\u043c\u0430\u043b\u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043b\u0435\u0434\u043d\u0438\u043a\u043e\u0432\u043e\u0433\u043e \u043f\u0435\u0440\u0438\u043e\u0434\u0430 \u043d\u0430 \u0442\u0435\u0440\u0440\u0438\u0442\u043e\u0440\u0438\u0438 \u0440\u0435\u0441\u043f\u0443\u0431\u043b\u0438\u043a\u0438 \u0421\u0430\u0445\u0430 (\u042f\u043a\u0443\u0442\u0438\u044f) \u0432 \u0420\u043e\u0441\u0441\u0438\u0438. \u041e\u043d\u0438 \u0437\u0430\u0432\u0435\u0437\u043b\u0438 \u0431\u0438\u0437\u043e\u043d\u043e\u0432 \u0438\u0437 \u0414\u0430\u043d\u0438\u0438 \u043d\u0430 \u0442\u0435\u0440\u0440\u0438\u0442\u043e\u0440\u0438\u044e \u043f\u0430\u0440\u043a\u0430, \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0434\u043b\u044f \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u0441\u043b\u0435\u0434\u0438\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u043f\u043e\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c GPS-\u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432.  <\/p>\n<h4>\u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435<\/h4>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c MVP \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043d\u0430 \u0432\u0445\u043e\u0434 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 GPS-\u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432, \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c.   <\/p>\n<blockquote>\n<p><strong>Note.<\/strong> \u0421 \u043f\u043e\u043b\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c demo-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/nathandope\/movement-data-pipeline\/tree\/habr\"><u>GitHub<\/u><\/a>.<\/p>\n<\/blockquote>\n<h4>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430<\/h4>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<h3>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n<h4>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/h4>\n<p><strong>build.properties<\/strong><\/p>\n<pre><code>sbt.version = 1.5.4<\/code><\/pre>\n<p><strong>cloudflow-plugins.sbt<\/strong><\/p>\n<p>\u0424\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u043e\u043c \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 pipeline \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Cloudflow \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0431\u043e\u0440 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 Sbt, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0443\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438. \u0411\u0430\u0437\u043e\u0432\u044b\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u201csbt-cloudflow\u201d. \u0422\u0430\u043a \u0447\u0442\u043e \u0444\u0430\u0439\u043b <strong>cloudflow-plugins.sbt<\/strong> \u043d\u0430\u0440\u044f\u0434\u0443 \u0441 <strong>build.properties<\/strong> \u2013\u00a0 \u044d\u0442\u043e \u043f\u0435\u0440\u0432\u043e\u0435, \u043e \u0447\u0435\u043c \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0437\u0430\u0431\u043e\u0442\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 Cloudflow.  <\/p>\n<pre><code class=\"scala\">addSbtPlugin(\"com.lightbend.cloudflow\" % \"sbt-cloudflow\" % \"2.1.0\")<\/code><\/pre>\n<p><strong>build.sbt<\/strong><\/p>\n<p>\u0424\u0430\u0439\u043b, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u044c\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439 \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 IDE:  <\/p>\n<pre><code class=\"scala\">\/\/ (1) - Enabling The Cloudflow Plugins  lazy val root = (project in file(\".\"))   .settings(     name := ProjectName,     version := ProjectVersion,     publish \/ skip := true,     CustomSettings.commons   )   .withId(ProjectName)   .aggregate(     pipeline,     datamodel,     transceiver,     converter,     collector   )  lazy val pipeline = appModule(postfix)   .enablePlugins(CloudflowApplicationPlugin)              \/\/ (1)   .settings(     blueprint := Some(\"blueprint.conf\"),     runLocalConfigFile := Some(s\"$ProjectResources\/sandbox\/local.conf\"),     runLocalLog4jConfigFile := Some(s\"$ProjectResources\/sandbox\/log4j.properties\")   )   .dependsOn(datamodel, transceiver, converter, collector)  \/* The auxiliary things are here *\/ lazy val common = appModule(\"common\")   .settings(     libraryDependencies += Logback,     Test \/ parallelExecution := false   )  \/* The Avro-schemas are here *\/ lazy val datamodel = appModule(\"datamodel\")   .enablePlugins(CloudflowLibraryPlugin)                  \/\/ (1)  \/* The Akka Streamlet Module *\/ lazy val transceiver = appModule(\"transceiver\")   .enablePlugins(CloudflowAkkaPlugin)                     \/\/ (1)   .settings(     libraryDependencies ++= commons,     Test \/ parallelExecution := false   )   .dependsOn(datamodel)  \/* The Flink Streamlet Module *\/ lazy val converter = appModule(\"converter\")   .enablePlugins(CloudflowFlinkPlugin)                    \/\/ (1)   .settings(     libraryDependencies ++= commons ++ flinkTestKit,     Test \/ parallelExecution := false   )   .dependsOn(datamodel, common)  \/* The Spark Streamlet Module *\/ lazy val collector = appModule(\"collector\")   .enablePlugins(CloudflowSparkPlugin)                   \/\/ (1)   .settings(     libraryDependencies ++= (commons :+ AkkaSlf4j),     Test \/ parallelExecution := false   )   .dependsOn(datamodel, common)  def appModule(moduleID: String): Project = {   Project(id = moduleID, base = file(moduleID))     .settings(       name := moduleID,       idePackagePrefix := Some(s\"$Company.$namePart1.$namePart2.$moduleID\"),       CustomSettings.commons     )     .withId(moduleID) } <\/code><\/pre>\n<p><strong>blueprint.conf<\/strong> <\/p>\n<p>\u0413\u043e\u0432\u043e\u0440\u044f, \u0447\u0442\u043e blueprint &#8212; \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0435\u0440\u0442\u0435\u0436, \u043c\u044b \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u043b\u0438. \u041f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u0432 \u043d\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 Kafka:<\/p>\n<pre><code class=\"scala\">common-kafka-config = {   producer-config {     linger.ms = 5     batch.size = 131072     max.request.size = 3145728   }   consumer-config {     max.partition.fetch.bytes = 3145728     fetch.max.bytes = 3145728   } }  blueprint {   streamlets {     transiever = dope.nathan.movement.data.transceiver.Transceiver     converter = dope.nathan.movement.data.converter.Converter     collector = dope.nathan.movement.data.collector.Collector   }    topics {     transiever_sensor-data-got = ${common-kafka-config}{       producers = [transiever.sensor-data-got-out]       consumers = [converter.sensor-data-got-in]     }      converter_track-made = ${common-kafka-config}{       producers = [converter.track-made-out]       consumers = [collector.track-made-in]     }   } } <\/code><\/pre>\n<p><strong>local.conf<\/strong><\/p>\n<p>\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b pipeline \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c <em>.conf<\/em>. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 pipeline \u0432 <abbr title=\"sandbox\">\u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0435<\/abbr>:<\/p>\n<pre><code class=\"scala\">cloudflow.streamlets { converter.config-parameters {         auto-watermark-interval = 200ms         track-window-duration = 60s         max-time-delay-of-track-points = 5s         track-window-release-timeout = 30s <\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-402018","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/402018","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=402018"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/402018\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=402018"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=402018"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=402018"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}