diff --git a/.env.example b/.env.example
index a657413fbab84166dc7b4b7f96af819494904f00..d0b8b81bcfa87727379ddd8c9db66e8032235303 100644
--- a/.env.example
+++ b/.env.example
@@ -15,7 +15,7 @@ REDIS_RESULT_CONNECTION=default
 REDIS_RESULT_CACHE_DURATION=60
 
 BROADCAST_DRIVER=log
-CACHE_DRIVER=file
+CACHE_DRIVER=database
 SESSION_DRIVER=file
 QUEUE_CONNECTION=sync
 
diff --git a/app/CacheHelper.php b/app/CacheHelper.php
deleted file mode 100644
index 3a4aeaae55015b4c26f40d5ae2ebd0ed927a4d05..0000000000000000000000000000000000000000
--- a/app/CacheHelper.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-namespace App;
-
-use Illuminate\Support\Facades\Redis;
-
-class CacheHelper
-{
-
-    /**
-     * MetaGer uses a pretty slow harddrive for the configured cache
-     * That's why we have some processes running to write cache to disk in parallel
-     */
-    public static function put($key, $value, $timeSeconds)
-    {
-        $cacherItem = [
-            'timeSeconds' => $timeSeconds,
-            'key' => $key,
-            'value' => $value,
-        ];
-        Redis::rpush(\App\Console\Commands\RequestCacher::CACHER_QUEUE, base64_encode(serialize($cacherItem)));
-
-    }
-}
diff --git a/app/Console/Commands/RequestCacher.php b/app/Console/Commands/RequestCacher.php
deleted file mode 100644
index bf52f428edd9f6474fb1c89b79a43f1b584ce5b4..0000000000000000000000000000000000000000
--- a/app/Console/Commands/RequestCacher.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Cache;
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Redis;
-
-class RequestCacher extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'requests:cacher';
-
-    const CACHER_QUEUE = 'cacher.queue';
-    protected $shouldRun = true;
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Listens to a buffer of fetched search results and writes them to the filesystem cache.';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return mixed
-     */
-    public function handle()
-    {
-        pcntl_async_signals(true);
-        pcntl_signal(SIGINT, [$this, "sig_handler"]);
-        pcntl_signal(SIGTERM, [$this, "sig_handler"]);
-        pcntl_signal(SIGHUP, [$this, "sig_handler"]);
-
-        while ($this->shouldRun) {
-            $cacheItem = Redis::blpop(self::CACHER_QUEUE, 1);
-            if (!empty($cacheItem)) {
-                $cacheItem = unserialize(base64_decode($cacheItem[1]));
-                if (empty($cacheItem["value"])) {
-                    $cacheItem["value"] = "no-result";
-                }
-                Cache::put($cacheItem["key"], $cacheItem["value"], now()->addSeconds($cacheItem["timeSeconds"]));
-            }
-        }
-    }
-
-    public function sig_handler($sig)
-    {
-        $this->shouldRun = false;
-        echo ("Terminating Cacher Process\n");
-    }
-}
diff --git a/app/Console/Commands/RequestFetcher.php b/app/Console/Commands/RequestFetcher.php
index 3af939a7ea2fc5611ce71bd1842361cc4b745a17..9b986603af972b57e341d7327218940608b28bec 100644
--- a/app/Console/Commands/RequestFetcher.php
+++ b/app/Console/Commands/RequestFetcher.php
@@ -2,7 +2,7 @@
 
 namespace App\Console\Commands;
 
-use Artisan;
+use Cache;
 use Illuminate\Console\Command;
 use Illuminate\Support\Facades\Redis;
 use Log;
