Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How (and why) to run SQLite in production

Stephen
December 16, 2023

How (and why) to run SQLite in production

You've heard the whispers, sensed the hype, but you're still not sure what all the fuss is about with SQLite these days. Join me as we explore the use-cases and benefits of running SQLite in a production environment. Along the way, we will learn why SQLite makes sense as your next production database and how to ensure that your setup is optimized for end-user performance and developer happiness. We will setup and deploy a full Rails application—with caching, background jobs, websockets, and full-text search all backed by SQLite—in these 40 minutes. Come along for the ride!

Stephen

December 16, 2023
Tweet

More Decks by Stephen

Other Decks in Programming

Transcript

  1. Stephen Margheim · 16 December 2023 SQLite on Rails How

    (and why) to run SQLite in production
  2. Who am I? • Head of Engineering at Test IO

    • Open source developer • rails/rails • sparklemotion/sqlite3-ruby • oldmoe/litestack • joeldrapper/phlex • joeldrapper/literal • fractaledmind/activerecord-enhancedsqlite3-adapter • fractaledmind/litestream-ruby • fractaledmind/acidic_job • Writer: https://fractaledmind.github.io Stephen Margheim · @fractaledmind 🇺🇸 🛫 🇩🇪 💒 🇷🇺
  3. MVP

  4. $ hey -c N -z 10s -m POST / https://demo.sqliteonrails.com/benchmarking/read_heavy

    $ hey -c N -z 10s -m POST / https://demo.sqliteonrails.com/benchmarking/write_heavy $ hey -c N -z 10s -m POST / https://demo.sqliteonrails.com/benchmarking/balanced ⇒ 16, 24, 22 ⇒ 21 RPS N ⇒ [1, 2, 4, 8, 16, 32, 64, 128, 256] ×2
  5. $ hey -c N -z 10s -m POST / https://demo.sqliteonrails.com/benchmarking/balanced

    ⇒ 14 RPS N ⇒ [1, 2, 4, 8, 16, 32, 64, 128, 256] ×2
  6. Rails default PRAGMAs PRAGMA foreign_keys = ON; 
 PRAGMA journal_mode

    = WAL; PRAGMA synchronous = NORMAL; PRAGMA mmap_size = 134217728; -- 128 megabytes PRAGMA journal_size_limit = 67108864; -- 64 megabytes PRAGMA cache_size = 2000; >= 7.1.0
  7. Enhancing ActiveRecord • deferred foreign keys, • generated columns, •

    PRAGMA tuning, • extension loading, and • improved concurrency support How?
  8. Enhancing ActiveRecord $ bundle add sqlite-vss # /config/database.yml default: &default

    adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 extensions: - sqlite_vss Extension loading
  9. Enhancing ActiveRecord busy_handler do |count| timed_out = false if (count

    % 100).zero? timed_out = (count * retry_interval) > timeout_seconds end if timed_out false else sleep(retry_interval) true end end Improved concurrency support
  10. Fine-tuning compilation $ bundle config set build.sqlite3 \ "--with-sqlite-cflags=' -DSQLITE_DQS=0

    -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_FTS5'"
  11. Branch-specific databases # /config/database.yml development: <<: *default database: storage/<%= `git

    branch --show-current`.chomp || 'development' %>.sqlite3 # /config/environments/development.rb config.after_initialize do ActiveRecord::Tasks::DatabaseTasks.prepare_all end
  12. • Database Server (e.g. PostgreSQL, MySQL) • Cache Server (e.g.

    Redis, Memcached) • Job Processor (e.g. Sidekiq, Goodjob) • Pubsub Server (e.g. Redis, PostgreSQL) • Fulltext Search Server (e.g. Elasticsearch, Mielisearch) What? Integrating Litestack