{"id":1991,"date":"2021-09-02T05:34:37","date_gmt":"2021-09-02T05:34:37","guid":{"rendered":"https:\/\/www.hostinger.com\/blog\/?p=1991"},"modified":"2022-07-11T09:39:35","modified_gmt":"2022-07-11T09:39:35","slug":"cloudprober-explained-the-way-we-use-it-at-hostinger","status":"publish","type":"post","link":"https:\/\/www.hostinger.com\/blog\/cloudprober-explained-the-way-we-use-it-at-hostinger","title":{"rendered":"Cloudprober Explained: The Way We Use It at Hostinger"},"content":{"rendered":"<p>Cloudprober is software used to monitor the availability and performance of various components of a system. Here at Hostinger, we use it to monitor the load time of our customers&rsquo; websites. Initially, it began as a free open-source application by Google to help customers monitor their projects or infrastructures.<\/p><p>Cloudprober&rsquo;s main task is to run probes<em>,<\/em> which are meant to investigate protocols such as HTTP, Ping, UDP, DNS to verify that the systems work as expected from the customer&rsquo;s point of view. It&rsquo;s even possible to have a specific custom probe (e.g. Redis or MySQL) via an external <a href=\"https:\/\/cloudprober.org\/how-to\/external-probe\/\" target=\"_blank\" rel=\"noopener\">API<\/a>. Hostinger focuses on the HTTP probe.&nbsp;&nbsp;<\/p><div class=\"wp-block-image\">\n<figure class=\"alignright size-large is-resized\"><img decoding=\"async\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/4\/2021\/09\/Cloudprober.png\/public\" alt=\"\" class=\"wp-image-1981\" width=\"431\" height=\"337\" srcset=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/4\/2021\/09\/Cloudprober.png\/w=1288,fit=scale-down 1288w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/4\/2021\/09\/Cloudprober.png\/w=300,fit=scale-down 300w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/4\/2021\/09\/Cloudprober.png\/w=1024,fit=scale-down 1024w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/4\/2021\/09\/Cloudprober.png\/w=768,fit=scale-down 768w\" sizes=\"(max-width: 431px) 100vw, 431px\" \/><figcaption>&nbsp;Source: <a href=\"https:\/\/cloudprober.org\/\" target=\"_blank\" rel=\"noopener\">https:\/\/cloudprober.org\/<\/a><\/figcaption><\/figure><\/div><h2 class=\"wp-block-heading\" id=\"h-probe-settings\"><strong>Probe Settings<\/strong><\/h2><p>Every probe is defined as the combination of these particular <a href=\"https:\/\/cloudprober.org\/concepts\/probe\/\" target=\"_blank\" rel=\"noopener\">settings<\/a>:<\/p><ul class=\"wp-block-list\"><li><strong>Type<\/strong> &ndash; for example, HTTP, PING, or UDP.<\/li><li><strong>Name<\/strong> &ndash; each probe needs to have a unique name.<\/li><li><strong>Interval_msec<\/strong> &ndash; describes how often to run the probe (in milliseconds).<\/li><li><strong>Timeout_msec<\/strong> &ndash; probe timeout (in milliseconds).<\/li><li><strong>Targets<\/strong> &ndash; targets to run the probe against.<\/li><li><strong>Validator<\/strong> &ndash; probe validators.<\/li><li><strong>&lt;type&gt;_probe<\/strong> &ndash; the probe type-specific configuration.<\/li><\/ul><h2 class=\"wp-block-heading\" id=\"h-surfacers\"><strong>Surfacers<\/strong><\/h2><p><a href=\"https:\/\/cloudprober.org\/surfacers\/overview\/\" target=\"_blank\" rel=\"noopener\">Surfacers<\/a> are built-in mechanisms designed to export data to multiple monitoring systems. Multiple surfacers can be configured at the same time. Cloudprober mainly aims to run probes and build standard usable metrics based on the results of those probes. Thus, it provides a user-friendly interface that makes probe data available to systems that offer ways to quantify monitoring data.<\/p><p>Currently, Cloudprober supports the following surfacer types: <a href=\"https:\/\/cloudprober.org\/surfacers\/stackdriver\/\" target=\"_blank\" rel=\"noopener\">Stackdriver<\/a> (Google Cloud Monitoring), <a href=\"https:\/\/github.com\/google\/cloudprober\/blob\/master\/surfacers\/prometheus\/proto\/config.proto\" target=\"_blank\" rel=\"noopener\">Prometheus<\/a>, <a href=\"https:\/\/cloudprober.org\/surfacers\/cloudwatch\/\" target=\"_blank\" rel=\"noopener\">Cloudwatch<\/a> (AWS Cloud Monitoring), <a href=\"https:\/\/github.com\/google\/cloudprober\/blob\/master\/surfacers\/pubsub\/proto\/config.proto\" target=\"_blank\" rel=\"noopener\">Google Pub\/Sub<\/a>, <a href=\"https:\/\/github.com\/google\/cloudprober\/blob\/master\/surfacers\/file\/proto\/config.proto\" target=\"_blank\" rel=\"noopener\">File<\/a>, and <a href=\"https:\/\/github.com\/google\/cloudprober\/blob\/master\/surfacers\/postgres\/proto\/config.proto\" target=\"_blank\" rel=\"noopener\">Postgres<\/a>.<\/p><h2 class=\"wp-block-heading\" id=\"h-validators\"><strong>Validators<\/strong><\/h2><p>Cloudprober <a href=\"https:\/\/cloudprober.org\/how-to\/validators\/\" target=\"_blank\" rel=\"noopener\">validators<\/a> permit to run checks on probe request outputs if there are any. More than one validator can be configured, but all of them have to succeed for the probe to be marked as successful.&nbsp;<\/p><p>The <strong>Regex validator<\/strong> is the most common one, working with the majority of probe types. When you load the site and expect some string in it, the Regex Validator helps you make it dynamic.&nbsp;<\/p><p>The <strong>HTTP validator<\/strong>, which is only applicable for the HTTP probe type, helps to check the Header (success\/fail) and Status code (success\/fail).&nbsp;<\/p><p>Lastly, the <strong>Data integrity validator<\/strong> is mainly used for UDP or PINGS when we expect to see data in some repeating pattern (for example, <em>1,2,3,1,2,3,1,2,3<\/em> in the payload).&nbsp;<\/p><h2 class=\"wp-block-heading\" id=\"h-targets-discovery\"><strong>Targets Discovery<\/strong><\/h2><p>As it is cloud-based software, Cloudprober has support for <strong>targets auto-discovery.<\/strong> It is currently considered one of the most critical features &ndash; with it, Cloudprober can touch data from Kubernetes, Google Cloud Engine, AWS EC2, file discovery, and more. If that is not enough, it also has an internal discovery service, so you can integrate other discoveries into your infrastructure.<\/p><p>The core idea behind Clouprober&rsquo;s targets discovery is using an independent source to clarify the targets that are supposed to be monitored. More information about the salient features of Cloudprober&rsquo;s targets discovery can be found <a href=\"https:\/\/cloudprober.org\/concepts\/targets\/\" target=\"_blank\" rel=\"noopener\">here<\/a>.&nbsp;<\/p><h2 class=\"wp-block-heading\" id=\"h-why-hostinger-chose-cloudprober\"><strong>Why Hostinger Chose Cloudprober<\/strong><\/h2><p>In October 2020, Hostinger was looking for an external monitoring system to gather uptime and speed statistics from all user websites. Consul (Blackbox consul website) was considered as one of the main ways to monitor sites. However, Cloudprober looked like a promising lightweight option that had Stackdriver integration, which allowed it to easily store logs, had no performance constraints, and could be accessed by the Data Team with no additional requirements.&nbsp;<\/p><p>Here are some factors as to why we have chosen Cloudprober as the preferred alternative:<\/p><ul class=\"wp-block-list\"><li><strong>Headless and lightweight. <\/strong>Most alternatives we&rsquo;ve looked at have a full solution regarding the custom problem they try to solve &ndash; web interface, user management, custom graphing, forced backed\/database solution, etc.<strong> <\/strong>Cloudprober only does one thing &ndash; launches and measures probes. The workflow is designed to be simple and lightweight to keep resource usage low. Deployment is just one single statically linked binary (thanks to Golang).<\/li><li><strong>Compossible. <\/strong>Advantageous baked-in tools are included in this monitoring software. However, additional configurations can be initiated to do more.&nbsp;<\/li><li><strong>Extensible. <\/strong>The extensible nature of Cloudprober allows users to add features to the tool if required to better fit their individual needs. Also, extensive support documentation and a community of users is available.&nbsp;<\/li><li><strong>Live and maintainable. <\/strong>Before committing to a technology it is wise to determine whether its GitHub projects are still active. Another factor is determining how community-oriented it is, including metrics such as its issue and PR count, external contributors, and overall activity. Cloudprober passed all of these.<\/li><li><strong>Supports all modern ecosystems. <\/strong>Cloudprober, as the name would suggest, was designed for cloud native applications since day one. It can be run as a container (k8s), supports most public cloud providers for metadata and target discovery, and is easily integratable with modern toolings like Prometheus and Grafana. <a href=\"https:\/\/www.hostinger.com\/blog\/awex-ipv6\">IPv6<\/a> is not a problem for Coudprober either.<\/li><\/ul><h2 class=\"wp-block-heading\" id=\"h-testing-to-check-if-it-works-for-hostinger\"><strong>Testing to Check if It Works for Hostinger<\/strong><\/h2><p>We tested Cloudprober thoroughly at Hostinger. To decide whether Cloudprober meets our needs, we checked the metric fidelity and possible setup\/configuration scenarios for our scale.<\/p><p>We tried changing the Cloudprober code to add basic concurrency control. Different patterns were attempted to keep moderate load during latency measurement &ndash; a concurrency of 5+5 (HTTP+HTTPS). On largely loaded servers, it took approximately 30 minutes to crawl around 3,900 HTTPS sites, and approximately 70 minutes to do the same for around 7,100 HTTP sites.<\/p><p>The main challenge that we recognized was probe spreading &ndash; Cloudprober waits for a configured check interval and starts all the probes at the same time. We did not see it as a huge problem for Cloudprober itself as Consul, Prometheus, and Blackbox Exporter share the same feature, but this may have an impact on the whole hosting server.&nbsp;<\/p><p>Later on, Cloudprober was launched on approximately 1,8 million sites, and we found out that a GCP instance with 8 cores and 32GiB of RAM can handle it well (60% idle CPU).&nbsp;<\/p><h2 class=\"wp-block-heading\" id=\"h-how-we-use-cloudprober-at-hostinger\"><strong>How We Use Cloudprober at Hostinger<\/strong><\/h2><p>Here at Hostinger, HTTP metrics are pushed to PostgreSQL (technically, CloudSQL on GCP). Metric filtering is used and Cloudprober&rsquo;s internal metrics are exported to the Prometheus surfacer. To check whether the sites are actually hosted with us, we send a specific header to every site and expect another header response.&nbsp;<\/p><h3 class=\"wp-block-heading\"><strong>Metric Output (Surfacers)<\/strong><\/h3><p>Initially, we thought that we would use a Prometheus surfacer. However, all collected metrics were around 1GB in size. This was too much for our Prometheus + M3DB system. While it&rsquo;s possible to make it work, it&rsquo;s not worth it. Therefore, we decided to move forward with PostgreSQL. We also evaluated Stackdriver, but PostgreSQL was a better fit for our tooling and purposes.<\/p><p>By default, the Cloudprober PostgreSQL surfacer expects this kind of table:<\/p><pre class=\"wp-block-code\"><code>CREATE TABLE metrics (\n  time TIMESTAMP WITH TIME ZONE,\n  metric_name text NOT NULL,\n  value DOUBLE PRECISION,\n  labels jsonb,\n  PRIMARY KEY (time, metric_name, labels)\n);<\/code><\/pre><p>There are a few drawbacks with this kind of storage:<\/p><ol class=\"wp-block-list\"><li>All labels are placed in the <em>jsonb<\/em> type.<\/li><li>The <em>jsonb<\/em> type is not index-friendly nor easy to query.<\/li><li>More data is stored than we need.<\/li><li>All data is collected in one big table which is not easy to maintain.<\/li><li>All data stored as strings which takes up lots of storage.<\/li><\/ol><p>At first, we mangled all the inserts into a table. PostgreSQL (and many other <a href=\"https:\/\/en.wikipedia.org\/wiki\/Relational_database\" target=\"_blank\" rel=\"noopener\">RDMS<\/a>) features a powerful technique &ndash; <a href=\"https:\/\/en.wikipedia.org\/wiki\/Database_trigger\" target=\"_blank\" rel=\"noopener\">triggers<\/a>. Another notable technique is called <a href=\"https:\/\/www.postgresql.org\/docs\/current\/datatype-enum.html\" target=\"_blank\" rel=\"noopener\">enums<\/a> and it allows storing &ldquo;string-like&rdquo; data in a compact way (4 bytes per item). By combining these two with <a href=\"https:\/\/www.postgresql.org\/docs\/13\/ddl-partitioning.html\" target=\"_blank\" rel=\"noopener\">partitioning<\/a>, we solved all of the drawbacks mentioned above.<\/p><p>We created two custom data types:<\/p><pre class=\"wp-block-code\"><code>CREATE TYPE http_scheme AS ENUM (\n  'http',\n  'https'\n);<\/code><\/pre><pre class=\"wp-block-code\"><code>CREATE TYPE metric_names AS ENUM (\n  'success',\n  'timeouts',\n  'latency',\n  'resp-code',\n  'total',\n  'validation_failure',\n  'external_ip',\n  'goroutines',\n  'hostname',\n  'uptime_msec',\n  'cpu_usage_msec',\n  'instance',\n  'instance_id',\n  'gc_time_msec',\n  'mem_stats_sys_bytes',\n  'instance_template',\n  'mallocs',\n  'frees',\n  'internal_ip',\n  'nic_0_ip',\n  'project',\n  'project_id',\n  'region',\n  'start_timestamp',\n  'version',\n  'machine_type',\n  'zone'\n);<\/code><\/pre><p>We created a data insert function for the trigger:<\/p><pre class=\"wp-block-code\"><code>CREATE OR REPLACE FUNCTION insert_fnc()\n  RETURNS trigger AS\n  $$\nBEGIN\n\n  IF new.labels-&gt;&gt;'dst' IS NULL THEN\n\tRETURN NULL;\n  END IF;\n\n  new.scheme = new.labels-&gt;&gt;'scheme';\n  new.vhost = rtrim(new.labels-&gt;&gt;'dst', '.');\n  new.server = new.labels-&gt;&gt;'server';\n\n  IF new.labels ? 'code' THEN\n\tnew.code = new.labels-&gt;&gt;'code';\n  END IF;\n\n  new.labels = NULL;\n\n  RETURN new;\nEND;\n$$\nLANGUAGE 'plpgsql';<\/code><\/pre><p>And the main table:<\/p><pre class=\"wp-block-code\"><code>CREATE TABLE metrics (\n  time TIMESTAMP WITH TIME ZONE,\n  metric_name metric_names NOT NULL,\n  scheme http_scheme NOT NULL,\n  vhost text NOT NULL,\n  server text NOT NULL,\n  value DOUBLE PRECISION,\n  labels jsonb,\n  code smallint\n) PARTITION BY RANGE (time);<\/code><\/pre><p>For partition creation, we can use the following script (creates partitions for next 28 days and attaches the trigger):<\/p><pre class=\"wp-block-preformatted\">DO\n$$\nDECLARE\n  f record;\n  i interval := '1 day';\nBEGIN\n  FOR f IN SELECT t as int_start, t+i as int_end, to_char(t, '\"y\"YYYY\"m\"MM\"d\"DD') as table_name\n\tFROM generate_series (date_trunc('day', now() - interval '0 days'), now() + interval '28 days' , i) t\n\tLOOP\n     RAISE notice 'table: % (from % to % [interval: %])', f.table_name, f.int_start, f.int_end, i;\n\tEXECUTE 'CREATE TABLE IF NOT EXISTS  m_' || f.table_name || ' PARTITION OF m FOR VALUES FROM (''' || f.int_start || ''') TO (''' || f.int_end || ''')';\n\tEXECUTE 'CREATE TRIGGER m_' || f.table_name || '_ins BEFORE INSERT ON m_' || f.table_name || ' FOR EACH ROW EXECUTE FUNCTION insert_fnc()';\n  END LOOP;\nEND;\n$$\nLANGUAGE 'plpgsql';<\/pre><p>We are currently in the process of automatically performing host monitoring by taking all host and website information from the Consul and using consul-template to generate a dynamic configuration.&nbsp;<\/p><p>We partition data by day for reason management and lockless operations. We also use PostgreSQL triggers and enums to filter, rewrite, and de-jsonb rows to save storage space (up to 10x savings) and speed things up. The Data Team imports such data from PostgreSQL into BigQuery and uses data mangling or modification to meet our needs.&nbsp;<\/p><p>How would the actual configuration look? The dynamic data from the consul-template is seen in the file path, and Cloudprober will re-read this file in 600 seconds, so one file with all the targets that have labels for the probe will be filtered out. Also, we use &ldquo;allow_metrics_with_label&rdquo; to expose different types of metrics to different surfacers. Prometheus &ndash; for Cloudprober itself, and PostgreSQL for probes. To save network bandwidth, we use the HTTP HEAD method. Not all our customers have up-to-date TLS certificates, so we have to skip validity checks for them.<\/p><h4 class=\"wp-block-heading\"><strong>Cloudprober.cfg:<\/strong><\/h4><pre class=\"wp-block-code\"><code>disable_jitter: true\n\nprobe {\n\tname: \"server1.hostinger.com-HTTP\"\n\ttype: HTTP\n\n\ttargets {\n  \trds_targets {\n    \tresource_path: \"file:\/\/\/tmp\/targets.textpb\"\n    \tfilter {\n      \tkey: \"labels.probe\",\n      \tvalue: \"server1.hostinger.com-HTTP\"\n    \t}\n  \t}\n\t}\n\n\thttp_probe {\n    \tprotocol: HTTP\n    \tport: 80\n    \tresolve_first: false\n    \trelative_url: \"\/\"\n    \tmethod: HEAD\n    \tinterval_between_targets_msec: 1000\n\n    \ttls_config {\n     \tdisable_cert_validation: true\n    \t}\n\n    \theaders: {\n      \tname: \"x-some-request-header\"\n      \tvalue: \"request-value\"\n    \t}\n\t}\n\n\tadditional_label {\n    \tkey: \"server\"\n    \tvalue: \"server1.hostinger.com\"\n\t}\n\n\tadditional_label {\n    \tkey: \"scheme\"\n    \tvalue: \"http\"\n\t}\n\n\tinterval_msec: 57600000\n\ttimeout_msec: 10000\n\n\tvalidator {\n  \tname: \"challenge-is-valid\"\n  \thttp_validator {\n    \tsuccess_header: {\n      \tname: \"x-some-response-header\"\n      \tvalue: \"header-value\"\n    \t}\n  \t}\n\t}\n}\n\nsurfacer {\n\ttype: PROMETHEUS\n\tprometheus_surfacer {\n    \tmetrics_buffer_size: 100000\n    \tmetrics_prefix: \"cloudprober_\"\n\t}\n\n\tallow_metrics_with_label {\n  \tkey: \"ptype\",\n  \tvalue: \"sysvars\",\n\t}\n}\n\nsurfacer {\n\ttype: POSTGRES\n\tpostgres_surfacer {\n  \tconnection_string: \"postgresql:\/\/example:password@localhost\/cloudprober?sslmode=disable\"\n  \tmetrics_table_name: \"metrics\"\n  \tmetrics_buffer_size: 120000\n   }\n\n   allow_metrics_with_label {\n  \tkey: \"ptype\",\n  \tvalue: \"http\",\n   }\n}\n\nrds_server {\n  provider {\n\tfile_config {\n  \tfile_path: \"\/tmp\/targets.textpb\"\n  \tre_eval_sec: 600\n\t}\n  }\n}<\/code><\/pre><h4 class=\"wp-block-heading\"><strong>\/tmp\/targets.textpb example:<\/strong><\/h4><pre class=\"wp-block-code\"><code>resource {\nname: \"hostinger.com.\"\nlabels {\n\tkey: \"probe\"\n\tvalue: \"server1.hostinger.com-HTTP\"\n  }\n}<\/code><\/pre><p>We only have a single request pending to meet our needs to use Cloudprober properly, and Cloudprober runs on a single instance of 8x 2.20GHz and 32 GiB RAM.<\/p><p><strong>Sources For Further Interest<\/strong><\/p><p>Interested in giving it a try and exploring Cloudprober&rsquo;s possibilities? We recommend checking the following sites out:<\/p><ul class=\"wp-block-list\"><li><a href=\"https:\/\/cloudprober.org\/getting-started\/\" target=\"_blank\" rel=\"noopener\">https:\/\/cloudprober.org\/getting-started\/<\/a><\/li><li><a href=\"https:\/\/opensource.googleblog.com\/2018\/03\/cloudprober-open-source-black-box.html\" target=\"_blank\" rel=\"noopener\">https:\/\/opensource.googleblog.com\/2018\/03\/cloudprober-open-source-black-box.html<\/a><\/li><li><a href=\"https:\/\/medium.com\/dm03514-tech-blog\/sre-availability-probing-101-using-googles-cloudprober-8c191173923c\" target=\"_blank\" rel=\"noopener\">https:\/\/medium.com\/dm03514-tech-blog\/sre-availability-probing-101-using-googles-cloudprober-8c191173923c<\/a><\/li><\/ul><p><strong>Commits<\/strong><\/p><ul class=\"wp-block-list\"><li><a href=\"https:\/\/github.com\/google\/cloudprober\/commit\/3d5080b5dd0ee6a23395e6cf42a24c3e10557c2d\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/google\/cloudprober\/commit\/3d5080b5dd0ee6a23395e6cf42a24c3e10557c2d<\/a><\/li><li><a href=\"https:\/\/github.com\/google\/cloudprober\/commit\/9f817036c98755d1f8da12b48b0ba00dbf331380\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/google\/cloudprober\/commit\/9f817036c98755d1f8da12b48b0ba00dbf331380<\/a><\/li><li><a href=\"https:\/\/github.com\/google\/cloudprober\/commit\/a1da1cd837b40598b3d9869b5ff2d8871ae38ea2\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/google\/cloudprober\/commit\/a1da1cd837b40598b3d9869b5ff2d8871ae38ea2<\/a><\/li><li><a href=\"https:\/\/github.com\/google\/cloudprober\/commit\/9674ae27076360098bc178330cc05191cb17ee89\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/google\/cloudprober\/commit\/9674ae27076360098bc178330cc05191cb17ee89<\/a><\/li><li><a href=\"https:\/\/github.com\/google\/cloudprober\/commit\/0618ca6fe240a579400b153982fb383dc2df4dd6\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/google\/cloudprober\/commit\/0618ca6fe240a579400b153982fb383dc2df4dd6<\/a><\/li><li><a href=\"https:\/\/github.com\/google\/cloudprober\/commit\/a173510c80b854923366278d93fbc079c406e1fb\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/google\/cloudprober\/commit\/a173510c80b854923366278d93fbc079c406e1fb<\/a><\/li><li><a href=\"https:\/\/github.com\/google\/cloudprober\/commit\/5aef6ad1aea957a01f6c690edde70a63136b3a6b\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/google\/cloudprober\/commit\/5aef6ad1aea957a01f6c690edde70a63136b3a6b<\/a><\/li><li><a href=\"https:\/\/github.com\/google\/cloudprober\/commit\/adab69a51b5059acd85e1f1940d7a3fc8a4b759b\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/google\/cloudprober\/commit\/adab69a51b5059acd85e1f1940d7a3fc8a4b759b<\/a><\/li><li><a href=\"https:\/\/github.com\/google\/cloudprober\/commit\/684c9ce87416813cc523f07b7f9fb9a84abfc81e\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/google\/cloudprober\/commit\/684c9ce87416813cc523f07b7f9fb9a84abfc81e<\/a><\/li><li><\/ul><p><strong><em>This article was inspired by our R&amp;D Engineer presentation on Cloudprober and its usage at Hostinger.&nbsp;<\/em><\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cloudprober is software used to monitor the availability and performance of various components of a system. Here at Hostinger, we use it to monitor the load time of our customers&#8217;\u2026<\/p>\n","protected":false},"author":213,"featured_media":1982,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[82],"tags":[2246,264,2248,2247],"hashtags":[],"class_list":["post-1991","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering","tag-cloudprober","tag-hostinger","tag-monitoring-software","tag-probe"],"hreflangs":[],"_links":{"self":[{"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/posts\/1991","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/users\/213"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/comments?post=1991"}],"version-history":[{"count":59,"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/posts\/1991\/revisions"}],"predecessor-version":[{"id":3441,"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/posts\/1991\/revisions\/3441"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/media\/1982"}],"wp:attachment":[{"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/media?parent=1991"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/categories?post=1991"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/tags?post=1991"},{"taxonomy":"hashtags","embeddable":true,"href":"https:\/\/www.hostinger.com\/blog\/wp-json\/wp\/v2\/hashtags?post=1991"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}