Browse Source

Phoenix performance (#5153)

* perf(DB): Reduce pool_size as it is overprovisioned for the underlying hardware we are testing on

* chore(Elixir): Bump to version 1.9.1

* perf(DB): Run SQL queries in parallel
Thomas Cioppettini 5 years ago
parent
commit
5c6101cac4

+ 1 - 1
frameworks/Elixir/phoenix/config/prod.exs

@@ -14,7 +14,7 @@ config :hello, Hello.Repo,
   password: "benchmarkdbpass",
   password: "benchmarkdbpass",
   database: "hello_world",
   database: "hello_world",
   hostname: "tfb-database",
   hostname: "tfb-database",
-  pool_size: 256
+  pool_size: 14
 
 
 config :logger,
 config :logger,
   compile_time_purge_matching: [
   compile_time_purge_matching: [

+ 1 - 1
frameworks/Elixir/phoenix/mix.exs

@@ -5,7 +5,7 @@ defmodule Hello.Mixfile do
     [
     [
       app: :hello,
       app: :hello,
       version: "0.1.0",
       version: "0.1.0",
-      elixir: "~> 1.8",
+      elixir: "~> 1.9",
       elixirc_paths: elixirc_paths(Mix.env()),
       elixirc_paths: elixirc_paths(Mix.env()),
       compilers: [:phoenix] ++ Mix.compilers(),
       compilers: [:phoenix] ++ Mix.compilers(),
       start_permanent: Mix.env() == :prod,
       start_permanent: Mix.env() == :prod,

+ 1 - 1
frameworks/Elixir/phoenix/phoenix.dockerfile

@@ -1,4 +1,4 @@
-FROM elixir:1.8.1
+FROM elixir:1.9.1
 
 
 ADD ./ /phoenix
 ADD ./ /phoenix
 WORKDIR /phoenix
 WORKDIR /phoenix

+ 48 - 36
frameworks/Elixir/phoenix/web/controllers/page_controller.ex

@@ -1,41 +1,40 @@
 defmodule Hello.PageController do
 defmodule Hello.PageController do
+  alias Hello.{Fortune, World}
+
   use Hello.Web, :controller
   use Hello.Web, :controller
-  alias Hello.World
-  alias Hello.Fortune
+
+  @json "application/json"
+  @plain "text/plain"
 
 
   def index(conn, _params) do
   def index(conn, _params) do
     conn
     conn
-    |> put_resp_content_type("application/json", nil)
+    |> put_resp_content_type(@json, nil)
     |> send_resp(200, Jason.encode_to_iodata!(%{"TE Benchmarks\n" => "Started"}))
     |> send_resp(200, Jason.encode_to_iodata!(%{"TE Benchmarks\n" => "Started"}))
   end
   end
 
 
   # avoid namespace collision
   # avoid namespace collision
   def _json(conn, _params) do
   def _json(conn, _params) do
     conn
     conn
-    |> put_resp_content_type("application/json", nil)
+    |> put_resp_content_type(@json, nil)
     |> send_resp(200, Jason.encode_to_iodata!(%{"message" => "Hello, world!"}))
     |> send_resp(200, Jason.encode_to_iodata!(%{"message" => "Hello, world!"}))
   end
   end
 
 
   def db(conn, _params) do
   def db(conn, _params) do
     conn
     conn
-    |> put_resp_content_type("application/json", nil)
+    |> put_resp_content_type(@json, nil)
     |> send_resp(200, Jason.encode_to_iodata!(Repo.get(World, :rand.uniform(10000))))
     |> send_resp(200, Jason.encode_to_iodata!(Repo.get(World, :rand.uniform(10000))))
   end
   end
 
 
   def queries(conn, params) do
   def queries(conn, params) do
-    q = try do
-      case String.to_integer(params["queries"]) do
-        x when x < 1    -> 1
-        x when x > 500  -> 500
-        x               -> x
-      end
-    rescue
-      ArgumentError -> 1
-    end
+    json =
+      params["queries"]
+      |> query_range()
+      |> parallel(fn _ -> Repo.get(World, :rand.uniform(10000)) end)
+      |> Jason.encode_to_iodata!()
 
 
     conn
     conn
-    |> put_resp_content_type("application/json", nil)
-    |> send_resp(200, Jason.encode_to_iodata!(for _ <- 1..q, do: Repo.get(World, :rand.uniform(10000))))
+    |> put_resp_content_type(@json, nil)
+    |> send_resp(200, json)
   end
   end
 
 
   def fortunes(conn, _params) do
   def fortunes(conn, _params) do
@@ -50,32 +49,45 @@ defmodule Hello.PageController do
   end
   end
 
 
   def updates(conn, params) do
   def updates(conn, params) do
-    q = try do
-      case String.to_integer(params["queries"]) do
-        x when x < 1    -> 1
-        x when x > 500  -> 500
-        x               -> x
-      end
-    rescue
-      ArgumentError -> 1
-    end
-
-    data = for _ <- 1..q do
-      id = :rand.uniform(10000)
-      num = :rand.uniform(10000)
-      w = Repo.get(World, id)
-      changeset = Ecto.Changeset.change(w, randomnumber: num)
-      Repo.update!(changeset)
-    end
+    json =
+      params["queries"]
+      |> query_range()
+      |> parallel(fn _ ->
+          Repo.checkout(fn ->
+            World
+            |> Repo.get(:rand.uniform(10000))
+            |> Ecto.Changeset.change(randomnumber: :rand.uniform(10000))
+            |> Repo.update!()
+          end)
+        end)
+      |> Jason.encode_to_iodata!()
 
 
     conn
     conn
-    |> put_resp_content_type("application/json", nil)
-    |> send_resp(200, Jason.encode_to_iodata!(data))
+    |> put_resp_content_type(@json, nil)
+    |> send_resp(200, json)
   end
   end
 
 
   def plaintext(conn, _params) do
   def plaintext(conn, _params) do
     conn
     conn
-    |> put_resp_content_type("text/plain", nil)
+    |> put_resp_content_type(@plain, nil)
     |> send_resp(200, "Hello, world!")
     |> send_resp(200, "Hello, world!")
   end
   end
+
+  defp parallel(collection, func) do
+    collection
+    |> Enum.map(&Task.async(fn -> func.(&1) end))
+    |> Enum.map(&Task.await(&1))
+  end
+
+  defp query_range(queries) do
+    try do
+      case String.to_integer(queries) do
+        x when x < 1    -> 1..1
+        x when x > 500  -> 1..500
+        x               -> 1..x
+      end
+    rescue
+      ArgumentError -> 1..1
+    end
+  end
 end
 end