Guest User

Untitled

a guest
May 19th, 2018
171
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.73 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2.  
  3. require 'pg'
  4.  
  5. =begin
  6.  
  7. when creating a postgres db replica in RDS, or restoring from a snapshot, the
  8. underlying EBS volume of the new instance must be initialized by reading every
  9. block, otherwise the blocks will be lazy-initialized by production queries
  10. which will be extremely latent. (i've seen normally 50ms queries take 30s in
  11. some cases on the fresh EBS instance.) because RDS is managed, we do not have
  12. filesystem access, so must use postgres to read the full volume and bring
  13. the replica up to normal disk performance.
  14.  
  15. for this script to work, several preconditions exist:
  16.  
  17. 1. the pg_prewarm extension must be created. so if you want to warm up a hot
  18. standby replica, run the create extension command on the primary if it doesn't
  19. have it yet. if this is a restore from a backup and the extension doesn't
  20. exist in the backup, create it on the instance directly.
  21.  
  22. CREATE EXTENSION IF NOT EXISTS pg_prewarm;
  23.  
  24. 2. if running the warmup on a hot standby replica, the replica must have
  25. hot_standby_feedback enabled. because these warmup queries are very
  26. long-running, without feedback from the replica the primary will vacuum pages
  27. that the replica still needs to access, causing the query to be cancelled.
  28. there are other solutions to preventing query conflicts on a replica but this
  29. is the simplest IMO. in order to turn on hot_standby_feedback, you must create
  30. a "parameter group" in RDS console that is based on the default postgres
  31. parameter group, change the hot_standby_feedback to "1" (on), assign this
  32. parameter group to the replica, then reboot the replica.
  33.  
  34. 3. pg gem is installed.
  35.  
  36. once the replica is ready for the warmup queries, this script can be run
  37. in the following way to set the appropriate env vars:
  38.  
  39. DB_HOST=<replica endpoint> \
  40. DB_NAME=<db name> \
  41. DB_USER=<username> \
  42. DB_PASS=<password> \
  43. bundle exec ./prewarm_db.rb
  44.  
  45. =end
  46.  
  47. puts "connecting: db=#{ENV['DB_NAME']} host=#{ENV['DB_HOST']} user=#{ENV['DB_USER']} password=(not shown)"
  48. conn = PG.connect({
  49. :dbname => ENV['DB_NAME'],
  50. :host => ENV['DB_HOST'],
  51. :user => ENV['DB_USER'],
  52. :password => ENV['DB_PASS'],
  53. })
  54. all_start = Time.now
  55. conn.exec("
  56. SELECT c.oid, relkind, c.relname, c.relpages
  57. FROM pg_class c
  58. JOIN pg_user u ON u.usesysid = c.relowner
  59. WHERE u.usename NOT IN (
  60. 'rdsadmin', 'rdsrepladmin', ' pg_signal_backend', 'rds_superuser',
  61. 'rds_replication')
  62. ORDER BY c.relpages DESC
  63. ") do |res|
  64. res.each do |rel|
  65. start = Time.now
  66. puts "warming up #{rel['relname']} (pages=#{rel['relpages']}, kind=#{rel['relkind']})"
  67. conn.exec("select pg_prewarm(#{rel['oid'].to_i}::regclass)")
  68. finish = Time.now
  69. puts "completed #{rel['relname']} in #{(finish-start).to_i} seconds"
  70. end
  71. end
  72. all_finish = Time.now
  73. puts "all completed in #{((all_finish - all_start) / 60.0).to_i} minutes"
Add Comment
Please, Sign In to add comment