Cloud HaskellでSky Beesを曞く


こんにちは、Habr

ITMOのGoToフォヌルスクヌルの終わりからわずか11577635秒しかかかりたせんでした。 Distributed Systems Weekは、Cloud Haskellでの分散システムのプロトタむピングから始たりたした。 私たちは粟力的に始めたため、博士号なしで既存のドキュメントを理解するこずは難しいこずをすぐに発芋し、トレヌニングマニュアルを䜜成するこずにしたした。

カットの䞋で、p2pクラりドhaskellの玹介、PCのプロトタむピング、やる気、そしお「なぜ」のわずかに機胜的なスタック。



あなたがそう分散した䜕かをしたいずしたす %% sCoin 既存のシステムではカバヌされおいたせんYARNはすべおの質問に察する答えではありたせん。 手䜜業ですべおを始めるず、特に目暙が最終補品たたは矎しい堎合は、倚重化接続や暗号化から、NATやピアルヌティングの突砎たで人類史䞊初めおではない本圓に倚くの問題をすばやく発芋できたす。 䜜業プロトタむプ。

そのような問題の声明から適甚されたプログラマは、すぐに「ラむブラリ」ずいう単語を思い぀きたす。 そしお本圓に。 たずえば、暙準のNATパンチメカニズムSTUN、TURN、ICEも䞀般的に知られおいるKademliaから発芋ずルヌティングのピヌスを取埗できたす。など

しかし、それでも倚くの時間ず専門知識が必芁になりたす。 投資家には忍耐がないかもしれたせん。

ここでは、より経隓豊富な同僚が「フレヌムワヌクが必芁です」ずいう考えを思い぀きたす。 そしお本圓に。 分散システムおよびアプリケヌションのプロトタむピング甚。

そしお誰かが蚀うこずさえありたす 神 、それはlibp2pです そしお圌は正しいでしょう。 郚分的に。

libp2pは、トランスポヌト、その倚重化ず暗号化、怜出、ピアルヌティング、NATブレヌクダりン、接続アップグレヌドなどの問題を解決したす。 -䞀般的に、分散アプリケヌションの倚くのネットワヌクおよび暗号化のニヌズ。 On GoずJS。

これは玠晎らしいフレヌムワヌクですが、いく぀かの問題がありたす。 これがGoずJSです。 さらに、レプリケヌションのフレヌムワヌクに䜕かがあるず䟿利です。



チュヌトリアルの断片的な性質䞀郚はたったく機胜したせんでしたにより、Cloud Haskellを䜿甚しないように説埗されたした

http://www.scs.stanford.edu/14sp-cs240h/projects/joshi.pdf 、蚀い換え

私たちのプロゞェクトは、Haskellでブロックチェヌン申し蚳ありたせんが、むノベヌションを䜜成するずいう野心から始たりたした。したがっお、libp2pはありたせんでした。 私たちはネットワヌクトランスポヌト、ディスカバリヌ、シリアル化を䜜るものを探し始めたした。 Cloud Haskellが芋぀かりたした。 ドキュメントが耇雑であるこずがわかりたした。 私の玹介を曞くこずにしたした。 だから

Cloud HaskellでSky Beesを曞く


この䟋では、ミツバチのシステムを䜜成したす。ハむブマシンのクラスタヌずミツバチノヌドがありたす。 ミツバチは花を探すためにスカりトに送られ、おいしい花の座暙ずずもに巣に戻りたす。他のすべおの蜂はこれらの座暙を知っおいる必芁がありたす。

プログラムを耇数のコンピュヌタヌで実行する必芁はたったくありたせん。プログラムを䞊行しお実行するラップトップだけです。

完党なコヌドはリポゞトリにありたす 。

Cloud Haskellは、ノヌドが共通のリ゜ヌススペヌスRAMなどを共有しないため、ノヌド間でメッセヌゞを亀換するずいう原則に基づいお動䜜したすそのようなモデルはメッセヌゞパッシングず呌ばれたす 。 アクタヌモデルは、 アクタヌが他のアクタヌにメッセヌゞを送信し、 メヌルボックスでメッセヌゞを受信する堎合のメッセヌゞパッシングモデルのプラむベヌトな䟋です。これが、Cloud Haskellでのメッセヌゞパッシングの様子です。



1.最初に、ミツバチが代衚するデヌタのタむプを定矩したす src / Types.hs

type Flower = (Int, Int) --   type Flowers = GSet Flower -- Grow-Only Set  


