diff --git a/src/httpc.c b/src/httpc.c
index 5d1d06a2d2480cd7314e784940d319ca55b08d77..59cc14b30647560b5722b0c510d4172c6738f7ec 100644
--- a/src/httpc.c
+++ b/src/httpc.c
@@ -169,6 +169,7 @@ httpc_request_new(struct httpc_env *env, const char *method,
 	curl_easy_setopt(req->curl_request.easy, CURLOPT_HEADERFUNCTION,
 			 curl_easy_header_cb);
 	curl_easy_setopt(req->curl_request.easy, CURLOPT_NOPROGRESS, 1L);
+	curl_easy_setopt(req->curl_request.easy, CURLOPT_NOSIGNAL, 1L);
 
 	ibuf_create(&req->body, &cord()->slabc, 1);
 
diff --git a/src/lib/core/CMakeLists.txt b/src/lib/core/CMakeLists.txt
index fa6e91079c403a28080dc8447396c3c9c9341f8a..f17ae163d87a69f57cdd1857572cf0286817c994 100644
--- a/src/lib/core/CMakeLists.txt
+++ b/src/lib/core/CMakeLists.txt
@@ -38,6 +38,7 @@ set(core_sources
     mp_datetime.c
     mp_interval.c
     prbuf.c
+    clock_lowres.c
 )
 
 if(ENABLE_TUPLE_COMPRESSION)
diff --git a/src/lib/core/clock_lowres.c b/src/lib/core/clock_lowres.c
new file mode 100644
index 0000000000000000000000000000000000000000..0ee899debd07797b8a4445b147ceb31980b2e563
--- /dev/null
+++ b/src/lib/core/clock_lowres.c
@@ -0,0 +1,98 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2010-2022, Tarantool AUTHORS, please see AUTHORS file.
+ */
+#include <signal.h>
+#include <string.h>
+#include <say.h>
+#include <pthread.h>
+#include "clock.h"
+#include "clock_lowres.h"
+
+#if defined(__APPLE__) || !defined(NDEBUG)
+/**
+ * A thread that initialized this module. Only owner thread
+ * is allowed to handle SIGALRM and use methods from this module.
+ */
+static pthread_t owner;
+
+/** Check if current thread is owner. */
+bool
+clock_lowres_thread_is_owner(void)
+{
+	return pthread_equal(owner, pthread_self());
+}
+#endif
+
+/** Resolution of clock (clock update period). */
+static const struct timeval resolution = {
+	.tv_sec = 0,
+	.tv_usec = 10 * 1e3,
+};
+
+double
+clock_lowres_resolution(void)
+{
+	return (double)resolution.tv_sec + resolution.tv_usec / 1e6;
+}
+
+/** Monotonic time, updated once every resolution of time unit. */
+double clock_lowres_monotonic_clock_value = 0.0;
+
+/** A tick of clock_lowres, SIGALRM handler. */
+static void
+clock_lowres_tick(int signum)
+{
+#ifdef __APPLE__
+	/**
+	 * We cannot guarantee that the signal is delivered
+	 * only to owner thread on MacOS. So use this workaround.
+	 * https://github.com/tarantool/tarantool/issues/7206
+	 */
+	if (!clock_lowres_thread_is_owner()) {
+		pthread_kill(owner, signum);
+		return;
+	}
+#else
+	(void)signum;
+	assert(clock_lowres_thread_is_owner());
+#endif
+	clock_lowres_monotonic_clock_value = clock_monotonic();
+}
+
+void
+clock_lowres_signal_init(void)
+{
+#if defined(__APPLE__) || !defined(NDEBUG)
+	owner = pthread_self();
+#endif
+	clock_lowres_monotonic_clock_value = clock_monotonic();
+	struct sigaction sa;
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = clock_lowres_tick;
+	sa.sa_flags = SA_RESTART;
+	if (sigaction(SIGALRM, &sa, NULL) == -1)
+		panic_syserror("cannot set low resolution clock timer signal");
+
+	struct itimerval timer;
+	timer.it_interval = resolution;
+	timer.it_value = resolution;
+	if (setitimer(ITIMER_REAL, &timer, NULL) == -1)
+		panic_syserror("cannot set low resolution clock timer");
+}
+
+void
+clock_lowres_signal_reset(void)
+{
+	struct itimerval timer;
+	memset(&timer, 0, sizeof(timer));
+	if (setitimer(ITIMER_REAL, &timer, NULL) == -1)
+		say_syserror("cannot reset low resolution clock timer");
+
+	struct sigaction sa;
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = SIG_DFL;
+	if (sigaction(SIGALRM, &sa, NULL) == -1)
+		say_syserror("cannot reset low resolution clock timer signal");
+}
diff --git a/src/lib/core/clock_lowres.h b/src/lib/core/clock_lowres.h
new file mode 100644
index 0000000000000000000000000000000000000000..732fc8349ba5dbbf577132cb95bfb60a8db79803
--- /dev/null
+++ b/src/lib/core/clock_lowres.h
@@ -0,0 +1,58 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2010-2022, Tarantool AUTHORS, please see AUTHORS file.
+ */
+#pragma once
+
+/**
+ * Monotonic low resolution clock, based on interval timer.
+ * Not thread-safe!
+ */
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#include <assert.h>
+#include <stdbool.h>
+
+/** Low resolution clock accumulator. */
+extern double clock_lowres_monotonic_clock_value;
+
+#ifndef NDEBUG
+
+/**
+ * Check that current thread is the thread
+ * that initialized this module.
+ */
+bool
+clock_lowres_thread_is_owner(void);
+
+#endif /* NDEBUG */
+
+/** Get resolution of clock_lowres clocks in double. */
+double
+clock_lowres_resolution(void);
+
+/**
+ * Blazingly fast low resolution monotonic time in seconds.
+ */
+static inline double
+clock_lowres_monotonic(void)
+{
+	assert(clock_lowres_thread_is_owner());
+	return clock_lowres_monotonic_clock_value;
+}
+
+/** Initialize signal handler and interval timer. */
+void
+clock_lowres_signal_init(void);
+
+/** Reset signal handler and interval timer. */
+void
+clock_lowres_signal_reset(void);
+
+#if __cplusplus
+}
+#endif
diff --git a/src/main.cc b/src/main.cc
index 444f4a1fa5583e105be8ad25fa26226984eef29c..67a9c41d0faad44fb9d5a723d03a2961a2f15772 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -85,6 +85,7 @@
 #include "core/crash.h"
 #include "ssl_cert_paths_discover.h"
 #include "core/errinj.h"
