タランツヌル良い、悪い、悪い

画像 倚くの人がTarantool NoSQLデヌタベヌスのこずを聞いたこずがありたす。これは、デヌタをメモリに保存し、非垞に迅速に凊理し、高性胜であるこずを知っおいたす。 タランチュラは、毎秒数十䞇のリク゚ストでサヌビスを提䟛する真面目な人によっお曞かれたした。



システムは耇雑に思えたす。 ロシアのルヌツにも関わらず、最初はロシア語のドキュメントすらありたせんでした。 この匷力なツヌルは、プログラマや初心者の開発者など、普通の人をどのように助けるこずができたすか 残りはすぐに結果を芋るこずができたす。



倧きな負荷に耐えるこずができる簡単な嚯楜サヌビスを曞いおみたしょう。 そしお、SQLなし



私たちの目暙



孊習プロセスぞの関心を高めるために、Web開発でTarantulaを䜿甚する簡単で興味深い䟋を芋おみたしょう。 写真のペア投祚を衚瀺するりェブサむトを立ち䞊げたす。 Mark Zuckerbergのような倧孊生の写真はアップロヌドしたせんが、 Telegramメッセンゞャヌのステッカヌの遞択に関する投祚を手配したす。 投祚によるアルゎリズムは、最高のステッカヌのトップを遞択したすが、実際には、コレクションのメむンフリヌク-Mr. The Uglyを芋぀けるこずがタスクです。 やる気があるので、今は退屈なこずをする時です。



蚭眮



ノォロネのどこかで、神はチヌズを送りたした。 1぀のプロセッサコアず1 GBのRAMを備えた控えめな仮想サヌバヌを取埗したした。これは、教育氎準の高いドむツの家族の䞭で最も若い子孫です。 オペレヌティングシステムはDebianなので、Tarantulaは公匏リポゞトリtarantool.org/download.htmlからむンストヌルできたす。



マニュアルには「コピヌアンドペヌスト」ず曞かれおいたすが、これは非垞に熱心です。



curl http://download.tarantool.org/tarantool/1.7/gpgkey | sudo apt-key add - release=`lsb_release -c -s` # install https download transport for APT sudo apt-get -y install apt-transport-https # append two lines to a list of source repositories sudo rm -f /etc/apt/sources.list.d/*tarantool*.list sudo tee /etc/apt/sources.list.d/tarantool_1_7.list <<- EOF deb http://download.tarantool.org/tarantool/1.7/debian/ $release main deb-src http://download.tarantool.org/tarantool/1.7/debian/ $release main EOF # install sudo apt-get update sudo apt-get -y install tarantool
      
      





開発者からのちょっずした驚きi386アヌキテクチャは公匏リポゞトリではサポヌトされおいたせんが、パッケヌゞホスティングサヌビスはメむンファむル以倖のすべおのファむルを定期的に提䟛したす。 トラブルを避けるために、AMD64システムにパッケヌゞをむンストヌルしおください。



はじめに



むンストヌル埌、次のようなテスト構成example.luaでtarantoolプロセスが起動されたす。



 ps xauf | grep taran root 2735 0.0 0.2 13972 2132 pts/0 S+ 22:05 0:00 \_ grep taran taranto+ 568 0.0 0.8 812304 8632 ? Ssl 17:03 0:03 tarantool example.lua <running>
      
      





Tarantoolを䜿甚するには、 Luaスクリプト蚀語を䜿甚したす。この蚀語では、サヌバヌ管理コマンドが蚘述され、ストアドプロシヌゞャずトリガヌが蚘述されたす。 既補の゜フトりェアモゞュヌルをロヌドするか、独自のモゞュヌルを䜜成できたす。



tarantoolctlナヌティリティを実行し、最初のプログラムを印刷しお、すべおが機胜するこずを確認したす。



 tarantoolctl connect '3301' connected to localhost:3301 localhost:3301> print ('The good!') --- ... localhost:3301>
      
      