2.ノヌドの実装を開始したしょう。将来、コマンドラむンから実行したす app / Main.hs

 main = do --   [port, bootstrapPort] <- getArgs -- (1)     bootstrap      let hostName = "127.0.0.1" -- IP  P2P.bootstrap --       : hostName port --   (\port -> (hostName, port)) initRemoteTable -- (2)  remote table [P2P.makeNodeId (hostName ++ ":" ++ bootstrapPort)] --    bootstrap  spawnNode --    ,      

  1. 最初に、ノヌドは䜕らかの方法でお互いに぀いお孊習する必芁がありたす。぀たり、 ピア発芋を行いたす。 Cloud Haskellにはすぐに䜿甚できる゜リュヌションがありたす。ノヌドを初期化するずきに、少なくずも1぀の他のブヌトストラップノヌドを指定するだけで十分です。ノヌドは、 Peer Exchangeノヌドをブヌトストラップで䜜成したす-知っおいるノヌド別名、 ピア のアドレスを亀換したす。
  2. リモヌトテヌブルは、ピアがシリアル化をサポヌトしおいる堎合、ピアがhaskellタむプを亀換できるようにするものです。぀たり、ネットワヌクを介しお送信し、Haskellオブゞェクトに埩元できる圢匏で衚すこずができたす。 型はclass (Binary a, Typeable) => Serializable a実装する堎合、盎列化をサポヌトしたすclass (Binary a, Typeable) => Serializable a 。 Serializable 、 Binary 、 Typeable実装をTypeableで発明する必芁はありたせん-haskellはこれをあなたのために行いたす魔法の自動導出メカニズムを䜿甚

     {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} --  ,    Binary data Example = Example deriving (Typeable, Generic) instance Binary Example 
    次に、簡朔にするためにinstance Binary deriving ... 、 instance Binaryおよびプラグマを省略しinstance Binary 。

3.次に、ノヌドを起動するためのロゞックを蚘述したす。

 spawnNode :: Process () -- (1)     spawnNode = do liftIO $ threadDelay 3000000 --  bootstrap     let flowers = S.initial :: Flowers --  GSet     self <- getSelfPid -- (3)   Pid  REPL     repl <- spawnLocal $ runRepl self -- (2)  REPL    register "bees" self --        "bees" spawnLocal $ forever $ do -- (3)  : send self Tick --          liftIO $ threadDelay $ 10^6 --  0.1   ,     runNode (NodeConfig repl) flowers -- (5)   

  1. Cloud Haskellでは、䞻な機胜単䜍はProcess OSプロセスず混同しないでください。 それらは軜量の緑のスレッドに基づいおおり、他のプロセスにメッセヌゞを送信できたす特定のプロセスに送信するsend機胜たたはすべおの䜿い慣れたノヌドに送信するP2P.nsendPeers 、 メヌルボックスでメッセヌゞを受信したす expectたたはreceive*機胜、他のプロセスを開始したすたずえば、ロヌカルでspawnLocalを䜿甚するなど
  2. REPLを別のスレッドに実装する必芁がありたす。そうしないず、メむンスレッドノヌドがブロックされるため、REPLずノヌドの䞡方で倉曎できるようにGSetのスレッドセヌフむンタヌフェむスを䜜成する必芁がありたす。 システムはアクタヌに基づいおいるため、セットを倉曎するメッセヌゞを送信し、メむンスレッドでメッセヌゞを凊理する無限のサむクルで順次凊理したす。
  3. REPLを個別のクラりドハスケルプロセスずしお぀たり、緑色のスレッドずしお実行し、メむンプロセスのPid䞀意のプロセス識別子を枡しお、REPLがナヌザヌが入力したコマンドをメッセヌゞの圢匏で送信する堎所を認識できるようにしたす。 次に、PID REPLspawnLocalが返すを取埗しお、コマンドぞの応答を送信したす。 REPLコヌドはこちらです。
  4. 花の耇補はどのように機胜したすか
    • 各ノヌドはその状態を定期的にすべおのピアに送信し ブロヌドキャスト 、CRDTずずもにこれにより耇補の問題を解決したす。
      ノヌドAずBがあるずしたすB Aは芁玠xがなく、 B xがあるずしたす。 Bがブロヌドキャストを行った埌、 Aはxを远加したす-コンセンサスに達したした、など。
      GSetではなく通垞のセットがあれば、䜕も起こりたせんでしたAずB芁玠yがあるずしたす。 A yを削陀させたす。 Bがブロヌドキャストを行った埌、 Aはyを返したす。
    • すべおのノヌドにメッセヌゞを送信する堎合、 サヌビスの名前を指定する必芁がありたす。実際、このサヌビスをサポヌトするものずしおレゞスタに登録されおいるノヌドにのみメッセヌゞを送信したす。 ここでは、ノヌドを「bees」サヌビスをサポヌトするものずしお登録したす。 register "bees" selfたす。
    • 野田は、他の人にい぀幞運を送るべきかを知らなければなりたせん。 最も簡単な解決策は、タむマヌでそれを行うこずです。1秒埅っおから行動したすが、その埌、メむンのメッセヌゞ凊理フロヌをブロックしたす。 ここでは、 spawnLocalをspawnLocalおプロセスを開始したす。最初にTickメッセヌゞをメむンプロセスに送信しメむンプロセスがTickを怜出するず、その状態をノヌドに送信したす、1秒埅機しお繰り返したす。

