SlideShare a Scribd company logo
1 of 50
Download to read offline
Concurrency Model for
             huge MySQL data
                Mu-Fan Teng(@ryudoawaru)
                 @ RubyConf Taiwan 2012




12年12月8⽇日星期六
緣起

               Background




12年12月8⽇日星期六
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⽇日星期六
The purpose




12年12月8⽇日星期六
Transcoding to UTF8



12年12月8⽇日星期六
Try



12年12月8⽇日星期六
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⽇日星期六
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 statement.
               • Write SQL file



12年12月8⽇日星期六
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⽇日星期六
Thanks for Ruby 1.9’s
                Awesome Encoding
               class which supports
                     Big5-UAO.


12年12月8⽇日星期六
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
               • MacOS 10.8
               • MRI 1.9.3p194


12年12月8⽇日星期六
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
      end


12年12月8⽇日星期六
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)}}
      end




12年12月8⽇日星期六
Result of 100k*4 rows




12年12月8⽇日星期六
Thread




12年12月8⽇日星期六
Fork




12年12月8⽇日星期六
Fork




12年12月8⽇日星期六
Circumstance
               • Thread
                ‣ CPU utilization rate between 105 and
                   125 percent.
               • Fork
                ‣ The rate changes frequently between
                   processes.



12年12月8⽇日星期六
GVL still effects



12年12月8⽇日星期六
Try again



12年12月8⽇日星期六
Decompose the steps
                to find how to skip
                       GVL.


12年12月8⽇日星期六
Experiment No.2



12年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("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)}
   end




12年12月8⽇日星期六
Result of 100k*4 rows




12年12月8⽇日星期六
It seems the Mysql2
               Gem can skip GVL.


12年12月8⽇日星期六
Experiment NO.3



12年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|
         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}}
       end




12年12月8⽇日星期六
12年12月8⽇日星期六
Result of 100k*4 rows




12年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/null','w')
                   puts io.path
                   io.write "INSERT INTO `cdb_posts` VALUES "
                   io.write arr.join(',')
                   io.write "n"
                   io.close
                 end
               end




12年12月8⽇日星期六
Result reversed




