Asyncio Tarantool Queue、䞊んでください





私の蚘事の1 ぀で、PythonでTarantoolを䜿甚した非同期䜜業に぀いお説明したした 。 この蚘事ではこのトピックを続けたすが、 Tarantoolのキュヌを介した情報の凊理に泚意を払いたいず思いたす。 私の同僚は、キュヌの利点に関するいく぀かの蚘事を公開しおいたす 䟋ずしお、 My World゜ヌシャルネットワヌクでの凊理むンフラストラクチャのキュヌむングず、REST APIでのプッシュ通知 。 PythonずasyncioでTarantool Queueを操䜜するこずず同様に、問題の解決策の䟋によっおキュヌに関する情報を補足したいず思いたす。 RedisやRabbitMQではなく、Tarantoolを遞択する理由は䜕ですか



「ナヌザヌベヌス党䜓に」メッセヌゞを送信するタスク



Mail.Ruには倚くのメディアサむトがありたす News 、 Auto 、 Lady 、 Health 、 Hi-Techなど、毎日䜕癟䞇人ものナヌザヌがそれらを蚪れたす。 サむトはモバむルデバむスに適合しおおり、それらのほずんどにはタッチバヌゞョンがありたす。 ナヌザヌの利䟿性のために、AndroidおよびiOSデバむスで人気のあるNewsモバむルアプリケヌションを䜜成したした。 「ホット」ニュヌスの公開埌、アプリケヌションの各ナヌザヌはプッシュ通知を受け取りたす。 通垞、次のように衚瀺されたす。線集長がニュヌスを遞択し、管理パネルの[火灜]ボタンをクリックするず、それだけです それから䜕 次に、このニュヌスをできるだけ早くサブスクラむバヌデヌタベヌス党䜓に送信する必芁がありたす。 誰かが30分以内にプッシュ通知を受信した堎合、おそらくニュヌスはそれほど「ホット」ではなく、ナヌザヌは別の゜ヌスからそれに぀いお孊習したす。 これは私たちの堎合ではありたせん。



だから、私たちの最愛のタランツヌルに保存されおいるデヌタベヌスがありたす。 デヌタベヌス党䜓をできるだけ早く回避し、すべおのサブスクラむバヌにプッシュ通知を送信する必芁がありたす。 それぞれに぀いお、プッシュトヌクンずjson圢匏のデバむスに関するいく぀かの情報がデヌタベヌスに保存されたす。アプリケヌションバヌゞョン、画面解像床、タむムゟヌン、ナヌザヌが通知を受信する時間間隔です。 タむムゟヌンを指定するこずは非垞に重芁です。誰もが眠っおいる倜間にプッシュ通知を送信するこずはお勧めできたせん。



芁件があれば、すべおが明確になりたす。



問題を解決したす



通垞、額の問題を簡単な方法で解決し始めたす。 単玔なコヌドは垞に非垞にきれいに芋えたす。



while « »:  «»   -    «»
      
      





メむンのwhile



は、すべおのナヌザヌを凊理するたで実行されたす。 ナヌザヌベヌスが小さい堎合、それ以䞊䜕もするこずができず、問題は解決したす。 ここで䜕を改善できたすか そのようなサむクルをスピヌドアップする方法は デヌタベヌスのサむズに関係なく、䞀定時間送信する方法は これを行うには、通知を送信するプロセスの詳现を明確にする必芁がありたす。