@@ -51,23 +51,11 @@ class RequestFetcher extends Command
     public function handle()
     {
         $pids = [];
-        $pid = null;
-        for ($i = 0; $i < 5; $i++) {
-            $pid = \pcntl_fork();
-            $pids[] = $pid;
-            if ($pid === 0) {
-                break;
-            }
-        }
-        if ($pid === 0) {
-            Artisan::call('requests:cacher');
-            exit;
-        } else {
-            pcntl_async_signals(true);
-            pcntl_signal(SIGINT, [$this, "sig_handler"]);
-            pcntl_signal(SIGTERM, [$this, "sig_handler"]);
-            pcntl_signal(SIGHUP, [$this, "sig_handler"]);
-        }
+
+        pcntl_async_signals(true);
+        pcntl_signal(SIGINT, [$this, "sig_handler"]);
+        pcntl_signal(SIGTERM, [$this, "sig_handler"]);
+        pcntl_signal(SIGHUP, [$this, "sig_handler"]);
 
         try {
             $blocking = false;
@@ -115,12 +103,7 @@ class RequestFetcher extends Command
                     Redis::pipeline(function ($pipe) use ($resulthash, $body, $cacheDurationMinutes) {
                         $pipe->set($resulthash, $body);
                         $pipe->expire($resulthash, 60);
-                        $cacherItem = [
-                            'timeSeconds' => $cacheDurationMinutes * 60,
-                            'key' => $resulthash,
-                            'value' => $body,
-                        ];
-                        $pipe->rpush(\App\Console\Commands\RequestCacher::CACHER_QUEUE, base64_encode(serialize($cacherItem)));
+                        Cache::put($resulthash, $body, $cacheDurationMinutes * 60);
                     });
                     \curl_multi_remove_handle($this->multicurl, $info["handle"]);
                 }
diff --git a/app/Http/Controllers/MetaGerSearch.php b/app/Http/Controllers/MetaGerSearch.php
index 134b92beda984904081629189b197779d9318470..191cbd0cf174d5513f5b547f82f571582555b949 100644
--- a/app/Http/Controllers/MetaGerSearch.php
+++ b/app/Http/Controllers/MetaGerSearch.php
@@ -11,8 +11,13 @@ use View;
 
 class MetaGerSearch extends Controller
 {
-    public function search(Request $request, MetaGer $metager)
+
+    public function search(Request $request, MetaGer $metager, $timing = false)
     {
+        $timings = null;
+        if ($timing) {
+            $timings = ['starttime' => microtime(true)];
+        }
         $time = microtime(true);
         $spamEntries = [];
         if (file_exists(config_path('spam.txt'))) {
@@ -34,9 +39,15 @@ class MetaGerSearch extends Controller
 
         # Mit gelieferte Formulardaten parsen und abspeichern:
         $metager->parseFormData($request);
+        if (!empty($timings)) {
+            $timings["parseFormData"] = microtime(true) - $time;
+        }
 
         # Nach Spezialsuchen überprüfen:
         $metager->checkSpecialSearches($request);
+        if (!empty($timings)) {
+            $timings["checkSpecialSearches"] = microtime(true) - $time;
+        }
 
         if (Cache::has('spam.' . $metager->getFokus() . "." . md5($metager->getQ()))) {
             return response(Cache::get('spam.' . $metager->getFokus() . "." . md5($metager->getEingabe())));
@@ -44,24 +55,43 @@ class MetaGerSearch extends Controller
 
         # Die Quicktips als Job erstellen
         $quicktips = $metager->createQuicktips();
+        if (!empty($timings)) {
+            $timings["createQuicktips"] = microtime(true) - $time;
+        }
 
         # Suche für alle zu verwendenden Suchmaschinen als Job erstellen,
         # auf Ergebnisse warten und die Ergebnisse laden
-        $metager->createSearchEngines($request);
+        $metager->createSearchEngines($request, $timings);
 
-        $metager->startSearch();
+        $metager->startSearch($timings);
 
         $metager->waitForMainResults();
+        if (!empty($timings)) {
+            $timings["waitForMainResults"] = microtime(true) - $time;
+        }
 
         $metager->retrieveResults();
+        if (!empty($timings)) {
+            $timings["retrieveResults"] = microtime(true) - $time;
+        }
 
         # Versuchen die Ergebnisse der Quicktips zu laden
         $quicktipResults = $quicktips->loadResults();
+        if (!empty($timings)) {
+            $timings["loadResults"] = microtime(true) - $time;
+        }
+
         # Alle Ergebnisse vor der Zusammenführung ranken:
         $metager->rankAll();
+        if (!empty($timings)) {
+            $timings["rankAll"] = microtime(true) - $time;
+        }
 
         # Ergebnisse der Suchmaschinen kombinieren:
         $metager->prepareResults();
+        if (!empty($timings)) {
+            $timings["prepareResults"] = microtime(true) - $time;
+        }
 
         $finished = true;
         foreach ($metager->getEngines() as $engine) {
@@ -71,7 +101,10 @@ class MetaGerSearch extends Controller
             }
         }
 
-        \App\CacheHelper::put("loader_" . $metager->getSearchUid(), $metager->getEngines(), 60 * 60);
+        Cache::put("loader_" . $metager->getSearchUid(), $metager->getEngines(), 60 * 60);
+        if (!empty($timings)) {
+            $timings["Filled resultloader Cache"] = microtime(true) - $time;
+        }
 
         # Die Ausgabe erstellen:
         $resultpage = $metager->createView($quicktipResults);
@@ -84,9 +117,25 @@ class MetaGerSearch extends Controller
                 Cache::put('spam.' . $metager->getFokus() . "." . md5($metager->getEingabe()), $resultpage->render(), 604800);
             }
         }
+        if (!empty($timings)) {
+            $timings["createView"] = microtime(true) - $time;
+        }
+
+        if ($timings) {
+            dd($timings);
+        }
+
         return $resultpage;
     }
 
+    public function searchTimings(Request $request, MetaGer $metager)
+    {
+        $request->merge([
+            'eingabe' => "Hannover",
+        ]);
+        return $this->search($request, $metager, true);
+    }
+
     public function loadMore(Request $request)
     {
         /**
@@ -166,7 +215,7 @@ class MetaGerSearch extends Controller
         $result["finished"] = $finished;
 
         // Update new Engines
-        \App\CacheHelper::put("loader_" . $metager->getSearchUid(), $metager->getEngines(), 1 * 60);
+        Cache::put("loader_" . $metager->getSearchUid(), $metager->getEngines(), 1 * 60);
         return response()->json($result);
     }
 
diff --git a/app/Http/Middleware/HumanVerification.php b/app/Http/Middleware/HumanVerification.php
index f7c61dc15b4736cec50de395a483a38ebbcdeb16..d646e1fbd935c507be1482104067bf516e63ed97 100644
--- a/app/Http/Middleware/HumanVerification.php
+++ b/app/Http/Middleware/HumanVerification.php
@@ -2,11 +2,11 @@
 
 namespace App\Http\Middleware;
 
+use Cache;
 use Captcha;
 use Closure;
 use Cookie;
 use Illuminate\Http\Response;
-use Illuminate\Support\Facades\Cache;
 use URL;
 
 class HumanVerification
@@ -148,7 +148,7 @@ class HumanVerification
         // Lock must be acquired within 2 seconds
         $userList = Cache::get($prefix . "." . $user["id"], []);
         $userList[$user["uid"]] = $user;
-        \App\CacheHelper::put($prefix . "." . $user["id"], $userList, 2 * 7 * 24 * 60 * 60);
+        Cache::put($prefix . "." . $user["id"], $userList, 2 * 7 * 24 * 60 * 60);
     }
 
     public function removeOldUsers($prefix, $userList)
@@ -168,7 +168,7 @@ class HumanVerification
         }
 
         if ($changed) {
-            \App\CacheHelper::put($prefix . "." . $user["id"], $newUserlist, 2 * 7 * 24 * 60 * 60);
+            Cache::put($prefix . "." . $user["id"], $newUserlist, 2 * 7 * 24 * 60 * 60);
         }
 
         return $newUserlist;
diff --git a/app/MetaGer.php b/app/MetaGer.php
index ea175f09edd33537bb15603ad4dbe7451c524672..550755979e96c9f92d4bb54f56d7fc7187b650b1 100644
--- a/app/MetaGer.php
+++ b/app/MetaGer.php
@@ -324,7 +324,7 @@ class MetaGer
                 'page' => $page,
                 'engines' => $this->next,
             ];
-            \App\CacheHelper::put($this->getSearchUid(), serialize($this->next), 60 * 60);
+            Cache::put($this->getSearchUid(), serialize($this->next), 60 * 60);
         } else {
             $this->next = [];
         }
@@ -473,8 +473,12 @@ class MetaGer
      * Die Erstellung der Suchmaschinen bis die Ergebnisse da sind mit Unterfunktionen
      */
 
-    public function createSearchEngines(Request $request)
+    public function createSearchEngines(Request $request, &$timings)
     {
+        if (!empty($timings)) {
+            $timings["createSearchEngines"]["start"] = microtime(true) - $timings["starttime"];
+        }
+
         # Wenn es kein Suchwort gibt
         if (!$request->filled("eingabe") || $this->q === "") {
             return;
@@ -495,8 +499,16 @@ class MetaGer
             $sumas[$sumaName] = $this->sumaFile->sumas->{$sumaName};
         }
 
+        if (!empty($timings)) {
+            $timings["createSearchEngines"]["created engine array"] = microtime(true) - $timings["starttime"];
+        }
+
         $this->removeAdsFromListIfAdfree($sumas);
 
+        if (!empty($timings)) {
+            $timings["createSearchEngines"]["removed ads"] = microtime(true) - $timings["starttime"];
+        }
+
         foreach ($sumas as $sumaName => $suma) {
             # Check if this engine is disabled and can't be used
             $disabled = empty($suma->disabled) ? false : $suma->disabled;
@@ -550,6 +562,10 @@ class MetaGer
             }
         }
 
+        if (!empty($timings)) {
+            $timings["createSearchEngines"]["filtered invalid engines"] = microtime(true) - $timings["starttime"];
+        }
+
         # Include Yahoo Ads if Yahoo is not enabled as a searchengine
         if (!$this->apiAuthorized && $this->fokus != "bilder" && empty($this->enabledSearchengines["yahoo"]) && isset($this->sumaFile->sumas->{"yahoo-ads"})) {
             $this->enabledSearchengines["yahoo-ads"] = $this->sumaFile->sumas->{"yahoo-ads"};
@@ -574,6 +590,10 @@ class MetaGer
             $this->errors[] = $error;
         }
         $this->setEngines($request);
+        if (!empty($timings)) {
+            $timings["createSearchEngines"]["saved engines"] = microtime(true) - $timings["starttime"];
+        }
+
     }
 
     private function removeAdsFromListIfAdfree(&$sumas)
@@ -612,12 +632,38 @@ class MetaGer
         }
     }
 