12年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(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
      end




12年12月8⽇日星期六
Dose not effect any




12年12月8⽇日星期六
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/O


12年12月8⽇日星期六
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 slide




12年12月8⽇日星期六
Matz is not a threading guy




12年12月8⽇日星期六
End




12年12月8⽇日星期六

More Related Content

What's hot

Nosql及其主要产品简介
Nosql及其主要产品简介Nosql及其主要产品简介
Nosql及其主要产品简介振林 谭
 
美团点评技术沙龙010-美团Atlas实践
美团点评技术沙龙010-美团Atlas实践美团点评技术沙龙010-美团Atlas实践
美团点评技术沙龙010-美团Atlas实践美团点评技术团队
 
Redis 常见使用模式分析
Redis 常见使用模式分析Redis 常见使用模式分析
Redis 常见使用模式分析vincent253
 
Mongo db 簡介
Mongo db 簡介Mongo db 簡介
Mongo db 簡介昱劭 劉
 
百度系统部分布式系统介绍 马如悦 Sacc2010
百度系统部分布式系统介绍 马如悦 Sacc2010百度系统部分布式系统介绍 马如悦 Sacc2010
百度系统部分布式系统介绍 马如悦 Sacc2010Chuanying Du
 
硬件体系架构浅析
硬件体系架构浅析硬件体系架构浅析
硬件体系架构浅析frogd
 
数据库内核分享——第一期
数据库内核分享——第一期数据库内核分享——第一期
数据库内核分享——第一期frogd
 
OpenStack Resource Scheduling
OpenStack Resource SchedulingOpenStack Resource Scheduling
OpenStack Resource SchedulingGuangya Liu
 
Hbase运维碎碎念
Hbase运维碎碎念Hbase运维碎碎念
Hbase运维碎碎念haiyuan ning
 
浅谈 My sql 性能调优
浅谈 My sql 性能调优浅谈 My sql 性能调优
浅谈 My sql 性能调优thinkinlamp
 
Ceph中国社区9.19 Ceph FS-基于RADOS的高性能分布式文件系统02-袁冬
Ceph中国社区9.19 Ceph FS-基于RADOS的高性能分布式文件系统02-袁冬Ceph中国社区9.19 Ceph FS-基于RADOS的高性能分布式文件系统02-袁冬
Ceph中国社区9.19 Ceph FS-基于RADOS的高性能分布式文件系统02-袁冬Hang Geng
 
分布式存储与TDDL
分布式存储与TDDL分布式存储与TDDL
分布式存储与TDDLmysqlops
 
淘宝软件基础设施构建实践
淘宝软件基础设施构建实践淘宝软件基础设施构建实践
淘宝软件基础设施构建实践Wensong Zhang
 
Redis介绍
Redis介绍 Redis介绍
Redis介绍 yubao fu
 
Sheepdog内部实现机制
Sheepdog内部实现机制Sheepdog内部实现机制
Sheepdog内部实现机制Liu Yuan
 
Spark sql培训
Spark sql培训Spark sql培训
Spark sql培训Jiang Yu
 
“云存储系统”赏析系列分享三:Sql与nosql
“云存储系统”赏析系列分享三:Sql与nosql“云存储系统”赏析系列分享三:Sql与nosql
“云存储系统”赏析系列分享三:Sql与nosqlknuthocean
 
云计算环境中Ssd在cassandra测试的性能表现
云计算环境中Ssd在cassandra测试的性能表现 云计算环境中Ssd在cassandra测试的性能表现
云计算环境中Ssd在cassandra测试的性能表现 july19850903
 

What's hot (20)

Nosql及其主要产品简介
Nosql及其主要产品简介Nosql及其主要产品简介
Nosql及其主要产品简介
 
美团点评技术沙龙010-美团Atlas实践
美团点评技术沙龙010-美团Atlas实践美团点评技术沙龙010-美团Atlas实践
美团点评技术沙龙010-美团Atlas实践
 
Redis 常见使用模式分析
Redis 常见使用模式分析Redis 常见使用模式分析
Redis 常见使用模式分析
 
Mongo db 簡介
Mongo db 簡介Mongo db 簡介
Mongo db 簡介
 
百度系统部分布式系统介绍 马如悦 Sacc2010
百度系统部分布式系统介绍 马如悦 Sacc2010百度系统部分布式系统介绍 马如悦 Sacc2010
百度系统部分布式系统介绍 马如悦 Sacc2010
 
Mongo db 特性
Mongo db 特性Mongo db 特性
Mongo db 特性
 
硬件体系架构浅析
硬件体系架构浅析硬件体系架构浅析
硬件体系架构浅析
 
数据库内核分享——第一期
数据库内核分享——第一期数据库内核分享——第一期
数据库内核分享——第一期
 
OpenStack Resource Scheduling
OpenStack Resource SchedulingOpenStack Resource Scheduling
OpenStack Resource Scheduling
 
Hbase运维碎碎念
Hbase运维碎碎念Hbase运维碎碎念
Hbase运维碎碎念
 
浅谈 My sql 性能调优
浅谈 My sql 性能调优浅谈 My sql 性能调优
浅谈 My sql 性能调优
 
Redis介绍
Redis介绍Redis介绍
Redis介绍
 
Ceph中国社区9.19 Ceph FS-基于RADOS的高性能分布式文件系统02-袁冬
Ceph中国社区9.19 Ceph FS-基于RADOS的高性能分布式文件系统02-袁冬Ceph中国社区9.19 Ceph FS-基于RADOS的高性能分布式文件系统02-袁冬
Ceph中国社区9.19 Ceph FS-基于RADOS的高性能分布式文件系统02-袁冬
 
分布式存储与TDDL
分布式存储与TDDL分布式存储与TDDL
分布式存储与TDDL
 
淘宝软件基础设施构建实践
淘宝软件基础设施构建实践淘宝软件基础设施构建实践
淘宝软件基础设施构建实践
 
Redis介绍
Redis介绍 Redis介绍
Redis介绍
 
Sheepdog内部实现机制
Sheepdog内部实现机制Sheepdog内部实现机制
Sheepdog内部实现机制
 
Spark sql培训
Spark sql培训Spark sql培训
Spark sql培训
 
“云存储系统”赏析系列分享三:Sql与nosql
“云存储系统”赏析系列分享三:Sql与nosql“云存储系统”赏析系列分享三:Sql与nosql
“云存储系统”赏析系列分享三:Sql与nosql
 
云计算环境中Ssd在cassandra测试的性能表现
云计算环境中Ssd在cassandra测试的性能表现 云计算环境中Ssd在cassandra测试的性能表现
云计算环境中Ssd在cassandra测试的性能表现
 

Viewers also liked

Drupal MySQL Cluster
Drupal MySQL ClusterDrupal MySQL Cluster
Drupal MySQL ClusterKris Buytaert
 
DIY: A distributed database cluster, or: MySQL Cluster
DIY: A distributed database cluster, or: MySQL ClusterDIY: A distributed database cluster, or: MySQL Cluster
DIY: A distributed database cluster, or: MySQL ClusterUlf Wendel
 
Overview of some popular distributed databases
Overview of some popular distributed databasesOverview of some popular distributed databases
Overview of some popular distributed databasessagar chaturvedi
 
MySQL Tech Tour 2015 - Progettare, installare e configurare MySQL Cluster
MySQL Tech Tour 2015 - Progettare, installare e configurare MySQL ClusterMySQL Tech Tour 2015 - Progettare, installare e configurare MySQL Cluster
MySQL Tech Tour 2015 - Progettare, installare e configurare MySQL ClusterPar-Tec S.p.A.
 
Ramp-Tutorial for MYSQL Cluster - Scaling with Continuous Availability
Ramp-Tutorial for MYSQL Cluster - Scaling with Continuous AvailabilityRamp-Tutorial for MYSQL Cluster - Scaling with Continuous Availability
Ramp-Tutorial for MYSQL Cluster - Scaling with Continuous AvailabilityPythian
 
MySQL HA Solutions
MySQL HA SolutionsMySQL HA Solutions
MySQL HA SolutionsMat Keep
 

Viewers also liked (7)

Drupal MySQL Cluster
Drupal MySQL ClusterDrupal MySQL Cluster
Drupal MySQL Cluster
 
DIY: A distributed database cluster, or: MySQL Cluster
DIY: A distributed database cluster, or: MySQL ClusterDIY: A distributed database cluster, or: MySQL Cluster
DIY: A distributed database cluster, or: MySQL Cluster
 
Overview of some popular distributed databases
Overview of some popular distributed databasesOverview of some popular distributed databases
Overview of some popular distributed databases
 
MySQL Tech Tour 2015 - Progettare, installare e configurare MySQL Cluster
MySQL Tech Tour 2015 - Progettare, installare e configurare MySQL ClusterMySQL Tech Tour 2015 - Progettare, installare e configurare MySQL Cluster
MySQL Tech Tour 2015 - Progettare, installare e configurare MySQL Cluster
 
Mysql cluster
Mysql clusterMysql cluster
Mysql cluster
 
Ramp-Tutorial for MYSQL Cluster - Scaling with Continuous Availability
Ramp-Tutorial for MYSQL Cluster - Scaling with Continuous AvailabilityRamp-Tutorial for MYSQL Cluster - Scaling with Continuous Availability
Ramp-Tutorial for MYSQL Cluster - Scaling with Continuous Availability
 
MySQL HA Solutions
MySQL HA SolutionsMySQL HA Solutions
MySQL HA Solutions
 

Similar to Concurrency model for mysql data processing@rubyconf.tw 2012

Network and Multitasking
Network and MultitaskingNetwork and Multitasking
Network and Multitaskingyarshure Kong
 
JCConf2015: groovy to gradle
 JCConf2015: groovy to gradle JCConf2015: groovy to gradle
JCConf2015: groovy to gradleChing Yi Chan
 
May the source_be_with_you
May the source_be_with_youMay the source_be_with_you
May the source_be_with_youEddie Kao
 
基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理Jacky Chi
 
Hadoop Map Reduce 程式設計
Hadoop Map Reduce 程式設計Hadoop Map Reduce 程式設計
Hadoop Map Reduce 程式設計Wei-Yu Chen
 
Spark调研串讲
Spark调研串讲Spark调研串讲
Spark调研串讲jie cao
 
Spark 巨量資料處理基礎教學
Spark 巨量資料處理基礎教學Spark 巨量資料處理基礎教學
Spark 巨量資料處理基礎教學NUTC, imac
 
Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 zhen chen
 
iOs app 101
iOs app 101iOs app 101
iOs app 101Tom Sun
 
D2_node在淘宝的应用实践_pdf版
D2_node在淘宝的应用实践_pdf版D2_node在淘宝的应用实践_pdf版
D2_node在淘宝的应用实践_pdf版Jackson Tian
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践guestf5121c
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践xcq
 
使用Dsl改善软件设计
使用Dsl改善软件设计使用Dsl改善软件设计
使用Dsl改善软件设计mingjin
 
Node.js在淘宝的应用实践
Node.js在淘宝的应用实践Node.js在淘宝的应用实践
Node.js在淘宝的应用实践taobao.com
 
分布式计算与Hadoop - 刘鹏
分布式计算与Hadoop - 刘鹏分布式计算与Hadoop - 刘鹏
分布式计算与Hadoop - 刘鹏Shaoning Pan
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验QLeelulu
 
Hadoop学习总结
Hadoop学习总结Hadoop学习总结
Hadoop学习总结ordinary2012
 
善用 MySQL 及 PostgreSQL - RDBMS 的逆襲 - part1
善用 MySQL 及 PostgreSQL - RDBMS 的逆襲 - part1善用 MySQL 及 PostgreSQL - RDBMS 的逆襲 - part1
善用 MySQL 及 PostgreSQL - RDBMS 的逆襲 - part1Yi-Feng Tzeng
 

Similar to Concurrency model for mysql data processing@rubyconf.tw 2012 (20)

Network and Multitasking
Network and MultitaskingNetwork and Multitasking
Network and Multitasking
 
Sourcemap
SourcemapSourcemap
Sourcemap
 
JCConf2015: groovy to gradle
 JCConf2015: groovy to gradle JCConf2015: groovy to gradle
JCConf2015: groovy to gradle
 
May the source_be_with_you
May the source_be_with_youMay the source_be_with_you
May the source_be_with_you
 
基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理
 
Hadoop Map Reduce 程式設計
Hadoop Map Reduce 程式設計Hadoop Map Reduce 程式設計
Hadoop Map Reduce 程式設計
 
Spark调研串讲
Spark调研串讲Spark调研串讲
Spark调研串讲
 
Spark 巨量資料處理基礎教學
Spark 巨量資料處理基礎教學Spark 巨量資料處理基礎教學
Spark 巨量資料處理基礎教學
 
Hi Haskell
Hi HaskellHi Haskell
Hi Haskell
 
Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储
 
iOs app 101
iOs app 101iOs app 101
iOs app 101
 
D2_node在淘宝的应用实践_pdf版
D2_node在淘宝的应用实践_pdf版D2_node在淘宝的应用实践_pdf版
D2_node在淘宝的应用实践_pdf版
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践
 
使用Dsl改善软件设计
使用Dsl改善软件设计使用Dsl改善软件设计
使用Dsl改善软件设计
 
Node.js在淘宝的应用实践
Node.js在淘宝的应用实践Node.js在淘宝的应用实践
Node.js在淘宝的应用实践
 
分布式计算与Hadoop - 刘鹏
分布式计算与Hadoop - 刘鹏分布式计算与Hadoop - 刘鹏
分布式计算与Hadoop - 刘鹏
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验
 
Hadoop学习总结
Hadoop学习总结Hadoop学习总结
Hadoop学习总结
 
善用 MySQL 及 PostgreSQL - RDBMS 的逆襲 - part1
善用 MySQL 及 PostgreSQL - RDBMS 的逆襲 - part1善用 MySQL 及 PostgreSQL - RDBMS 的逆襲 - part1
善用 MySQL 及 PostgreSQL - RDBMS 的逆襲 - part1
 

More from Mu-Fan Teng

My experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMy experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMu-Fan Teng
 
WebSocket For Web Rubyists
WebSocket For Web RubyistsWebSocket For Web Rubyists
WebSocket For Web RubyistsMu-Fan Teng
 
20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年Mu-Fan Teng
 
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務Mu-Fan Teng
 
實踐大學教案20140329
實踐大學教案20140329實踐大學教案20140329
實踐大學教案20140329Mu-Fan Teng
 
Rails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroRails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroMu-Fan Teng
 
Eventmachine Websocket 實戰
Eventmachine Websocket 實戰Eventmachine Websocket 實戰
Eventmachine Websocket 實戰Mu-Fan Teng
 
Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Mu-Fan Teng
 
Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Mu-Fan Teng
 
Sinatra Tutorial@Rubyconf.TW2011
Sinatra Tutorial@Rubyconf.TW2011Sinatra Tutorial@Rubyconf.TW2011
Sinatra Tutorial@Rubyconf.TW2011Mu-Fan Teng
 
Ruby程式語言入門導覽
Ruby程式語言入門導覽Ruby程式語言入門導覽
Ruby程式語言入門導覽Mu-Fan Teng
 

More from Mu-Fan Teng (12)

My experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMy experience of Ruby Education in Taiwan
My experience of Ruby Education in Taiwan
 
WebSocket For Web Rubyists
WebSocket For Web RubyistsWebSocket For Web Rubyists
WebSocket For Web Rubyists
 
20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年
 
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
 
實踐大學教案20140329
實踐大學教案20140329實踐大學教案20140329
實踐大學教案20140329
 
Rails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroRails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 Intro
 
Eventmachine Websocket 實戰
Eventmachine Websocket 實戰Eventmachine Websocket 實戰
Eventmachine Websocket 實戰
 
Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013
 
Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享
 
Sinatra Tutorial@Rubyconf.TW2011
Sinatra Tutorial@Rubyconf.TW2011Sinatra Tutorial@Rubyconf.TW2011
Sinatra Tutorial@Rubyconf.TW2011
 
Ruby程式語言入門導覽
Ruby程式語言入門導覽Ruby程式語言入門導覽
Ruby程式語言入門導覽
 
Ruby on discuz
Ruby on discuzRuby on discuz
Ruby on discuz
 

Concurrency model for mysql data processing@rubyconf.tw 2012

  • 1. Concurrency Model for huge MySQL data Mu-Fan Teng(@ryudoawaru) @ RubyConf Taiwan 2012 12年12月8⽇日星期六
  • 2. 緣起 Background 12年12月8⽇日星期六
  • 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⽇日星期六
  • 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⽇日星期六
  • 9. Cause • Too big size for most text editor. • Many mis-encoding text. 12年12月8⽇日星期六
  • 10. Let’s reinvent the wheel! 12年12月8⽇日星期六
  • 11. The new work flow • Connect DB • Transcode • Output db rows to SQL insert statement. • Write SQL file 12年12月8⽇日星期六
  • 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. Thanks for Ruby 1.9’s Awesome Encoding class which supports Big5-UAO. 12年12月8⽇日星期六
  • 14. Reduces almost 80% of encoding problem. 12年12月8⽇日星期六
  • 15. But the file size is too big to wait for transcoding! 12年12月8⽇日星期六
  • 16. So I have to find the concurrency model to make it faster. 12年12月8⽇日星期六
  • 17. Experiment Target • Test the difference of performance between thread and fork model. 12年12月8⽇日星期六
  • 18. H&W Platform • 4 Cores Core2Quad CPU@2.5G • 8GB RAM • 1*SSD • MacOS 10.8 • MRI 1.9.3p194 12年12月8⽇日星期六
  • 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 end 12年12月8⽇日星期六
  • 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)}} end 12年12月8⽇日星期六
  • 21. Result of 100k*4 rows 12年12月8⽇日星期六
  • 25. Circumstance • Thread ‣ CPU utilization rate between 105 and 125 percent. • Fork ‣ The rate changes frequently between processes. 12年12月8⽇日星期六
  • 28. Decompose the steps to find how to skip GVL. 12年12月8⽇日星期六
  • 30. Minify the process to query DB only. 12年12月8⽇日星期六
  • 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)} end 12年12月8⽇日星期六
  • 32. Result of 100k*4 rows 12年12月8⽇日星期六
  • 33. It seems the Mysql2 Gem can skip GVL. 12年12月8⽇日星期六
  • 35. Limit the experiment to I/O operation only. 12年12月8⽇日星期六
  • 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}} end 12年12月8⽇日星期六
  • 38. Result of 100k*4 rows 12年12月8⽇日星期六
  • 39. Change I/O to different files. 12年12月8⽇日星期六
  • 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 end 12年12月8⽇日星期六
  • 42. Implement the same change to the first experiment. 12年12月8⽇日星期六
  • 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 end 12年12月8⽇日星期六
  • 44. Dose not effect any 12年12月8⽇日星期六
  • 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/O 12年12月8⽇日星期六
  • 46. There is no effective and 「all-around」 concurrency model. 12年12月8⽇日星期六
  • 47. The small I/O can’t release GVL. 12年12月8⽇日星期六
  • 49. Matz is not a threading guy 12年12月8⽇日星期六