簡単にするために、2぀のAndroidプラットフォヌムずiOSプラットフォヌムに焊点を圓おたす。 「プッシュ送信」ずは䜕ですか どうやっおやるの Google Cloud MessagingおよびApple Push Notification Serviceプロトコルの説明がありたす。 PythonのAndroidおよびiOSでプッシュ通知を送信するための既補のラむブラリがあり、通垞の「同期」モヌドで動䜜するように蚭蚈されおいたす。 さらに深く掘り䞋げるず、各プラットフォヌムには固有の特性がありたす。 Androidでのプッシュずは、httpsを介しおjsonデヌタを送信するこずを意味し、iOSでは、ssl゜ケットにバむナリデヌタを送信したす。 Appleは間もなくHTTP / 2プロトコルのサポヌトを玄束したす。 Androidでは、耇数の宛先ぞの送信が可胜です。 IOSには、耇数のナヌザヌをグルヌプ化し、グルヌプに通知を送信する機胜がありたす。 ぀たり、各プラットフォヌムのグルヌプ化にも独自の特性がありたす。



キュヌの決定は明らかに頌りになりたす。 デヌタベヌスからナヌザヌを遞択するプロセスず、プラットフォヌムごずに通知を送信するプロセスを分離したいず思いたす。 しかし、倚くの重芁な詳现がありたす。 あるプラットフォヌムを別のプラットフォヌムから送信するプロセスを独立させるために、iOSおよびAndroidで遞択した「バンドル」からナヌザヌを分離し、ナヌザヌをグルヌプ化し、目的のキュヌに送信するメッセヌゞを远加できたす。 さらにメッセヌゞを凊理できたす。぀たり、プッシュ通知を送信する䜜業を盎接実行できたす。 抂略的に、これらのプロセスはすべお次のように衚すこずができたす。





ナヌザヌベヌスをバむパスし、キュヌを介しおメッセヌゞを凊理するスキヌム



そのようなアプロヌチは䜕をもたらすでしょうか ナヌザヌベヌスをバむパスするプロセスをプッシュ通知から分離したす。 したがっお、元のルヌプの「バンドル」をより高速に゜ヌト select_range



実行しselect_range



たす。 プラットフォヌムの1぀でメッセヌゞを凊理する際に朜圚的な問題が発生した堎合そしお、そのようなこずが頻繁に発生する堎合、これは他のプラットフォヌムでの配垃には圱響したせん。 したがっお、論理キュヌがあるため、サヌバヌコア間でメッセヌゞ凊理を簡単に䞊列化できたす。 システムを少し拡匵する必芁がある堎合は、新しい論理キュヌを远加するだけです。



ロヌドずスケヌリングの問題を解決したす



1぀のサヌバヌの負荷が増加するず、CPUはすぐに終了したす。 別のサヌバヌを远加したすか はい、たったく同じです。 ただし、これはサヌビスの蚭蚈段階で行う方が適切です。 システムを2台のサヌバヌで動䜜させる堎合、数十台を远加するこずは難しくありたせん。 私たちはこの原則を守りたす。実際の負荷がない堎合でも、少なくずも2台のサヌバヌです。 いく぀かのサヌバヌは、サヌビスの信頌性も高めたす。 サヌビスアヌキテクチャの圢匏は次のずおりです。





2台のサヌバヌでナヌザヌデヌタベヌスをバむパスするスキヌム



そのため、2぀のサヌバヌがあり、それぞれに独自のキュヌがありたすもちろん、ナヌザヌデヌタベヌスもありたす。それは近くのどこかにあるず考えられ、 select_range



で利甚できたすが、これにはあたり泚意を払いたせん。 2぀のサヌバヌでクロヌルルヌプを䞊行しお開始するこずが非垞に重芁です。 いずれかのサヌバヌでサむクルを繰り返し、「パック」を遞択し、各「パック」を異なるキュヌに配眮し、「パック」をすべおのサヌバヌに均等に分散するこずができたす。 このアプロヌチでは、ネットワヌクを介しおデヌタを「駆動」する必芁がありたす。 「バンドル」を遞択しお別のサヌバヌのキュヌに入れるこずは、このアプロヌチの匱点です。 サヌバヌ間でselect_range



を䞊列化する必芁がありたす。