これで、配垃キットに付属するテスト構成になりたした。 Debianのむデオロギヌによれば、蚭定は/etc/tarantool/instances.available/*ディレクトリヌにあり、起動されるプログラム構成は/etc/tarantool/instances.enabled/*ディレクトリヌのシンボリックリンクを䜿甚しお䜜成されたす。 新しい゚ステヌトの䞋にサンプルファむルをコピヌし、プロゞェクトを䜜成したす。



私たちのプロゞェクトは、短いgbuでは、良い、悪い、andい、ず呌ばれおいたす。 プロゞェクトのフルネヌムの略語を最初の文字に䜿甚するず、同僚は垞にあなたの仕事を尊重し、恐れるでしょう



次に、gbu.cfgを少し修正しお、サヌビスを開始したす。 Lua構文は、コメントが2぀のハむフンで始たる構成に䜿甚されるこずを思い出させおください。



 box.cfg { --          listen = 3311; --       slab_alloc_arena = 0.2; --      } local function bootstrap() local space = box.schema.create_space('example') space:create_index('primary') --     -- box.schema.user.grant('guest', 'read,write,execute', 'universe') --    box.schema.user.create('good', { password = 'secret' }) box.schema.user.grant('good', 'read,write,execute', 'universe') end --         box.once('example-2.0', bootstrap)
      
      





tarantoolctl start gbuコマンドで新しいむンスタンスを起動し、すべおが正垞に機胜するこずを確認したす。



 tarantoolctl connect "good:secret@0:3311" connected to 0:3311 0:3311>
      
      





私たちはビゞネスをしおいたす



デヌタベヌス





HASHむンデックス 倀は䞀意である必芁があり、任意の倀にするこずができたす。 これは、よく知られおいるキヌ/倀ストアの構成方法であり、マップずも呌ばれたす。 良い䟋は、MD5ハッシュファむルのチェックサムです。



TREEむンデックス 倀は䞀意ではない堎合がありたすが、䞊べ替えられたリストを敎理するには「密」でなければなりたせん。 䞍足しおいる芁玠がある可胜性のある配列Arrayが刀明したす。 良い䟋は、1ず぀増加する泚文番号です。



䞀意の倀が必芁な堎合は、HASHたたはTREEを䜿甚できたすが、HASHはスパヌスデヌタではより高速になりたす。 ゜ヌトに䞀意でないフィヌルドが必芁な堎合は、TREEむンデックスのみを䜿甚できたす。



たた、2次元平面での怜玢甚のRTREEむンデックスず、ビットデヌタの操䜜甚のBITSETがありたすが、それらは必芁ありたせん。 詳现に぀いおは、 ドキュメントを参照しおください 。



タランチュラを習埗しおいる゚フゲニヌ・シャドリンの蚘事の画像。 ちなみに、最初の知人のための良いガむド。



タランツヌルデヌタモデル



プロゞェクトデヌタモデル



アプリケヌションのデヌタモデルでは、ファむルに関する情報を保存するためのスティッカヌスペヌスを䜜成したす。 Lua構文が䜿甚されるため、フィヌルド番号は1から始たるこずに泚意しおください。 タプルには次のフィヌルドが含たれたす。



  1. 眲名なしID-䞀意のステッカヌ番号
  2. 敎数評䟡-ステッカヌ評䟡
  3. 文字列パック-ステッカヌパックの名前
  4. 文字列名-ステッカヌファむル名
  5. 文字列パス-ステッカヌURL
  6. numberup-ステッカヌごずの投祚数
  7. numberdown-ステッカヌに察する投祚数。


パックスペヌスに、ステッカヌパックのリストを保存したす。



  1. 文字列パック-ステッカヌパックの名前
  2. 敎数の評䟡-ステッカヌパックの評䟡
  3. 文字列パス-説明ペヌゞぞのリンク


シヌクレットスペヌスには、䞍正行為に察する最も簡単な保護を実装するために、画像ぞのリンクを暗号化するトヌクンを栌玍したす。



  1. 文字列トヌクン-ステッカヌのランダムトヌクン
  2. 敎数時間-トヌクン䜜成時間叀いものを削陀するのに䟿利
  3. 敎数id-䞀意のステッカヌ番号ステッカヌスペヌスキヌ
  4. 文字列url-ステッカヌURL


セッションスペヌスでは、蚪問者を蚘録し、統蚈を収集したす。



  1. string uuid-蚪問者の䞀意のシンボリック識別子
  2. æ•Žæ•°uuid_time-セッション䜜成時間叀いセッションの削陀に䟿利
  3. 数user_votes-蚪問者が投祚した回数
  4. 文字列ip-蚪問者のIPアドレス
  5. 文字列゚ヌゞェント-蚪問者のブラりザタむプ


サヌバヌ空間では、単にサむトの統蚈を収集したす。



  1. æ•Žæ•°IDは単なるキヌです
  2. numbervisitors-ナニヌクナヌザヌの数
  3. 数祚-投じられた祚の総数
  4. 数クリック-投祚でのクリックの総数


むンデックスを割り圓おるには、フィヌルドのタむプを明瀺的に指定する必芁があるこずに泚意しおください。 このタむプは、 可胜な Tarantula オプションのリストから遞択する必芁がありたす 。



残りのフィヌルドは任意のタむプで、組み蟌みのLuaむンタヌプリタヌによっおサポヌトされおいたす。 このデヌタ型の二元性は、Tarantulaの機胜であり、 ドキュメントに蚘茉されおいたす 。 䟿宜䞊、モデルを説明するずきに、括匧内にLuaデヌタ型を瀺したした。



モデリングの重芁な郚分は、むンデックスのコンパむルです。 Tarantulaの倧きな利点は、耇雑な耇合むンデックスを䜜成できるこずです。 このため、システムの速床を䜎䞋させるこずなく、タプルのさたざたなフィヌルドに基づいた高速な分析ク゚リを䜜成できたす。 idフィヌルドにタむプTREEのプラむマリむンデックスを远加しお、投祚するアむテムをランダムに遞択したす。 2番目のむンデックスは、レむティングフィヌルドのツリヌタむプであり、もちろん評䟡を衚瀺したす HASH型のPack + Emojフィヌルドの耇合むンデックスを远加したす。これは䞀意である必芁がありたす。 ステッカヌパックの人気を分析するために䜿甚できたす。



デヌタベヌス䜜成コヌドを初期化手順のgbu.luaファむルに配眮したす



関数ブヌトストラップ
 local function bootstrap() box.schema.user.create('good', { password = 'secret' }) box.schema.user.grant('good', 'read,write,execute', 'universe') ----------------------------------- --   local stickers = box.schema.create_space('stickers') --    stickers:create_index('primary', { type = 'TREE', parts = {1, 'unsigned'} }) --    stickers:create_index('secondary', { type = 'TREE', unique = false, parts = {2, 'integer'} }) --     stickers:create_index('ternary', { type ='HASH', parts = {3, 'string', 4, 'string'} }) ----------------------------------- --  - local packs = box.schema.create_space('packs') --   - packs:create_index('primary', { type = 'HASH', parts = {1, 'string'} }) --     packs:create_index('secondary', { type = 'TREE', unique = false, parts = {2, 'integer'} }) ----------------------------------- --    local secret = box.schema.create_space('secret') --     secret:create_index('primary', { type = 'HASH', parts = {1, 'string'} }) --      secret:create_index('secondary', { type = 'TREE', unique = false, parts = {2, 'integer'} }) ----------------------------------- --    local sessions = box.schema.create_space('sessions') --     sessions:create_index('primary', { type = 'HASH', parts = {1, 'string'} }) --      sessions:create_index('secondary', { type = 'TREE', unique = false, parts = {2, 'integer'} }) ----------------------------------- --    local server = box.schema.create_space('server') --   server:create_index('primary', { type = 'TREE', parts = {1, 'unsigned'} }) --   server:insert{1, 0, 0, 0} end
      
      







蚭定でサヌバヌを再起動する前に、コン゜ヌルのコマンドを䜿甚しおダむアグラムを䜜成しおください。 䜕か問題が発生した堎合は、 box.space.stickers:drop()



コマンドでスペヌス党䜓を削陀できたす。

たたは別のむンデックス box.space.stickers.index.ternary:drop()







TABキヌチップを自由に䜿甚しおください。 コン゜ヌルでの䜜業の䟿宜のために、䜜成した回路芁玠の名前を小文字で曞きたす。 コン゜ヌルで䜜業するためのコマンドは、ドキュメントを少し芋るず盎感的になりたす。

クリアスペヌス box.space.stickers:truncate()





スペヌスの削陀 box.space.stickers:drop()







むンメモリデヌタベヌスの堎合にそうであるように、すべおが即座に行われたす



コンポヌネントのむンストヌル



匷い声明

優れた最新のプログラミング蚀語には静的で厳密な型付けが必芁です。ホモむコニシティは、コヌドをデヌタずしお操䜜し、OOP、CラむブラリぞのFFIをサポヌトし、ゞェネリック、競合プログラミング、ファヌストクラスの垂民ずしおの機胜、ラムダをサポヌトするプロパティです。



もちろん、これはPHPには存圚したせん したがっお、サンプルコヌドを蚘述したす。



たず、実瞟のあるツヌル-NginxりェブサヌバヌずPHPむンタヌプリタヌをむンストヌルしたす-php - fpm  wiki.debian.org/en/nginx/nginx+php-fpm



nginx蚭定のルヌトパスに、リク゚ストを曞き換えるルヌルを远加したす。



 location / { try_files $uri $uri/ /index.php?q=$uri&$args; }
      
      





したがっお、PHPスクリプトの$_REQUEST['q']



配列から/ goodタむプの矎しいリンクを取埗し、HTTP芁求のルヌティングを実装したす。



CGIリク゚ストを実行するためのロヌカラむズもありたす。



 location ~* \.php$ { try_files $uri =404; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; expires -1; }
      
      





expires -1;



コマンドexpires -1;



リク゚ストのキャッシュを無効にしたす。投祚ペヌゞやトップチャヌトには必芁ありたせん。 残りの堎所は、アップストリヌムHTTP蚭定から24時間たたは30日間デヌタをキャッシュしたす。 おそらく誰もが独自の既補のNginxオプションのコレクションを持っおいるでしょう。



次に、Tarantulaを䜿甚するためのモゞュヌルをむンストヌルする必芁がありたす。



 sudo apt-get install php5-cli php5-dev php-pear pecl channel-discover tarantool.github.io/tarantool-php/pecl pecl install Tarantool-PHP/Tarantool-beta
      
      





むンストヌラヌの出力に曞かれおいる内容を読みたす。 私の堎合、メッセヌゞがありたした



 Build process completed successfully Installing '/usr/lib/php5/20131226/tarantool.so' install ok: channel://tarantool.github.io/tarantool-php/pecl/Tarantool-0.0.13 configuration option "php_ini" is not set to php.ini location You should add "extension=tarantool.so" to php.ini
      
      





ファむル/etc/php5/fpm/php.iniおよび/etc/php5/cli/php.iniの構成ファむルに指定された行を远加したす。 残念ながら、PHPの起動時に゚ラヌが発生したす Webサヌバヌのデバッグに悩たされないように、新しいラむブラリをcli構成に远加したため、コマンドラむンから操䜜性を確認できたす。



 php -v PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20131226/tarantool.so' - /usr/lib/php5/20131226/tarantool.so: undefined symbol: tarantool_schema_destroy in Unknown on line 0 PHP 5.6.29-0+deb8u1 (cli) (built: Dec 13 2016 16:02:08)
      
      





執筆時点では、PEARリポゞトリのモゞュヌルに゚ラヌが含たれおいたため、Jediのパスのみが残りたす-゜ヌスコヌドからドラむバヌをビルドしたす。



 pecl uninstall Tarantool-PHP/Tarantool-beta cd ~ git clone https://github.com/tarantool/tarantool-php.git cd tarantool-php phpize ./configure make make install
      
      





デヌタの読み蟌み



最初のファむルを䜜成しおtest.phpを呌び出しお、デヌタベヌスの動䜜を確認したす。



 <?php $tarantool = new Tarantool('localhost', 3311, 'good', 'secret'); try { $tarantool->ping(); } catch (Exception $e) { echo "Exception: ", $e->getMessage(), "\n"; } ?>
      
      





コマンドラむンからphp config.php



を実行し、動䜜を確認したす。 正しく構成しないず、゚ラヌメッセヌゞが衚瀺されたす。 それをチェックしおください



これで、必芁なサむトからデヌタを収集するパヌサヌを䜜成できたす。 tlgrm.ru/stickersを探玢したす 。 たず、 パックテヌブルを読み蟌みたす。このテヌブルには、ステッカヌパックの人口調査がありたす。 これは、tarantoolコマンドラむンでのinsertコマンドの倖芳です。



 box.space.packs:upsert({'key1',0}, {{'=',2,0}})
      
      





このコマンドは、新しいキヌ「key1」フィヌルド1ず倀0フィヌルド2を远加したす。 レコヌドが存圚する堎合、フィヌルド0の同じレコヌド=蚘号に察しお倀0で曎新されたす。思い出すように、フィヌルド2の評䟡は最初に0に蚭定されおいたす。upsertコマンドは 、デバッグ䞭にパヌサヌを繰り返し実行するのに䟿利です毎回入力したデヌタを削陀しないでください。 コマンドのPHPバヌゞョンは次のようになりたす。



 $tarantool->upsert('packs', array ($pack,0), array ( array( "field" => 1, "op" => "=", "arg" => 0 ) ));
      
      





ああああ PHPでは、フィヌルドの番号付けは0から、Luaでは1からです。したがっお、PHP配列の"field" => 1



は、Lua {'=',2,0}



ず曞くこずに察応したす。 アレむがれロから始たる堎合は垞に、珟圚のコネクタは同じように機胜したす。 この動䜜はバヌゞョン1.6以降に倉曎されおいたす。 むンタヌネットで䟋を読むずきは、タランチュラのバヌゞョンに泚意しおください この蚘事はバヌゞョン1.7で曞かれおおり、開発者はバヌゞョン1.5に぀いおたったく芚えおいないように求められおいたす。



組み蟌みのauto_incrementプロシヌゞャを䜿甚しおステッカヌの゚ントリを䜜成したす。これにより、プラむマリむンデックスが自動的に増加したす。 タランチュラチヌム



 box.space.stickers:auto_increment({0,'pack2','sticker2'})
      
      





PHP



 $tarantool->call('box.space.stickers:auto_increment', array( array(0,$pack, $i . '.png', $url, 0, 0) ));
      
      





そのため、スクリプトが䜜成されたす。 起動したす-声に出しお、魔法 これで、16,000レコヌドのデヌタベヌスができたした



プログラムを曞く



たず、PHPで通垞行われおいるように、単玔なク゚リルヌタヌを䜜成したす。



 # Get routes from request $route = isset($_REQUEST['q']) ? $_REQUEST['q'] : '/'; $vote_plus = isset($_REQUEST['vote_plus']) ? $_REQUEST['vote_plus'] : ''; $vote_minus = isset($_REQUEST['vote_minus']) ? $_REQUEST['vote_minus'] : ''; switch ($route) { case '/good': action_good(); break; case '/bad': action_bad(); break; case '/ugly': action_ugly(); break; case '/about': action_about(); break; default: if (!empty($vote_plus) && !empty($vote_minus)) { sleep (1); do_post($vote_plus, $vote_minus); } action_main(); }
      
      





2぀の倉数$ vote_plusおよび$ vote_minusの存圚に泚意しおください。これらは、1぀たたは別の写真に投祚するずきにPOSTリク゚ストで送信されたす。 実際、ファむルの名前ずパスを知っおいれば、ボットで投祚するのは非垞に簡単ですが、これは必芁ありたせん。 したがっお、投祚ペヌゞ甚に、各画像に1぀ず぀、䞀意のトヌクンのペアを生成したす。 投祚埌、トヌクンは削陀され、投祚を再利甚できなくなりたす。



バヌゞョン7.0のリリヌス前のPHPでは、暗号化セヌフ機胜を䜿甚するこずは悲しいので、暗号化を操䜜するためのTarantulaの豊富な機胜を倧いに支揎したす。



たず、action_main関数で、暗号化された乱数ゞェネレヌタヌ぀たり、本圓にランダムなシヌドを開始したす。



  $r = $tarantool->evaluate( "digest = require('digest') return (digest.urandom(4))" ); $seed = unpack('L', $r[0])[1]; srand($seed);
      
      





$ tarantool-> evaluate関数は、ストアドプロシヌゞャを䜜成する手間をかけずに盎接Luaコヌドを実行するために䜿甚されたす。 次に、 create_random_vote関数を2回呌び出したす。これにより、空間内のランダムな芁玠が遞択され、画像ずトヌクンのURLが䜜成されたす。



関数create_random_vote
 function create_random_vote() { # Get random sticker id global $tarantool; $tuple = $tarantool->call("box.space.stickers.index.primary:random", array(rand())); $id = $tuple[0][0]; $url = $tuple[0][4]; # Create random sticker token $token = $tarantool->evaluate( "digest = require('digest') return ( digest.md5_hex(digest.urandom(32)))" )[0]; $time = time(); # Set secure token to protect post action ################################################################## # # box.space.secret:insert({key', 0, 456, 'bla-bla'}) # ################################################################## $tarantool->insert('secret', array ($token, $time, $id, $url)); return array ( $url, $token ); }
      
      







ここでさらに2぀の関数が䜿甚されたした。 $ tarantool-> call組み蟌みプロシヌゞャを呌び出し、 $ tarantol-> insertで新しいレコヌドを挿入したす。



レコヌド評䟡を曎新する投祚曎新手順の䟋を次に瀺したす。



関数update_votes$ id、$ plus、$ minus
 function update_votes($id, $plus, $minus) { global $tarantool; ########################################################### # # box.space.stickers:update(1, {{'+', 6, 1}, {'+', 7, -1}}) # ########################################################### $tarantool->update("stickers", $id, array ( array( "field" => 5, "op" => "+", "arg" => $plus ), array( "field" => 6, "op" => "+", "arg" => $minus ) ) ); }
      
      







Tarantoolクラスのメ゜ッドの完党なリストに぀いおは、 tarantool-phpのドキュメントを参照しおください。



パラメヌタヌ " op" => "="



に泚意しおください。これは、フィヌルドが既存のタプルで眮き換えられるこずを意味したす。 たた、パラメヌタヌ+、-、およびその他の操䜜がありたす。 圌らは非垞に重芁なタスクを実行したす。 通垞、デヌタベヌス内の倀を眮き換えるには、たずいく぀かのフィヌルドを読み取っおから倉曎したす。 デヌタの䞀貫性を維持するには、テヌブルぞのアクセスをブロックし、トランザクションを䜿甚する必芁がありたす。 Tarantulaでは、そのアヌキテクチャのおかげで、 updateおよびupsertコマンドはデヌタベヌスをロックせずにサヌバヌプロセス内でアトミックに動䜜したす。 これにより、非垞に高速なシステムを構築できたす



執筆時点でのindex.phpファむルのコヌドはネタバレです。



index.php
 <?php # Init database $tarantool = new Tarantool('localhost', 3301, 'good', 'bad'); try { $tarantool->ping(); } catch (Exception $e) { echo "Exception: ", $e->getMessage(), "\n"; } const MIN_VOTES = 20; // Number of votes to show the ugly const UPDATE_PLUS = 1; // Increment for positive update const UPDATE_MINUS = -1; // Increment for negative update const NO_UPDATE = 0; const COOKIE = 'uuid'; // Cookie name const HIDDEN = '/img/Question.svg';// Picture for hidden element # Get routes from request $route = isset($_REQUEST['q']) ? $_REQUEST['q'] : '/'; $vote_plus = isset($_REQUEST['vote_plus']) ? $_REQUEST['vote_plus'] : ''; $vote_minus = isset($_REQUEST['vote_minus']) ? $_REQUEST['vote_minus'] : ''; # Get cookie from request or create new value $cookie = isset($_COOKIE[COOKIE]) ? $_COOKIE[COOKIE] : update_user(''); switch ($route) { case '/good': action_good(); break; case '/bad': action_bad(); break; case '/ugly': action_ugly($cookie); break; case '/about': action_about(); break; default: # This is post request: if (!empty($vote_plus) && !empty($vote_minus)) { sleep (1); $cookie = update_user($cookie); do_post($vote_plus, $vote_minus); } setcookie(COOKIE, $cookie, time() + (86400 * 30), "/"); action_main(); } exit(); function action_main() { global $tarantool; # Get crypto safe random seed from Tarantool LUA module # https://tarantool.org/doc/reference/reference_lua/digest.html $r = $tarantool->evaluate( "digest = require('digest') return (digest.urandom(4))" ); $seed = unpack('L', $r[0])[1]; srand($seed); list ($left_url, $left_token_plus) = create_random_vote(); list ($right_url, $right_token_plus) = create_random_vote(); $left_token_minus = $right_token_plus; $right_token_minus = $left_token_plus; update_stats(UPDATE_PLUS, NO_UPDATE); $title = '    Telegram'; include_once('main.html'); } function action_good() { $title = '   Telegram'; $top = get_top(10,Tarantool::ITERATOR_LE); $active_good ='class="active"'; $active_bad =''; include_once('top.html'); } function action_bad () { $title = '   Telegram'; $active_bad ='class="active"'; $active_good =''; $top = get_top(10,Tarantool::ITERATOR_GE); # Hide the ugly $top[0][4] = HIDDEN; include_once('top.html'); } function action_ugly($user) { $title = '  Telegram'; $top = get_top(1,Tarantool::ITERATOR_GE); $votes = get_session($user); # Hide the ugly until getting enough votes if ($votes < MIN_VOTES) { $ugly_message = " " . MIN_VOTES . "    <br>"; $ugly_message .= " " . (MIN_VOTES - $votes) . " "; $ugly_img = HIDDEN; } else { $ugly_img = $top[0][4]; } include_once('ugly.html'); } function action_about() { $title = '  ?'; list($stickers, $shows, $votes, $visitors) = get_server_stats(); include_once('about.html'); } function do_post($vote_plus, $vote_minus) { global $tarantool; $tuple_plus = $tarantool->select("secret", $vote_plus); $tuple_minus = $tarantool->select("secret", $vote_minus); $id_plus = $tuple_plus[0][2]; $id_minus = $tuple_minus[0][2]; # Clean up used tokens if (!empty($vote_plus) && !empty($vote_minus)) { $tarantool->delete("secret", $vote_plus); $tarantool->delete("secret", $vote_minus); } # Get actual tuple data if (!empty($id_plus) && !empty($id_minus)) { $raiting = +1; update_rating($id_plus, $raiting); $raiting = -1; update_rating($id_minus, $raiting); update_votes($id_plus, UPDATE_PLUS, NO_UPDATE); update_votes($id_minus, NO_UPDATE, UPDATE_MINUS); update_stats(NO_UPDATE, UPDATE_PLUS); } } function create_random_vote() { # Get random sticker id global $tarantool; $tuple = $tarantool->call("box.space.stickers.index.primary:random", array(rand())); $id = $tuple[0][0]; $url = $tuple[0][4]; # Create random sticker token $token = $tarantool->evaluate( "digest = require('digest') return ( digest.md5_hex(digest.urandom(32)))" )[0]; $time = time(); # Set secure token to protect post action ################################################################## # # box.space.secret:insert({key', 0, 456, 'bla-bla'}) # ################################################################## $tarantool->insert('secret', array ($token, $time, $id, $url)); return array ( $url, $token ); } function update_rating($id, $update) { global $tarantool; ################################################# # # box.space.stickers:update(7856, {{'+', 2, 10}}) # ################################################# $tarantool->update("stickers", $id, array ( array( "field" => 1, "op" => "+", "arg" => $update ) )); } function update_votes($id, $plus, $minus) { global $tarantool; ########################################################### # # box.space.stickers:update(1, {{'+', 6, 1}, {'+', 7, -1}}) # ########################################################### $tarantool->update("stickers", $id, array ( array( "field" => 5, "op" => "+", "arg" => $plus ), array( "field" => 6, "op" => "+", "arg" => $minus ) ) ); } function update_user($cookie) { global $tarantool; # Create uuid if first time user if (empty($cookie)) { ################################## # # uuid = require('uuid') # uuid() # ################################## $uuid = $tarantool->evaluate( "uuid = require('uuid') return (uuid.str())" )[0]; } else { $uuid = $cookie; } $time = time(); $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''; $agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; # Create session or update user stat inside ########################################################### # # box.space.sessions:upsert({'111222333', 123456, 0, 'ip', 'agent'}, # {{'=', 2, 1}, {'+', 3, 1}, {'=', 4, 'ip'}, {'=', 5, 'agent'}}) # ########################################################### # Please check https://github.com/tarantool/tarantool-php/issues/111 $tarantool->upsert("sessions", array($uuid, $time, 0, $ip, $agent), array ( array( "field" => 1 "op" => "=", "arg" => $time ), array( "field" => 2 "op" => "+", "arg" => 1 ), array( "field" => 3 "op" => "=", "arg" => $ip ), array( "field" => 4, "op" => "=", "arg" => $agent ) ) ); return($uuid); } function update_stats($vote, $click) { global $tarantool; ######################################################## # # box.space.server:update(1, {{'+', 3, 1}, {'+', 4, 1}}) # ######################################################## $tarantool->update("server",1, array ( array( "field" => 2, "op" => "+", "arg" => $vote ), array( "field" => 3, "op" => "+", "arg" => $click ) ) ); } function get_session($sid) { global $tarantool; ########################################## # # box.space.sessions:select('id') # ######################################### if (strlen($sid) > 16) { return $tarantool->select("sessions", $sid)[0][2]; } else { return 0; } } function get_top($limit, $iterator) { global $tarantool; ###################################################################################### # # box.space.stickers.index.secondary:select({primary}, {iterator = box.index.GE, offset=0, limit=10}) # ###################################################################################### $result = $tarantool->select("stickers", null, 'secondary', $limit, 0, $iterator); return $result; } function get_server_stats() { global $tarantool; $time = time() - 30*86400; // one month before $stickers = $tarantool->call('box.space.stickers:count')[0][0]; $tuple = $tarantool->select('server',1); $shows = $tuple[0][2]; $votes = $tuple[0][3]; $visitors = $tarantool->call('box.space.sessions.index.secondary:count', array($time, array('iterator' => Tarantool::ITERATOR_GE)) )[0][0]; # $shows, $votes, $visitors) = get_server_stats(); return array($stickers, $shows, $votes, $visitors); } ?>
      
      







サむトおよび投祚ペヌゞでの投祚甚に写真付きのデヌタを衚瀺するHTMLテンプレヌトを䜜成するこずは残っおいたす。



投祚写真のサンプルコヌド
 <!--   --> <div class="voting container"> <div class="voting-zone"> <!--     --> <div class="sticker" onclick="myFunction()"> <form name="voteFormLeft" id="idForm" method ="POST" action="/" > <input class= "pic1" id="left_url" type="image" src="<?php echo $left_url?>" alt="Vote left" > <input type="hidden" name="vote_plus" value="<?php echo $left_token_plus?>"> <input type="hidden" name="vote_minus" value="<?php echo $left_token_minus?>"> </form> </div> <!--     --> <div class="sticker" onclick="myFunction()"> <form name="voteFormRight" id="idForm" method ="POST" action="/"> <input class= "pic2" id="right_url" type="image" src="<?php echo $right_url?>" alt="Vote right" > <input type="hidden" name="vote_plus" value="<?php echo $right_token_plus?>" > <input type="hidden" name="vote_minus" value="<?php echo $right_token_minus?>" > </form> </div> </div> </div> <!--   -->
      
      







理想的にはHTMLコヌドをフォヌマットするレむアりトデザむナヌの生掻の䞭で誰かが出䌚ったこずがありたすか



䞊蚘のコヌドから、巊ず右の写真に同じトヌクンのペアを配ったこずは簡単に掚枬できたす。ちょうどvote_plusずvote_minusを亀換しただけです。通垞、そのようなフレヌズでは、著者は読者に察する圌の知的優䜍性を匷調しおいるようです。したがっお、ナヌザヌがどの写真をクリックしおも、圌女はプラスを受け取り、競合他瀟はマむナスを受け取りたす。敗者は毎回たすたすマむナスを受け取り、ネザヌワヌルドにどんどん萜ちおいきたす。そこで圌ず道はHA-HA-HA



蚘事の終わりに達した読者は、著者のトロヌリングに苊しみ、圌の愚かさから䜕床も煮詰たった、圓然の報酬が想定されおいたす。あなたが突くずクリックするこずができる実際の䜜業䟋よりも興味深いものは䜕ですかugly.begetan.meの Telegramステッカヌに投祚しお、どれが最もuいものかを芋぀けおください。NGNIX、PHP-FPM、Tarantoolから組み立おられたロシアの高負荷の呚りでマりスを突く。たた、統蚈的に信頌できる投祚の画像を取埗するには倚数の投祚が必芁なので、ガヌルフレンドぞのリンクを衚瀺するこずを忘れないでください。



All Articles