PHP და AJAX ვიკის მარტივი მაგალითი. php სესიების შენახვა Redis-ში დაბლოკვით

). ინსტრუმენტი შექმნილია სხვადასხვა PHP სკრიპტების გასაშვებად კულისებში ან API-ს მეშვეობით. როგორც წესი, ეს სკრიპტები აწარმოებენ ნახაზებს და მოთხოვნა ვრცელდება დაახლოებით 100 სერვერზე. მანამდე ჩვენ ყურადღებას ვამახვილებდით იმაზე, თუ როგორ განხორციელდა კონტროლის ლოგიკა, რომელიც უზრუნველყოფს ყურადღების თანაბარ განაწილებას სერვერების ასეთ რაოდენობაზე და ამოცანების შემდეგ დავალებების გენერირებას. გარდა ამისა, ჩვენ გვჭირდებოდა დემონის დაწერა, რომელიც შეძლებდა ჩვენი PHP სკრიპტების CLI-ში გაშვებას და მათ ვიკის სტატუსს.

ასოების უმეტესობა დაწერილია C-ზე, ისევე როგორც ჩვენი კომპანიის ყველა სხვა დემონი. თუმცა, ჩვენ მივხვდით, რომ პროცესორის დროის უმეტესი ნაწილი (დაახლოებით 10%) არსებითად დაიხარჯა: თარჯიმანის გაშვება და ჩვენი ფრეიმერის „ბირთის“ გაშვება. იმისათვის, რომ შეგვეძლოს თარჯიმანისა და ჩვენი ფრეიმერის ინიციალიზაცია კიდევ ერთხელ, ჩვენ ვაფასებდით დემონის გადაწერის გადაწყვეტილებას PHP-ში. მე დავურეკე იოგოს Php კლდე syd (Phproxyd-ის ანალოგიით – PHP Proxy Daemon, დემონი C-ში, რომელიც ადრე გვქონდა). ის იღებს მოთხოვნებს სხვა კლასების გაშვების შესახებ და აწარმოებს fork() თითოეულ მოთხოვნას და ასევე აცნობებს თითოეული კლასის გაშვებიდან გაყვანის სტატუსს. ეს არქიტექტურა ძალიან ჰგავს Apache ვებ სერვერის მოდელს, რადგან ყველა ინიციალიზაცია ხდება ერთხელ „ოსტატის“ მიერ და „ბავშვები“ თავად აკეთებენ ყველა დამუშავებას. როგორც დამატებითი ბონუსი, ახლა შეგვიძლია გავააქტიუროთ ოპკოდის ქეში CLI-ში, რაც სწორად არის შესრულებული, რადგან ყველა ბავშვი იზიარებს მეხსიერების იმავე არეალს, როგორც ძირითადი პროცესი. გაშვების მოთხოვნის დამუშავებისას დაყოვნების შესაცვლელად, შეგიძლიათ იმუშაოთ fork()-ის უკან (prefork მოდელი), ან ჩვენს შემთხვევაში დააყენოთ delay to fork() 1 ms-ზე დაახლოებაზე, რაც მთლიანად გვაკონტროლებს.

თუმცა, რადგან ჩვენ ხშირად ვაახლებთ კოდს, ეს დემონიც ხშირად უნდა გადატვირთოთ, წინააღმდეგ შემთხვევაში მასში ჩართული კოდი შეიძლება მოძველდეს. კანის ფრაგმენტები ხელახლა იწყებენ suprovodzhuvavsya მასა წყალობის დანახვაზე კავშირის გადატვირთვა თანატოლების მიერ, მათ შორის vidmovs ტერმინალური koristuvachs-ის სამსახურში (დემონი ყავისფერია არა მხოლოდ სიბნელისთვის, არამედ ჩვენი საიტის ნაწილისთვისაც), ჩვენ ვეძებდით გზებს დემონის გადატვირთვისთვის, უკვე დაინსტალირებული კავშირების დახარჯვის გარეშე. არსებობს ერთი პოპულარული ტექნიკა, რომელიც უნდა ეძებოთ დახმარებისთვის. მოხდენილი გადატვირთვადემონებისთვის: გაუშვით fork-exec და მოსმენის სოკეტის აღმწერი გადაეცემა თქვენს მასპინძელს. ამგვარად, ახალი კავშირები მიიღება დემონის ახალ ვერსიასთან, ხოლო ძველებს ძველი ვერსიებიდან „გადახედვა“.