これを行うには、いずれかのサヌバヌで「パケット」を遞択し、珟圚の「パケット」から「隣接」サヌバヌに最埌のナヌザヌIDに関する情報を含む小さなメッセヌゞを远加したす。 2番目のサヌバヌで小さなメッセヌゞを凊理する堎合、指定されたIDで始たる「新しいパケット」を取埗し、「近隣サヌバヌ」などず同様のメッセヌゞを䜜成しお、デヌタベヌス党䜓を゜ヌトする必芁がありたす。 珟圚の「バンドル」は、垞にそのキュヌでロヌカルに凊理する必芁がありたす。 したがっお、コヌドをデヌタに「移動」し、サヌバヌ䞊の「パケット」の生成を䞊列化し、ネットワヌク䞊でデヌタを駆動したせん。



シヌケンス図は次のようになりたす。







「すべおのナヌザヌ向け」ルヌプは、 queue.put(last_id)



介しお暗黙的に実行されたす。 select_range



ナヌザヌをselect_range



メヌル送信プロセスはselect_range



たす。 分散スキヌムでは、デヌタベヌスにロックがないこずが非垞に重芁です。 このスキヌムは、HadoopのMapReduceプロセスず非垞によく䌌おおり、「分割しお埁服する」ずいう同じ原則です。



実皌働環境でもたったく同じアヌキテクチャが䜿甚されおいたす。 モバむルアプリケヌションずプラットフォヌムのタむプごずに、個別の論理キュヌが䜿甚され、プロセスの独立した䞊列実行が可胜になりたす。 200䞇番目のナヌザヌベヌスでニュヌスのプッシュ通知を送信するために玄2分を送信したす。 このようなメヌリングに加えお、8台のサヌバヌのクラスタヌは1秒あたり玄1䞇件のプッシュ通知を送信したす。



Tarantool Queueのコヌド䜜成の機胜



倚数の論理キュヌを䜿甚する方法 1぀のPythonプロセスですべおのキュヌのデヌタを同時に生成および生成する方法 非同期プログラミング技術が助けになりたす。 䟋では、Centos 6.4、Python 3、asyncio、 aiotarantool_queue 、Tarantool 1.6、およびTarantool Queueを䜿甚したす。



Tarantool Queueラむンは、かなり倧きな負荷に耐えたす。 GitHubに説明がありたす。 Tarantool Queueを䜿甚する1぀のむンスタンスでは、queue.create_tubeを呌び出すこずで耇数の論理キュヌを䜜成できたす。 論理キュヌはチュヌブず呌ばれたす。 いく぀かのタむプの論理キュヌがサポヌトされおいたす。 Tarantool Queueには、 take/ack



メカニズムがありたす。 実行呌び出しは、タスクを「進行䞭」ずしおマヌクしたす。 ack



呌び出すず、タスクがキュヌから削陀され、実行が成功したこずが確認されたす。 ack



呌び出しに到達しない堎合、別のプロセスがタスクをtake



を実行しtake



。 delay



パラメヌタヌを䜿甚しお、タスクの実行をしばらく遅らせるこずができたす。 すべおのキュヌにこのような機胜ずパフォヌマンスがあるわけではありたせん。



ナヌザヌストレヌゞずキュヌシステムの䞡方にTarantoolを䜿甚するず、䜿甚するテクノロゞヌの芳点からサヌビスがシンプルになりたす。 Tarantool Queueの䜿甚はオプションです。 TarantoolずLuaは、独自のキュヌを実装する機䌚を提䟛したす。



Tarantoolをむンストヌルし、github.com / tarantool / queueを/ usr / local / luaディレクトリに配眮したす。 Tarantool config /etc/tarantool/instances.enabled/q1.luaで、次を指定したす。



 #!/usr/bin/env tarantool package.path = package.path .. ';/usr/local/lua/tarantool-queue/?.lua' box.cfg{listen = 3301, slab_alloc_arena = 2} queue = require 'queue' queue.start() box.queue = queue
      
      





むンスタンスをキュヌで開始したす。



 tarantoolctl start q1
      
      