-    public function startSearch()
+    public function startSearch(&$timings)
     {
+        if (!empty($timings)) {
+            $timings["startSearch"]["start"] = microtime(true) - $timings["starttime"];
+        }
+
+        # Check all engines for Cached responses
+        if ($this->canCache()) {
+            $keys = [];
+            foreach ($this->engines as $engine) {
+                $keys[] = $engine->hash;
+            }
+            $cacheValues = Cache::many($keys);
+            foreach ($this->engines as $engine) {
+                if ($cacheValues[$engine->hash] !== null) {
+                    $engine->cached = true;
+                    $engine->retrieveResults($this, $cacheValues[$engine->hash]);
+                }
+            }
+        }
+        if (!empty($timings)) {
+            $timings["startSearch"]["cache checked"] = microtime(true) - $timings["starttime"];
+        }
+
         # Wir starten alle Suchen
         foreach ($this->engines as $engine) {
-            $engine->startSearch($this);
+            $engine->startSearch($this, $timings);
+        }
+        if (!empty($timings)) {
+            $timings["startSearch"]["searches started"] = microtime(true) - $timings["starttime"];
         }
+
     }
 
     # Spezielle Suchen und Sumas
@@ -788,19 +834,20 @@ class MetaGer
         $mainEngines = $this->sumaFile->foki->{$this->fokus}->main;
         foreach ($mainEngines as $mainEngine) {
             foreach ($engines as $engine) {
-                if ($engine->name === $mainEngine) {
+                if ($engine->name === $mainEngine && !$engine->loaded) {
                     $enginesToWaitFor[] = $engine;
                 }
             }
         }
 
         $timeStart = microtime(true);
+
         $answered = [];
         $results = null;
 
         # If there is no main searchengine to wait for or if the only main engine is yahoo-ads we will define a timeout of 1s
         $forceTimeout = null;
-        if (sizeof($enginesToWaitFor) === 0 || (sizeof($enginesToWaitFor) === 1 && $enginesToWaitFor[0]->name === "yahoo-ads")) {
+        if (sizeof($enginesToWaitFor) === 1 && $enginesToWaitFor[0]->name === "yahoo-ads") {
             $forceTimeout = 1;
         }
 
@@ -812,30 +859,13 @@ class MetaGer
                     break;
                 }
             }