ამ სტატიაში განვიხილავთ რთულ ვერსიას მოხდენილი გადატვირთვა: ძველი კავშირები განახლდება დემონის ახალი ვერსიით, რაც მნიშვნელოვანია ჩვენს შემთხვევაში, სანამ ისინი ძველ კოდს იმუშავებენ.

თეორია მოდით, ცოტა ხნით დავფიქრდეთ: რა არის ის შესაძლებლობები, რომელთაგან თავის დაღწევა გვინდა? და თუ ასეა, მაშინ როგორ მივიდე მას?

ვინაიდან დემონი მუშაობს Linux-ის ქვეშ, რომელიც არის POSIX მეგობრული, ჩვენთვის ხელმისაწვდომია შემდეგი პარამეტრები:

  • ყველა ღია ფაილი და სოკეტი არის იგივე რიცხვი, რომელიც შეესაბამება ღია აღწერის რაოდენობას. შეტყობინებების სტანდარტული შეყვანა, გამომავალი და ნაკადი არის აღწერები 0, 1 და 2 შესაბამისად.
  • არ არსებობს საერთო ფუნქციები ღია ფაილს, სოკეტსა და მილს შორის (მაგალითად, სოკეტებთან ერთად შეგიძლიათ გამოიყენოთ როგორც წაკითხვა/ჩაწერა, ასევე გაგზავნა/რექვ სისტემის დაწკაპუნებით).
  • როდესაც სისტემური გამოძახების fork() წყდება, ყველა დესკრიპტორი იხურება, ინახავს მათ ნომრებს და წაკითხვის/ჩაწერის პოზიციებს (ფაილებში).
  • როდესაც სისტემური გამოძახება execve() მთავრდება, ყველა გახსნილი დესკრიპტორი ასევე დეაქტივირებულია და გარდა ამისა, PID პროცესი ინახება და, შესაბამისად, სავალდებულოა მისი შვილებისთვის.
  • კრიტიკული პროცესის სახელურების სია ხელმისაწვდომია /dev/fd დირექტორიადან, რომელიც Linux-ზე არის /proc/self/fd-ის სიმბოლო.
  • ამ გზით, ჩვენ ყველაფერი გვაქვს მხედველობაში, რომ ჩვენი ამოცანა შეიძლება შესრულდეს და განსაკუთრებული ძალისხმევის გარეშე. კარგი, დავიწყოთ. არ მიუახლოვდეთ დემონს, რადგან ჩვენ უნდა ყურადღებით დავაკვირდეთ ღია აღწერებს, რათა არ გავანადგუროთ ძაფები ბავშვის პროცესების გადატვირთვისა და დაწყებისას).

    დამწყებთათვის, ჩვენ ვაკეთებთ PHP კოდს რამდენიმე პატარა პატჩს, რათა დავამატოთ fd ნაკადიდან ამოღების და მუშაობის უნარი, რათა fopen(php://fd/) არ გამოიწვიოს აღწერის ასლის გამოშვება ( კიდევ ერთი ცვლილება არ არის გონივრული PHP-ის threading ქცევასთან დაკავშირებით, ამიტომ, ამის ნაცვლად, შეგიძლიათ დაამატოთ ახალი „მისამართი“, მაგალითად, php://fdraw/):

    პაჩის კოდი

    diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index f8d7bda..fee964c 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/ph c @@ -24.6 +24.7 @@ #if HAVE_UNISTD_H #include #endif +#include #include "php.h" #include "php_globals.h" @@ -296.11 +297.11 @@ php_stream * php_stream_url_wrap_rapper *php. გზა, ch "ტელეგრაფის ფაილები არის %d-ზე უხილავი ფოსტის ნომრების დამნაშავე", dtablesize); დაბრუნება NULL; ) - - fd = dup (fildes_ori); - if (fd == -1) ( + + fd = fildes_ori; + if (fcntl(fildes_ori, F_GETFD) == -1) ( php_stream_wrapper_log_error(wrapper, ოფციები TSRMLS_CC, - "შეცდომა ფაილის აღწერის %ld გატყუებისას; შესაძლოა ეს ასეა 't "t არსებობს: " + "ფაილის აღმწერი %ld არასწორია: " "[%d]: %s", fildes_ori, errno, strerror(errno)); დაბრუნება NULL; ) diff --git a/ext/standard/ streamsfuncs. c b/ext/standard/streamsfuncs.c index 0610ecf..14fd3b0 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -24.6 +24.7 @ @ # მოიცავს "ext/standard/flock_compat.h" #include "ext/standard/file.h" #include "ext/standard/php_filestat.h" +#include "ext/standard/php_fopen_wrappers.h" #include "php_open_temporary_file .h" " #include "ext/standard/basic_functions.h" #include "php_ini.h" @@ -484,6 +485,7 @@ PHP_FUNCTION(stream_get_meta_data) zval *arg1; php_stream *stream; zval *newval; + int tmp_fd ; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) ( return; @@ -502.6 +504.9 @@ PHP_FUNCTION(stream_get_meta_data) add_as char *-stream >wops-rapper 1); ) add_assoc_string(return_value, "stream_type", (char *) stream->ops->label, 1); + if (SUCCESS == php_stream_cast(ნაკადი, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&tmp_fd, 1) && tmp_fd != -1) ( + add_assoc_long(return_mo_val, string(return_mo_val,return_mo_value);


    შედეგს დავამატეთ fd ველი, რომელიც ბრუნავს stream_get_meta_data() ფუნქციით, რადგან მას აქვს აზრი (მაგალითად, zlib სტრიმებისთვის არ იქნება fd ველი). ჩვენ ასევე ჩავანაცვლეთ dup() გამოძახება გადატანილი ფაილის აღწერიდან მარტივი შებრუნებით. სამწუხაროდ, ეს კოდი Windows-ში ცვლილებების გარეშე არ იმუშავებს, fcntl() გამოძახების ფრაგმენტები სპეციფიკურია POSIX-ისთვის, ამიტომ ახალ პატჩს შეუძლია დამატებითი შეცდომები შეიტანოს კოდში სხვა OS-ებში. დემონის მიღება შესაძლებელია ამის გარეშე. გადატვირთვა და JSON ფორმატში ჩაწერა მიეცით რაიმე სახის დადასტურება. მაგალითად, მასივში არის ელემენტების დიდი რაოდენობა, რომლებიც ყველაზე შესაფერისია შეკითხვისთვის.

    დემონი უსმენს პორტს 31337. რობოტის შედეგი არის დამნაშავე შემდეგში:

    $ telnet localhost 31337 ვცდილობ 127.0.0.1... დაკავშირებულია localhost-თან. გაქცევის სიმბოლოა "^]". ("hash":1) # შეყვანილი koristuvach-ის მიერ "მოთხოვნას ჰქონდა 1 გასაღები" ("hash":1,"cnt":2) # შეყვანილი koristuvach-ის მიერ "მოთხოვნას ჰქონდა 2 გასაღები"

    ჩვენ გამოვიყენებთ stream_socket_server() პორტის მოსმენის დასაწყებად და stream_select() რათა დავადგინოთ რომელი სახელურებია მზად წასაკითხად/ჩასაწერად.

    კოდი უმარტივესი განხორციელებისთვის (Simple.php)