コン゜ヌルに行きたす



 # tarantoolctl enter q1 /usr/bin/tarantoolctl: Connecting to /var/run/tarantool/q1.control /usr/bin/tarantoolctl: connected to unix/:/var/run/tarantool/q1.control unix/:/var/run/tarantool/q1.control
      
      





ゲストアクセスを蚱可し、論理キュヌq1



を䜜成したす。



 q1.control> box.schema.user.grant('guest','read,write,execute','universe') q1.control> queue.create_tube('q1', 'fifo') ^D
      
      





次のように1タヌンをレヌキできたす。



 queue = Tarantool.Queue(host="localhost", port=3301) while True: task = queue.take(tube="q1") process(task) task.ack()
      
      





N個のキュヌをレヌキするために、N個のプロセスを䜜成できたす。 各プロセスで、目的のキュヌに接続し、たったく同じサむクルを実行する必芁がありたす。 これは実甚的なアプロヌチですが、キュヌが倚数ある堎合は、Tarantool Queueぞの接続が倚くなりたす。 サヌバヌの物理メモリを消費する倚くのプロセスも起動されたす。 「倚くの接続」では、Tarantoolでの䜜業が可胜な限り効果的になりたせん。 たた、プロセスでは、GoogleおよびAppleサヌバヌぞの接続を維持する必芁がありたす。 繰り返したすが、保持しおいるGoogleたたはAppleサヌバヌぞの接続が少ないほど、ロヌドする負荷が少なくなるため、サヌバヌのリ゜ヌスをより倚く䜿甚できたす。



「PythonのTarantoolを䜿甚した非同期操䜜」の蚘事で、Tarantoolぞの単䞀の接続を䜿甚するずパフォヌマンスが顕著に向䞊する理由を詳しく説明したしたこれはワヌクロヌドにずっお非垞に重芁です。 このアプロヌチはここで適甚できたす。 ゜ヌスの擬䌌コヌドを少し倉曎しお、キュヌをかき集めたす。 それをasyncioに適合させたす。



 import asyncio import aiotarantool_queue @asyncio.coroutine def worker(tube): while True: task = yield from tube.take(.5) if not task: break # process(task.data) yield from task.ack() loop = asyncio.get_event_loop() queue = aiotarantool_queue.Queue("127.0.0.1", 3301, loop=loop) workers = [asyncio.async(worker(tube), loop=loop) for tube in (queue.tube('q1'), queue.tube('q2'), queue.tube('q3'))] loop.run_until_complete(asyncio.wait(workers)) loop.run_until_complete(queue.close()) loop.close()
      
      





1぀のプロセスで、キュヌぞの接続を䜜成したす。 すべおの論理キュヌに察しおtake / ackルヌプを䜿甚しおコルヌチンを䜜成したす。 むベントルヌプを開始し、すべおのキュヌをレヌキしたす。 これが、キュヌむングパタヌンの様子です。



コヌドは線圢のたたであり、コヌルバックはありたせん。 たた、このコヌドの「 aiotarantool_queue



」では、キュヌからのタスクが「バンドル」によっお差し匕かれるずいう事実が隠されおいたす-これはすべおaiotarantool_queue



埗られたす。 期埅もせず、キュヌずタむムアりトを匕き出したす かっこいい もちろん、すべおのサヌバヌコアをCPUにロヌドするには、このようなプロセスをいく぀か実行する必芁がありたすが、これは既に技術的な問題です。 Pythonプロセスでのキュヌむングは次のようになりたす。 コルチンの代わりに、プロセスがありたす。 たた、同期アプロヌチを䜿甚するず、コヌドはさらに耇雑になり、最も重芁なこずずしお、生産性が䜎䞋する可胜性がありたす。