+#include "core/clock_lowres.h"
 
 static pid_t master_pid = getpid();
 static struct pidfh *pid_file_handle;
@@ -234,6 +235,7 @@ signal_reset(void)
 	    sigaction(SIGWINCH, &sa, NULL) == -1)
 		say_syserror("sigaction");
 
+	clock_lowres_signal_reset();
 	crash_signal_reset();
 
 	/* Unblock any signals blocked by libev. */
@@ -265,6 +267,7 @@ signal_init(void)
 	if (sigaction(SIGPIPE, &sa, 0) == -1)
 		panic_syserror("sigaction");
 
+	clock_lowres_signal_init();
 	crash_signal_init();
 
 	ev_signal_init(&ev_sigs[0], sig_checkpoint, SIGUSR1);
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index f01557871fdb0716dab3d9b7c3992c407ace50ee..71b31cca9bd6d36fdf5d148330cabde53c48cae5 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -98,6 +98,8 @@ add_executable(func_cache.test func_cache.c box_test_utils.c)
 target_link_libraries(func_cache.test box unit)
 add_executable(prbuf.test prbuf.c)
 target_link_libraries(prbuf.test unit core)
+add_executable(clock_lowres.test clock_lowres.c core_test_utils.c)
+target_link_libraries(clock_lowres.test unit core)
 
 if (NOT ENABLE_GCOV)
     # This test is known to be broken with GCOV
diff --git a/test/unit/clock_lowres.c b/test/unit/clock_lowres.c
new file mode 100644
index 0000000000000000000000000000000000000000..34185b781e9cefc5352130d6ef6fa6d8eea658fd
--- /dev/null
+++ b/test/unit/clock_lowres.c
@@ -0,0 +1,43 @@
+#include "unit.h"
+
+#include <math.h>
+#include <unistd.h>
+#include "clock_lowres.h"
+#include "clock.h"
+
+/** Test duration in seconds. */
+#define TEST_LEN 1.5
+
+int
+main(void)
+{
+	plan(1);
+	clock_lowres_signal_init();
+
+	/* Such a large resolution to pass the test in debug or apple build. */
+	double resolution = clock_lowres_resolution() * 2;
+	bool success = true;
+	double start = clock_monotonic();
+	double clock = start;
+	while (clock < start + TEST_LEN) {
+		/*
+		 * Use pause before getting time so that the process
+		 * does not use all time and unlikely to be
+		 * rescheduled in the middle of check.
+		 * The process will wake up after receiving a signal:
+		 * the clock receives SIGALRM every resolution seconds.
+		 */
+		pause();
+		double lowres = clock_lowres_monotonic();
+		clock = clock_monotonic();
+		if (fabs(clock - lowres) > resolution) {
+			success = false;
+			break;
+		}
+	}
+	ok(success, "Check that monotonic lowres clock does not diverge "
+		    "too much from monotonic clock");
+
+	clock_lowres_signal_reset();
+	return check_plan();
+}
diff --git a/test/unit/clock_lowres.result b/test/unit/clock_lowres.result
new file mode 100644
index 0000000000000000000000000000000000000000..da595335e514fe500954ec13c5d3f906dfc6b143
--- /dev/null
+++ b/test/unit/clock_lowres.result
@@ -0,0 +1,2 @@
+1..1
+ok 1 - Check that monotonic lowres clock does not diverge too much from monotonic clock