+
             if ((microtime(true) - $timeStart) >= 2) {
                 break;
             } else {
                 usleep(50 * 1000);
             }
         }
-
-        # Now we can add an entry to Redis which defines the starting time and how many engines should answer this request
-        /*
-    $pipeline = $redis->pipeline();
-    $pipeline->hset($this->getRedisEngineResult() . "status", "startTime", $timeStart);
-    $pipeline->hset($this->getRedisEngineResult() . "status", "engineCount", sizeof($engines));
-    $pipeline->hset($this->getRedisEngineResult() . "status", "engineDelivered", sizeof($answered));
-    # Add the cached engines as answered
-    foreach ($engines as $engine) {
-    if ($engine->cached) {
-    $pipeline->hincrby($this->getRedisEngineResult() . "status", "engineDelivered", 1);
-    $pipeline->hincrby($this->getRedisEngineResult() . "status", "engineAnswered", 1);
-    }
-    }
-    foreach ($answered as $engine) {
-    $pipeline->hset($this->getRedisEngineResult() . $engine, "delivered", "1");
-    }
-    $pipeline->execute();*/
     }
 
     public function retrieveResults()
diff --git a/app/Models/Searchengine.php b/app/Models/Searchengine.php
index 6584aa30f75043645f5015d3f0ddf36c457b54cd..ef364a50c2ae6794752508c67afbcf2c12c31418 100644
--- a/app/Models/Searchengine.php
+++ b/app/Models/Searchengine.php
@@ -3,7 +3,6 @@
 namespace App\Models;
 
 use App\MetaGer;