ただし、asyncioを䜿甚するこずには欠点がありたす。 サヌドパヌティのラむブラリを動䜜させる必芁がありたすが、これはそれほど難しくありたせんが、これらのラむブラリのコヌドを慎重にレビュヌし、asyncio呌び出しを䜿甚しお動䜜を調敎する必芁がありたす。 生産的なサヌビスが必芁な堎合は、asyncioの䞋でサヌドパヌティラむブラリの䜜業をサポヌトするすべおの努力が正圓化されたす。



しかし、RedisずRabbitMQはどうでしょうか



RedisやRabbitMQではなくTarantool Queueを䜿甚する理由は䜕ですか 特定の補品に有利な遞択はそれほど単玔ではありたせん-RedisずRabbitMQの䞡方を怜蚎したした。 Redisにはプロトタむプもありたした。 これらの゜リュヌションはすべお、十分なパフォヌマンスを備えおいたす。 しかし、ここでの問題は「誰が速いか」だけではありたせん...



たず、キュヌをメモリ内ではなく信頌できるものにしたいのです。 WALを備えたTarantoolは、RedisやRabbitMQよりも信頌性が高く芋えたす。



各キュヌシステムには独自の特性がありたす。 Redisにはpub / subメカニズムがあり、問題の解決には適しおいたせん-キュヌが必芁です。 Redisにはリストずrpush / blpop操䜜があり、デヌタが衚瀺されるのをロックしお埅機したすが、take / ackメカニズムはありたせん。 私たちの生産では、この特定のメカニズムによっお信頌性が提䟛されたす-それが最高であるこずが繰り返し蚌明されおいたす。



RabbitMQは、キュヌのさたざたなパタヌンが豊富です。 問題を解決するには、RabbitMQ機胜の䞀​​郚のみが必芁です。 そのパフォヌマンスは非垞に高いですが、ディスクぞのデヌタの保存をオンにするず、負荷時のパフォヌマンスが倧幅に䜎䞋したす。 RabbitMQを実行するには、RabbitMQむンスタンスを再起動するだけでなく、運甚䞊の問題を蚺断できる経隓豊富なシステム管理者が必芁です。



RabbitMQの特別な泚意は、Python APIずasyncioのコネクタに倀したす。 キュヌAPIはコヌルバックに実装されたす。 コヌルバックからのコヌドは耇雑になり、保守が難しくなりたす。 asyncioでmessage.ackを䜜成するには、 Futureを䜜成しお埅぀必芁がありたす。 このようなコヌドは非垞に耇雑に芋えたす。 たた、1぀の接続に耇数のput / takeを送信するこずもできたせんでした。



asyncioを備えたRedisの方がはるかに優れおいたす。asyncioの䜜成者自身による玠晎らしいコネクタがありたす。 非垞に高速に動䜜したす。



RedisおよびRabbitMQでは、Tarantoolのようなデヌタベヌスずluaにそのようなデヌタ統合はありたせん。 原則ずしお、生産タスクには、ボックスからもう少し「ロゞック」が必芁です。 Tarantoolでは、これはluaのおかげで簡単に実珟できたす。 たずえば、カりンタヌたたはデヌタキャッシュの保存を開始したり、キュヌに入れられたむンスタンスの統蚈を盎接保存したりできたす。 これにより、Tarantoolはさたざたな問題を解決するのに䟿利です。



たずめるず



耇数のサヌバヌでキュヌむングシステムを䜿甚しお、ナヌザヌベヌス党䜓をできるだけ迅速か぀効率的に䞊列化する方法のアヌキテクチャを怜蚎したした。 Tarantool Queueずasyncioを䜿甚するパタヌンを調べたした。 キュヌシステムを䜿甚したコヌド開発の問題に泚意を払いたした。 RabbitMQずRedisの問題、およびTarantool Queueの利点を調べたした。



この情報がHabrの読者に圹立぀こずを願っおいたす。 誰かがキュヌを䜿甚するケヌスを共有し、この゜リュヌションたたはその゜リュヌションを遞択する理由に぀いお話しおくれるずうれしいです。



蚘事の執筆に䜿甚されたリンク




All Articles