【问题标题】:JRuby sending a steam over SSL causes high memory usageJRuby 通过 SSL 发送蒸汽会导致高内存使用
【发布时间】:2018-04-21 18:36:14
【问题描述】:

我正在尝试使用 JRuby(使用 jruby-openssl 0.9.21 的 9.1.8.0 )将大型 JSON 文件 ( ~300mb ) 流式传输到 Solr。远程 Solr 服务器正在使用 SSL 身份验证。我在下面包含了我的脚本。

当我使用 JRuby 时,我使用默认的 500mb 几乎立即耗尽了堆空间。使用 MRI,使用量永远不会超过 40mb。不使用 SSL,JRuby 工作正常。 我在纯 Java 中做过类似的过程,但从未遇到过这类问题。不知道这里发生了什么..

感谢您的任何建议...

require 'openssl'
require 'net/http'
require 'json'

PEM_FILE = ENV["CLIENT_CERT"]
SOLR_URL = ENV["SOLR_URL"]

class SolrClient

  DEFAULT_OPTIONS = {
    use_ssl: true,
    verify_mode: OpenSSL::SSL::VERIFY_PEER,
    keep_alive_timeout: 30,
    cert: OpenSSL::X509::Certificate.new(IO.read(PEM_FILE)),
    key:  OpenSSL::PKey::RSA.new(IO.read(PEM_FILE)),
  }


  def initialize(http = nil)
    if http
      @http = http
    else
      @http = Net::HTTP.start('my.solr.url', 443, DEFAULT_OPTIONS)
    end
  end

  def update()
    bytes = File.open('index_batch.json', 'rb').bytes.count.to_s
    stream = File.open('index_batch.json', 'rb')
    puts "starting request..." 
    request = Net::HTTP::Post.new "/solr/archivesspace/update" 
    request['Content-Type'] = 'application/json'
    request['Content-Length'] = bytes
    request.body_stream = stream

    response = @http.request request
    puts response.body
  end

end


SolrClient.new.update

【问题讨论】:

  • 您是将堆大小设置为 500mb 还是您认为是 500mb?
  • 不,只是运行没有任何 -J-Xmx 标志的脚本,它在开始发送请求时立即停止。如果用 -J-Xmx1024m 运行脚本,它会运行一分钟左右,然后用完...上升到 2048m,它会更长...等等。
  • 您可以尝试使用 VisualVM 或类似工具来查看内存的去向(例如 stackoverflow.com/questions/9154785/…),尽管除非您对调试 jruby-openssl 特别感兴趣,否则您可能会发现重写它会更容易Java 中的特殊事物。
  • 是的,我在 VisualVM 中进行了堆转储...... 97.5% 的内存被字节 [] 使用......所以我猜流在发送之前正在被读取。另外..刚刚在 jruby 1.7.9 上尝试过,它运行没有任何问题,所以,是的,看起来像是新版本的 jruby-openssl 的问题......

标签: ruby solr openssl jruby


【解决方案1】:

在jruby github上发了一个issue,几乎立刻就得到了回复:

https://github.com/jruby/jruby/issues/4842

作为临时修复,我正在修补 http:

class Net::HTTPGenericRequest

  def send_request_with_body_stream(sock, ver, path, f)                                                                                                                                      
    unless content_length() or chunked?                                                                                                                                                      
      raise ArgumentError,                                                                                                                                                                   
          "Content-Length not given and Transfer-Encoding is not `chunked'"                                                                                                                  
    end                                                                                                                                                                                      
    supply_default_content_type                                                                                                                                                              
    write_header sock, ver, path                                                                                                                                                             
    wait_for_continue sock, ver if sock.continue_timeout                                                                                                                                     
    if chunked?                                                                                                                                                                              
      chunker = Chunker.new(sock)                                                                                                                                                            
      IO.copy_stream(f, chunker)                                                                                                                                                             
      chunker.finish                                                                                                                                                                         
    else                                                                                                                                                                                     
      # copy_stream can sendfile() to sock.io unless we use SSL.                                                                                                                             
      # If sock.io is an SSLSocket, copy_stream will hit SSL_write()                                                                                                                         
      if  sock.io.is_a? OpenSSL::SSL::SSLSocket                                                                                                                                              
        IO.copy_stream(f, sock.io, 16 * 1024 * 1024) until f.eof?                                                                                                                            
      else                                                                                                                                                                                   
        IO.copy_stream(f, sock.io)                                                                                                                                                           
      end                                                                                                                                                                                    
    end                                                                                                                                                                                      
  end                                                                                                                                                                                        
end 

【讨论】:

    猜你喜欢
    • 2017-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 2020-10-17
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多