-use Cache;
 use Illuminate\Support\Facades\Redis;
 
 abstract class Searchengine
@@ -105,12 +104,17 @@ abstract class Searchengine
     {}
 
     # Prüft, ob die Suche bereits gecached ist, ansonsted wird sie als Job dispatched
-    public function startSearch(\App\MetaGer $metager)
+    public function startSearch(\App\MetaGer $metager, &$timings)
     {
-        if ($this->canCache && Cache::has($this->hash)) {
-            $this->cached = true;
-            $this->retrieveResults($metager, true);
-        } else {
+        if (!empty($timings)) {
+            $timings["startSearch"][$this->name]["start"] = microtime(true) - $timings["starttime"];
+        }
+
+        if (!$this->cached) {
+            if (!empty($timings)) {
+                $timings["startSearch"][$this->name]["checked cache"] = microtime(true) - $timings["starttime"];
+            }
+
             // We need to submit a action that one of our workers can understand
             // The missions are submitted to a redis queue in the following string format
             // <ResultHash>;<URL to fetch>
@@ -144,10 +148,17 @@ abstract class Searchengine
             // Since each Searcher is dedicated to one specific search engine
             // each Searcher has it's own queue lying under the redis key <name>.queue
             Redis::rpush(\App\MetaGer::FETCHQUEUE_KEY, $mission);
+            if (!empty($timings)) {
+                $timings["startSearch"][$this->name]["pushed job"] = microtime(true) - $timings["starttime"];
+            }
+
             // The request is not cached and will be submitted to the searchengine
             // We need to check if the number of requests to this engine are limited
             if (!empty($this->engine->{"monthly-requests"})) {
                 Redis::incr("monthlyRequests:" . $this->name);
+                if (!empty($timings)) {
+                    $timings["startSearch"][$this->name]["increased monthly requests"] = microtime(true) - $timings["starttime"];
+                }
             }
         }
     }
@@ -171,15 +182,13 @@ abstract class Searchengine
     }
 
     # Fragt die Ergebnisse von Redis ab und lädt Sie