4. OK、今最終的にメむンプロセスのロゞックノヌド実行コヌドを開始できたす。

 runNode :: NodeConfig -> Flowers -> Process () -- (1)    runNode config@(NodeConfig repl) flowers = do let run = runNode config receiveWait -- (2)   [ match (\command -> -- (3)    -  Command  REPL,  newFlowers <- handleReplCommand config flowers --     run newFlowers) , match (\Tick -> do --   ,        P2P.nsendPeers "bees" flowers --     run flowers) , match (\newFlowers -> do -- -    run $ newFlowers `union` flowers) --     -     ] 

  1. シグネチャを芋おみたしょうrunNodeは、タむプNodeConfigノヌドの構成を受け入れたす-実行時に倉曎されない情報。 私たちの堎合、これは単なるPID REPLです。 圌女は珟圚の状態である花のGSetも受け入れたす。 しかし、GSetは䞍倉のデヌタ型なので、花を远加する方法は 非垞に簡単関数を再垰的にし、状態が倉化するたびに関数を再起動したす。
  2. receiveWaitは、1぀の匕数着信メッセヌゞを持぀関数のリストを受け取り、メッセヌゞを匕き出しお、メッセヌゞのタむプに適した関数を呌び出したす。
  3. このタむプのメッセヌゞを受信した堎合 data Command = Add Flower | Show data Command = Add Flower | Show 、これはREPLからのコマンドです。 handleReplCommmandコマンドを凊理するための関数

     handleReplCommand :: NodeConfig -> Flowers -> Command -> Process Flowers handleReplCommand (NodeConfig repl) flowers (Add flower) = do --      send repl (Added flower) --  REPL ,    return $ S.add flower flowers --       handleReplCommand (NodeConfig repl) flowers Show = do --    send repl (HereUR $ toList flowers) --      return flowers 
  4. ティックがティッカヌから来た堎合、ステヌタスを送信する必芁がありたす P2P.nsendPeers "bees" flowers 。 ここで、「bees」はサヌビスの名前です。぀たり、「bees」ずしお登録されおいるノヌドにのみ花を転送したす。
  5. 他のミツバチから花を受け取った堎合、銎染みのない花をすべお自分自身に远加する必芁がありたす。぀たり、倚くの新しい花ず倚くの既存の花を単玔に組み合わせたす。

5.以䞊です 完党な゜ヌスコヌドをダりンロヌドしおコンパむルしたす。

 git clone https://github.com/SenchoPens/cloud-bees.git cd cloud-bees stack setup # Stack  GHC stack build #  

1぀のタヌミナルで次の行を実行したす。

 stack exec cloud-bees-exe 9000 9001 2>/dev/null 

そしお別のこれで

 stack exec cloud-bees-exe 9001 9000 2>/dev/null 

REPLがプロンプトを出したす。 1぀の端末にAdd (1, 2)を远加しおみおください。 座暙1、2を持぀花を远加し、別の-Showで、2番目のノヌドにもそのような花があるこずがわかりたす。




Haskellで分散システムを䜜成するこずはそれほど怖くないこずをあなたに玍埗させおいただければ幞いです:)

同様のシステムの倚くの実際のナヌザヌケヌスを考え出すこずができたすたずえば、公共亀通機関で野りサギの問題を解決するカヌド䞊の亀通機関に通行する人はログむン枈みずしおマヌクされ最初のGSetに自分のIDを远加、出力時に-ログアりト枈みずしおIDを远加したす 2番目のGSet。 倜茞送が機胜しないずきに、チェックが行われたす-人が出入りした堎合、圌は野りサギではありたせん。

興味のある方は、シフト䞭に行った暗号化を䜿甚したより倧きなプロゞェクトをご芧ください。



愛を蟌めお、アヌセニヌず仲間、9幎生。 wldhxの穏やかな指導の䞋で

Source: https://habr.com/ru/post/J351496/


All Articles