{"id":35722,"date":"2019-10-31T22:05:58","date_gmt":"2019-10-31T19:05:58","guid":{"rendered":"https:\/\/prohoster.info\/blog\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh\/"},"modified":"2019-10-31T22:05:58","modified_gmt":"2019-10-31T19:05:58","slug":"roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh","title":{"rendered":"RoadRunner: PHP is not made to die, or Golang rushes to the rescue","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"RoadRunner: PHP is not made to die, or Golang rushes to the rescue\" src=\"\/wp-content\/uploads\/2019\/06\/d2a69318cf25caa8fb49efedb333d7f8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nHello, Habr! We at Badoo are actively <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/badoo\/blog\/430722\/\">working on PHP performance<\/a><\/noindex>, as we have a quite large system built on this language and performance is a matter of cost savings. Over ten years ago, we created PHP-FPM for this purpose, which initially was a set of patches for PHP, and later became part of the official distribution.<\/p>\n<p>In recent years, PHP has made significant advancements: the garbage collector has improved, and stability has increased \u2014 today you can write daemons and long-running scripts in PHP without significant issues. This has allowed Spiral Scout to go further: RoadRunner, unlike PHP-FPM, does not clear memory between requests, resulting in additional performance gains (although this approach complicates the development process). We are currently experimenting with this tool, but we don\u2019t have results to share yet. To make the wait more enjoyable, <b>we are publishing a translation of the RoadRunner announcement from Spiral Scout.<\/b><\/p>\n<p>The approach in the article resonates with us: when solving our challenges, we too often use a combination of PHP and Go, gaining benefits from both languages without dismissing one for the other.<\/p>\n<p>Enjoy!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Over the past ten years, we have built applications for companies on the list of <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Fortune_Global_500\">Fortune 500<\/a><\/noindex>, as well as for businesses with an audience of no more than 500 users. Throughout this time, our engineers primarily developed the backend in PHP. But two years ago, something significantly impacted not only the performance of our products but also their scalability \u2014 we introduced Golang (Go) into our technology stack.<\/p>\n<p>Almost immediately, we found that Go allows us to create larger applications with performance increases of up to 40 times. It enabled us to extend existing PHP-based products, enhancing them through the combination of the advantages of both languages.<\/p>\n<p>We will discuss how the combination of Go and PHP helps solve real development problems and how it has become a tool for us to alleviate some issues related to <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/179399\/\">the 'dying' PHP model<\/a><\/noindex>.<\/p>\n<h3>Your everyday PHP development environment<\/h3>\n<p>\nBefore discussing how to revitalize the 'dying' PHP model with Go, let's look at your standard PHP development environment.<\/p>\n<p>In most cases, you run an application using a combination of the nginx web server and PHP-FPM. The former serves static files and redirects specific requests to PHP-FPM, which executes the PHP code. You might be using a less common combination of Apache and mod_php. However, while it operates a bit differently, the principles are the same.<\/p>\n<p>Let's see how PHP-FPM executes application code. When a request arrives, PHP-FPM initializes a child PHP process and passes the request details as part of its state (_GET, _POST, _SERVER, etc.). <\/p>\n<p>The state cannot change during the execution of a PHP script, so the only way to get a new set of input data is to clear the process memory and reinitialize it.<\/p>\n<p>This execution model has many advantages. You don't have to worry much about memory consumption, all processes are completely isolated, and if one 'dies', it will be automatically recreated without affecting the other processes. However, this approach also has drawbacks that become evident when trying to scale the application.<\/p>\n<h3>Drawbacks and Inefficiencies of a Standard PHP Environment<\/h3>\n<p>\nIf you're engaged in professional PHP development, you know that starting a new project begins with choosing a framework. It consists of libraries for dependency injection, ORMs, translations, and templates. And, of course, all incoming user data can be conveniently encapsulated in a single object (Symfony\/HttpFoundation or PSR-7). Frameworks are awesome!<\/p>\n<p>But everything has its price. In any enterprise-level framework, to handle a simple user request or database call, you will have to load at least dozens of files, create numerous classes, and parse multiple configurations. But worst of all, after each task, you will need to reset everything and start over: the code you just initialized becomes useless, and you can no longer process another request with it. Tell this to any programmer who writes in a different language, and you will see the confusion on their face.<\/p>\n<p>PHP engineers have been searching for ways to solve this problem for years, using thoughtful methods like 'lazy' loading, microframeworks, optimized libraries, caching, etc. But in the end, they still have to drop everything and start over, again and again.<i> (Translator's note: part of this issue will be resolved with the arrival of <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.php.net\/rfc\/preload\">preload<\/a><\/noindex> PHP 7.4)<\/p>\n<h3>Can PHP survive more than one request using Go?<\/h3>\n<p>\n<\/i>It's possible to write PHP scripts that last longer than just a few minutes (up to hours or days): for example, cron jobs, CSV parsers, queue processors. All of them follow the same pattern: they fetch a task, execute it, and wait for the next one. The code remains in memory, saving precious milliseconds, as loading the framework and application involves a lot of extra steps.<\/p>\n<p>However, developing long-lived scripts is not that simple. Any error completely wipes out the process, diagnosing memory leaks can drive you crazy, and using F5 for debugging is no longer an option.<\/p>\n<p>The situation improved with the release of PHP 7: a reliable garbage collector appeared, error handling became easier, and core extensions are now protected against leaks. Still, engineers must handle memory cautiously and remember about state issues in the code (is there any language where these things can be neglected?). Nonetheless, there are fewer surprises in PHP 7.<\/p>\n<p>Is it possible to take the model of long-lived PHP scripts, adapt it for more trivial tasks such as processing HTTP requests, and thus eliminate the need to load everything from scratch with each request?<\/p>\n<p>To solve this problem, it was first necessary to implement a server application capable of accepting HTTP requests and redirecting them one by one to a PHP worker without killing it each time.<\/p>\n<p>We knew we could write a web server in plain PHP (PHP-PM) or using a C extension (Swoole). While each method has its advantages, neither option satisfied us\u2014we wanted something more. We needed not just a web server, but a solution capable of freeing us from the problems associated with 'cold starts' in PHP, one that could be easily adapted and extended for specific applications. In other words, we needed an application server.<\/p>\n<p>Can Go help with this? We knew it could, because this language compiles applications into single binary files; it is cross-platform; it utilizes its own, very elegant concurrency model and an HTTP library; and finally, thousands of open-source libraries and integrations would be available to us.<\/p>\n<h3>The challenges of combining two programming languages<\/h3>\n<p>\nFirst, we needed to determine how multiple applications would communicate with each other.<\/p>\n<p>For example, using<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/deuill\/go-php\"> the excellent library<\/a><\/noindex> by Alex Paleystras, it was possible to implement shared memory between PHP and Go processes (analogous to mod_php in Apache). However, this library has certain features that limit its application for our task.<\/p>\n<p>We decided to use a different, more common approach: to build interaction between processes through sockets\/pipes. This approach has proven reliable over the past decades and has been well optimized at the operating system level.<\/p>\n<p>To start, we created a simple binary protocol for data exchange between processes and for error handling during transmission. At its simplest form, this type of protocol resembles <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Netstring\">netstring<\/a><\/noindex> with<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/prefix.go\"> with a fixed-size packet header<\/a><\/noindex> (in our case, 17 bytes), containing information about the packet type, its size, and a binary mask for data integrity checks.<\/p>\n<p>On the PHP side, we used <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/php-src\/SocketRelay.php#L247\">the pack function<\/a><\/noindex>, while on the Go side, we used the<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/prefix.go\"> encoding\/binary library.<\/a><\/noindex>.<\/p>\n<p>We found one protocol insufficient\u2014and we added the capability to invoke<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/codec.go\"> Go net\/rpc services directly from PHP<\/a><\/noindex>. This later proved to be very helpful during development, as we could easily integrate Go libraries into PHP applications. The result of this work can be seen, for example, in another one of our open-source products,<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\"> Goridge.<\/a><\/noindex>.<\/p>\n<h3>Task distribution among multiple PHP workers<\/h3>\n<p>\nAfter implementing the interaction mechanism, we started to think about how to efficiently pass tasks to PHP processes. When a task arrives, the application server must select a free worker for its execution. If a worker\/process finishes with an error or 'dies', we discard it and create a new one in its place. If a worker\/process completes successfully, we return it to the pool of available workers for task execution.<\/p>\n<p><img decoding=\"async\" alt=\"RoadRunner: PHP is not made to die, or Golang rushes to the rescue\" src=\"\/wp-content\/uploads\/2019\/06\/fe94ef304e0327247973ddd15723285a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTo store the pool of active workers, we used<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\/blob\/master\/static_pool.go\"> a buffered channel<\/a><\/noindex>, and to remove unexpectedly 'dead' workers from the pool, we added an error and state tracking mechanism.<\/p>\n<p>As a result, we obtained a functioning PHP server capable of handling any requests represented in binary format.<\/p>\n<p>In order for our application to function as a web server, we had to select a reliable PHP standard for representing any incoming HTTP requests. In our case, we simply <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\/blob\/master\/service\/http\/request.go\">transform<\/a><\/noindex> the net\/http request from Go into the format of<noindex><a rel=\"nofollow\" href=\"https:\/\/www.php-fig.org\/psr\/psr-7\/meta\/\"> PSR-7<\/a><\/noindex>, so that it would be compatible with most of the available PHP frameworks today.<\/p>\n<p>Since PSR-7 is considered immutable (some might argue that technically this is not the case), developers have to write applications that fundamentally do not treat the request as a global entity. This fits perfectly with the concept of long-lived PHP processes. Our final implementation, which still does not have a name, looked like this:<\/p>\n<p><img decoding=\"async\" alt=\"RoadRunner: PHP is not made to die, or Golang rushes to the rescue\" src=\"\/wp-content\/uploads\/2019\/06\/e3a3a1af1925dfc60b7f8fd256d1ae11.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Introducing RoadRunner \u2014<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\"> a high-performance PHP application server<\/a><\/noindex><\/h3>\n<p>\nOur first test task was an API backend, which periodically experienced unpredictable spikes in requests (much more frequently than usual). Although in most cases nginx's capabilities were sufficient, we regularly encountered a 502 error because we couldn't balance the system quickly enough under the expected load increase.<\/p>\n<p>To replace this solution, in early 2018, we deployed our first PHP\/Go application server. And we immediately saw incredible results! We not only completely eliminated the 502 error but also managed to reduce the number of servers by two-thirds, saving a lot of money and headache relief for engineers and product managers.<\/p>\n<p>By mid-year, we enhanced our solution, published it on GitHub under the MIT license, and named it <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\">RoadRunner<\/a><\/noindex>, highlighting its incredible speed and efficiency.<\/p>\n<h3>How RoadRunner Can Improve Your Development Stack<\/h3>\n<p>\nThe use of<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\"> RoadRunner<\/a><\/noindex> allowed us to use Middleware net\/http on the Go side to conduct JWT verification even before the request hits PHP, as well as to handle WebSockets and globally aggregate states into Prometheus. <\/p>\n<p>With built-in RPC, you can expose any Go library APIs to PHP without writing wrapper extensions. More importantly, RoadRunner can deploy new servers different from HTTP. For example, it allows launching PHP handlers<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\/wiki\/AWS-Lambda\"> AWS Lambda<\/a><\/noindex>, creating reliable queue parsers, and even adding<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/php-grpc\"> gRPC<\/a><\/noindex> to our applications.<\/p>\n<p>With the help of the PHP and Go communities, we increased the solution's stability, boosted application performance by up to 40 times in some tests, improved debugging tools, implemented integration with the Symfony framework, and added support for HTTPS, HTTP\/2, plugins, and PSR-17.<\/p>\n<h3>Conclusion<\/h3>\n<p>\nSome are still trapped in the outdated perception of PHP as a slow, cumbersome language suitable only for writing WordPress plugins. These individuals might even claim that PHP has such a limitation: when an application becomes large enough, one has to choose a more 'mature' language and rewrite a codebase accumulated over many years.<\/p>\n<p>To all this, we want to respond: think again. We believe that only you set some limitations for PHP. You can spend your entire life switching from one language to another, trying to find the perfect fit for your needs, or you can start viewing languages as tools. The perceived shortcomings of a language like PHP can actually be reasons for its success. And if you combine it with another language like Go, you will create much more powerful products than if you limited yourself to just one language.<\/p>\n<p>Having worked with the combination of Go and PHP, we can claim that we have fallen in love with them. We do not plan to sacrifice one for the other \u2014 on the contrary, we will seek ways to extract even more benefits from this dual stack.<\/p>\n<p><i>UPD: we welcome the creator of RoadRunner and co-author of the original article \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/users\/lachezis\/\" class=\"user_link\">Lachezis<\/a><\/noindex><\/i><br \/>\n<br \/>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/badoo\/blog\/434272\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u0432 Badoo \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043d\u0430\u0434 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e PHP, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0443 \u043d\u0430\u0441 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043d\u0430 \u044d\u0442\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u0438 \u0432\u043e\u043f\u0440\u043e\u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u2014 \u044d\u0442\u043e \u0432\u043e\u043f\u0440\u043e\u0441 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u0434\u0435\u043d\u0435\u0433. \u0411\u043e\u043b\u0435\u0435 \u0434\u0435\u0441\u044f\u0442\u0438 \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e PHP-FPM, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0441\u043e\u0431\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043f\u0430\u0442\u0447\u0435\u0439 \u0434\u043b\u044f PHP, \u0430 \u043f\u043e\u0437\u0436\u0435 \u0432\u043e\u0448\u0451\u043b \u0432 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0443\u044e \u043f\u043e\u0441\u0442\u0430\u0432\u043a\u0443. \u0417\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0433\u043e\u0434\u044b PHP \u0441\u0438\u043b\u044c\u043d\u043e [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":26762,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35722","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47RoadRunner: PHP \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043d, \u0447\u0442\u043e\u0431\u044b \u0443\u043c\u0438\u0440\u0430\u0442\u044c, \u0438\u043b\u0438 Golang \u0441\u043f\u0435\u0448\u0438\u0442 \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:05:58+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:05:58+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47RoadRunner: PHP is not meant to die, or Golang comes to the rescue | ProHoster","description":"Hello, Habr!","canonical_url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47RoadRunner: PHP \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043d, \u0447\u0442\u043e\u0431\u044b \u0443\u043c\u0438\u0440\u0430\u0442\u044c, \u0438\u043b\u0438 Golang \u0441\u043f\u0435\u0448\u0438\u0442 \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c | ProHoster","og:description":"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!","og:url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:05:58+00:00","article:modified_time":"2019-10-31T19:05:58+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35722","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 00:30:57","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:57:45","updated":"2026-01-22 00:30:57","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/35722","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=35722"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/35722\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media\/26762"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=35722"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=35722"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=35722"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}