-    public function retrieveResults(MetaGer $metager)
+    public function retrieveResults(MetaGer $metager, $body = null)
     {
         if ($this->loaded) {
             return true;
         }
 
-        $body = null;
         if ($this->cached) {
-            $body = Cache::get($this->hash);
             if ($body === "no-result") {
                 $body = "";
             }
diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml
index 0940498c1fbb03087901827449603c36c39b83fd..e619fd5a112375ee9aac7e21700acb2f1e2c2a60 100644
--- a/chart/templates/deployment.yaml
+++ b/chart/templates/deployment.yaml
@@ -38,9 +38,6 @@ spec:
       - name: mglogs-persistent-storage
         persistentVolumeClaim:
           claimName: mglogs
-      - name: mgcache-persistent-storage
-        persistentVolumeClaim:
-          claimName: mgcache
       containers:
       - name: {{ .Chart.Name }}
         image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
@@ -105,9 +102,6 @@ spec:
         - name: mglogs-persistent-storage
           mountPath: /html/storage/logs/metager
           readOnly: false
-        - name: mgcache-persistent-storage
-          mountPath: /html/storage/framework/cache
-          readOnly: false
         resources:
 {{ toYaml .Values.resources | indent 12 }}
 {{- end -}}
diff --git a/database/migrations/2020_02_05_163522_create_cache_table.php b/database/migrations/2020_02_05_163522_create_cache_table.php
new file mode 100644
index 0000000000000000000000000000000000000000..058afe69c98645601183f7b4adea77cd191bf882
--- /dev/null
+++ b/database/migrations/2020_02_05_163522_create_cache_table.php
@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class CreateCacheTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('cache', function (Blueprint $table) {
+            $table->string('key')->unique();
+            $table->mediumText('value');
+            $table->integer('expiration');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('cache');
+    }
+}
diff --git a/routes/web.php b/routes/web.php
index 90f0257318fc166ade1596c64106cceb64ed0bce..cae78b76b3cc2c9e289a96d8f166898db3ed8d3e 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -170,6 +170,7 @@ Route::group(
         Route::group(['middleware' => ['auth.basic'], 'prefix' => 'admin'], function () {
             Route::get('/', 'AdminInterface@index');
             Route::match(['get', 'post'], 'count', 'AdminInterface@count');
+            Route::get('timings', 'MetaGerSearch@searchTimings');
             Route::get('count/graphtoday.svg', 'AdminInterface@countGraphToday');
             Route::get('engine/stats.json', 'AdminInterface@engineStats');
             Route::get('check', 'AdminInterface@check');
@@ -181,6 +182,7 @@ Route::group(
         });
 
         Route::match(['get', 'post'], 'meta/meta.ger3', 'MetaGerSearch@search')->middleware('humanverification', 'useragentmaster');
+
         Route::get('meta/loadMore', 'MetaGerSearch@loadMore');
         Route::post('img/cat.jpg', 'HumanVerification@remove');
         Route::get('r/metager/{mm}/{pw}/{url}', ['as' => 'humanverification', 'uses' => 'HumanVerification@removeGet']);