Concurrency Model for             huge MySQL data                Mu-Fan Teng(@ryudoawaru)                 @ RubyConf Taiwa...
緣起               Background12年12月8⽇日星期六
Legacy environment               • A Mysql Database with 2.3gb data with Big5                 charset and ISO-8859-1 encod...
The purpose12年12月8⽇日星期六
Transcoding to UTF812年12月8⽇日星期六
Try12年12月8⽇日星期六
Work Flow               1. mysqldump with -default-character-                  set=latin1 parameter to generate SQL file.  ...
Failed!12年12月8⽇日星期六
Cause               • Too big size for most text editor.               • Many mis-encoding text.12年12月8⽇日星期六
Let’s reinvent the                     wheel!12年12月8⽇日星期六
The new work flow               • Connect DB               • Transcode               • Output db rows to SQL insert stateme...
CORES_COUNT = 4   LIMIT = ARGV[0].to_i || 10000   sqls = CORES_COUNT.times.map do |x|     sprintf("SELECT * FROM cdb_posts...
Thanks for Ruby 1.9’s                Awesome Encoding               class which supports                     Big5-UAO.12年1...
Reduces almost 80% of                 encoding problem.12年12月8⽇日星期六
But the file size is too                   big to wait for                    transcoding!12年12月8⽇日星期六
So I have to find the               concurrency model to                   make it faster.12年12月8⽇日星期六
Experiment Target               • Test the difference of performance                 between thread and fork model.12年12月8...
H&W Platform               • 4 Cores Core2Quad CPU@2.5G               • 8GB RAM               • 1*SSD               • MacO...
DBNAME = wwwfsc      CORES_COUNT = 4      ForceEncoding = Big5-UAO      LIMIT = ARGV[0].to_i || 10000      OUT = /dev/null...
Benchmark.bm(15) do |x|        x.report("Thread"){procs.map{|p| Thread.new{p.call(OUT)} }.each(&:join)}        x.report("F...
Result of 100k*4 rows12年12月8⽇日星期六
Thread12年12月8⽇日星期六
Fork12年12月8⽇日星期六
Fork12年12月8⽇日星期六
Circumstance               • Thread                ‣ CPU utilization rate between 105 and                   125 percent.  ...
GVL still effects12年12月8⽇日星期六
Try again12年12月8⽇日星期六
Decompose the steps                to find how to skip                       GVL.12年12月8⽇日星期六
Experiment No.212年12月8⽇日星期六
Minify the process to                 query DB only.12年12月8⽇日星期六
DBNAME = wwwfsc   CORES_COUNT = 4   limit = ARGV[0].to_i || 10000   sqls = CORES_COUNT.times.map do |x|     sprintf("SELEC...
Result of 100k*4 rows12年12月8⽇日星期六
It seems the Mysql2               Gem can skip GVL.12年12月8⽇日星期六
Experiment NO.312年12月8⽇日星期六
Limit the experiment               to I/O operation only.12年12月8⽇日星期六
client = Mysql2::Client.new(database: DBNAME, reconnect: true, encoding:       latin1)       sql_raws = sqls.map do |sql| ...
12年12月8⽇日星期六
Result of 100k*4 rows12年12月8⽇日星期六
Change I/O to different                    files.12年12月8⽇日星期六
procs = sql_raws.map do |arr|                 proc do                   io = Tempfile.new(SecureRandom.uuid)#open(/dev/nul...
Result reversed12年12月8⽇日星期六
Implement the same                change to the first                   experiment.12年12月8⽇日星期六
procs = sqls.map do |sql|        Proc.new do          io = Tempfile.new(SecureRandom.uuid)          Mysql2::Client.new(dat...
Dose not effect any12年12月8⽇日星期六
Conclusion                        Thread       fork      normal      MySQL2-read        Fast        Fast        x      Tra...
There is no effective               and 「all-around」               concurrency model.12年12月8⽇日星期六
The small I/O can’t                 release GVL.12年12月8⽇日星期六
Kosaki-san’s slide12年12月8⽇日星期六
Matz is not a threading guy12年12月8⽇日星期六
End12年12月8⽇日星期六
Upcoming SlideShare
Loading in...5
×

Concurrency model for mysql data processing@rubyconf.tw 2012

1,149

Published on

Video: http://www.youtube.com/watch?v=3Oi_IjKDZtg

Published in: News & Politics
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,149
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
29
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Concurrency model for mysql data processing@rubyconf.tw 2012

  1. 1. Concurrency Model for huge MySQL data Mu-Fan Teng(@ryudoawaru) @ RubyConf Taiwan 201212年12月8⽇日星期六
  2. 2. 緣起 Background12年12月8⽇日星期六
  3. 3. Legacy environment • A Mysql Database with 2.3gb data with Big5 charset and ISO-8859-1 encoding. • The biggest table in DB is 1.5gb.12年12月8⽇日星期六
  4. 4. The purpose12年12月8⽇日星期六
  5. 5. Transcoding to UTF812年12月8⽇日星期六
  6. 6. Try12年12月8⽇日星期六
  7. 7. Work Flow 1. mysqldump with -default-character- set=latin1 parameter to generate SQL file. 2. Transcoding SQL file with tool like iconv/ bsdconv. 3. Edit transcoded SQL file to avoid 「slash」 problem. 4. Restore SQL file to new DB.12年12月8⽇日星期六
  8. 8. Failed!12年12月8⽇日星期六
  9. 9. Cause • Too big size for most text editor. • Many mis-encoding text.12年12月8⽇日星期六
  10. 10. Let’s reinvent the wheel!12年12月8⽇日星期六
  11. 11. The new work flow • Connect DB • Transcode • Output db rows to SQL insert statement. • Write SQL file12年12月8⽇日星期六
  12. 12. CORES_COUNT = 4 LIMIT = ARGV[0].to_i || 10000 sqls = CORES_COUNT.times.map do |x| sprintf("SELECT * FROM cdb_posts ORDER BY pid LIMIT %d OFFSET %d;", LIMIT, (x * LIMIT)) end class String def to_my_val "#{Mysql2::Client.escape self.force_encoding(‘Big5- UAO’).encode(UTF-8, :invalid => :replace, :undef => :replace, :replace => ??)}" end end procs = sqls.map do |sql| Proc.new do |out| Mysql2::Client.new(database: DBNAME, reconnect: true, encoding: latin1).query(sql).each(as: :array) do |row| out.print "INSERT INTO `cdb_posts` VALUES (#{row.map(&:to_my_val).join(,)});n" end end end procs.each{|p| p.call(OUT)}12年12月8⽇日星期六
  13. 13. Thanks for Ruby 1.9’s Awesome Encoding class which supports Big5-UAO.12年12月8⽇日星期六
  14. 14. Reduces almost 80% of encoding problem.12年12月8⽇日星期六
  15. 15. But the file size is too big to wait for transcoding!12年12月8⽇日星期六
  16. 16. So I have to find the concurrency model to make it faster.12年12月8⽇日星期六
  17. 17. Experiment Target • Test the difference of performance between thread and fork model.12年12月8⽇日星期六
  18. 18. H&W Platform • 4 Cores Core2Quad CPU@2.5G • 8GB RAM • 1*SSD • MacOS 10.8 • MRI 1.9.3p19412年12月8⽇日星期六
  19. 19. DBNAME = wwwfsc CORES_COUNT = 4 ForceEncoding = Big5-UAO LIMIT = ARGV[0].to_i || 10000 OUT = /dev/null sqls = CORES_COUNT.times.map do |x| sprintf("SELECT * FROM cdb_posts ORDER BY pid LIMIT %d OFFSET %d;", LIMIT, (x * LIMIT)) end class String def to_my_val "#{Mysql2::Client.escape self.force_encoding(ForceEncoding).encode(UTF-8, :invalid => :replace, :undef => :replace, :replace => ??)}" end end procs = sqls.map do |sql| Proc.new do |out| open(out,w) do |io| Mysql2::Client.new(database: DBNAME, reconnect: true, encoding: latin1).query(sql).each(as: :array) do |row| io.print "INSERT INTO `cdb_posts` VALUES (#{row.map(&:to_my_val).join(,)});n" end end end end12年12月8⽇日星期六
  20. 20. Benchmark.bm(15) do |x| x.report("Thread"){procs.map{|p| Thread.new{p.call(OUT)} }.each(&:join)} x.report("Fork"){procs.each{|p| fork{p.call(OUT)} }; Process.waitall} x.report("Normal"){procs.each{|p| p.call(OUT)}} end12年12月8⽇日星期六
  21. 21. Result of 100k*4 rows12年12月8⽇日星期六
  22. 22. Thread12年12月8⽇日星期六
  23. 23. Fork12年12月8⽇日星期六
  24. 24. Fork12年12月8⽇日星期六
  25. 25. Circumstance • Thread ‣ CPU utilization rate between 105 and 125 percent. • Fork ‣ The rate changes frequently between processes.12年12月8⽇日星期六
  26. 26. GVL still effects12年12月8⽇日星期六
  27. 27. Try again12年12月8⽇日星期六
  28. 28. Decompose the steps to find how to skip GVL.12年12月8⽇日星期六
  29. 29. Experiment No.212年12月8⽇日星期六
  30. 30. Minify the process to query DB only.12年12月8⽇日星期六
  31. 31. DBNAME = wwwfsc CORES_COUNT = 4 limit = ARGV[0].to_i || 10000 sqls = CORES_COUNT.times.map do |x| sprintf("SELECT * FROM cdb_posts ORDER BY pid LIMIT %d OFFSET %d;", limit, (x * limit)) end procs = CORES_COUNT.times.map do |x| Proc.new do client = Mysql2::Client.new(database: DBNAME, reconnect: true) result = client.query(sqls[x]) end end Benchmark.bmbm(15) do |x| x.report("Thread"){procs.map{|p| Thread.new{p.call} }.each(&:join)} x.report("Fork"){procs.each{|p| fork{p.call} }; Process.waitall} x.report("Normal"){procs.each(&:call)} end12年12月8⽇日星期六
  32. 32. Result of 100k*4 rows12年12月8⽇日星期六
  33. 33. It seems the Mysql2 Gem can skip GVL.12年12月8⽇日星期六
  34. 34. Experiment NO.312年12月8⽇日星期六
  35. 35. Limit the experiment to I/O operation only.12年12月8⽇日星期六
  36. 36. client = Mysql2::Client.new(database: DBNAME, reconnect: true, encoding: latin1) sql_raws = sqls.map do |sql| arr = [] client.query(sql).each(as: :array) do |row| arr << "(#{row.map(&:to_my_val).join(,)})" end arr end procs = sql_raws.map do |arr| proc do io = open(/dev/null,w) io.write "INSERT INTO `cdb_posts` VALUES " io.write arr.join(,) io.write "n" io.close end end Benchmark.bm(15) do |x| x.report("Thread"){procs.map{|p| Thread.new{p.call} }.each(&:join)} x.report("Fork"){procs.each{|p| fork{p.call} }; Process.waitall} x.report("Normal"){procs.each{|p| p.call}} end12年12月8⽇日星期六
  37. 37. 12年12月8⽇日星期六
  38. 38. Result of 100k*4 rows12年12月8⽇日星期六
  39. 39. Change I/O to different files.12年12月8⽇日星期六
  40. 40. procs = sql_raws.map do |arr| proc do io = Tempfile.new(SecureRandom.uuid)#open(/dev/null,w) puts io.path io.write "INSERT INTO `cdb_posts` VALUES " io.write arr.join(,) io.write "n" io.close end end12年12月8⽇日星期六
  41. 41. Result reversed12年12月8⽇日星期六
  42. 42. Implement the same change to the first experiment.12年12月8⽇日星期六
  43. 43. procs = sqls.map do |sql| Proc.new do io = Tempfile.new(SecureRandom.uuid) Mysql2::Client.new(database: DBNAME, reconnect: true, encoding: latin1).query(sql).each(as: :array) do |row| io.write "INSERT INTO `cdb_posts` VALUES (#{row.map(&:to_my_val).join(,)});n" end io.close end end12年12月8⽇日星期六
  44. 44. Dose not effect any12年12月8⽇日星期六
  45. 45. Conclusion Thread fork normal MySQL2-read Fast Fast x Transcoding & Slow Very fast x iteration Write to the Very slow Slow Fast same I/O Write to the Fast Slow Fast different I/O12年12月8⽇日星期六
  46. 46. There is no effective and 「all-around」 concurrency model.12年12月8⽇日星期六
  47. 47. The small I/O can’t release GVL.12年12月8⽇日星期六
  48. 48. Kosaki-san’s slide12年12月8⽇日星期六
  49. 49. Matz is not a threading guy12年12月8⽇日星期六
  50. 50. End12年12月8⽇日星期六
  1. Gostou de algum slide específico?

    Recortar slides é uma maneira fácil de colecionar informações para acessar mais tarde.

×