从Ruby长期运行Redshift事务

时间:2014-10-10 01:09:09

标签: ruby amazon-redshift pg

我使用Ruby pg gem在事务中运行了几个sql语句。我遇到的问题是由于防火墙设置,连接超时了这些查询。建议的解决方案here不起作用,因为它需要jdbc连接字符串,而我在Ruby中(jRuby不是一个选项)。将驱动程序移动到AWS以删除防火墙也不是一种选择。

我所拥有的代码如下:

conn = RedshiftHelper.get_redshift_connection
begin
  conn.transaction do
    # run my queries
  end
ensure
  conn.flush
  conn.finish
end

我现在正在研究PG异步API。我想知道我是否可以使用is_busy来防止防火墙超时,或者是那种效果。我找不到关于这个主题的好文档。感谢任何提示。

PS:我已经为单个查询解决了这个问题 - 我可以异步触发它并使用系统STV_INFLIGHT Redshift table跟踪它的完成.Transaction不能这样工作,因为我必须保持连接打开。

2 个答案:

答案 0 :(得分:5)

好的,我把它钉了下来。以下是事实:

  1. Redshift基于Postgres 8.0。要检查它,请使用psql连接到Redshift实例,并看到它显示“server version 8.0”
  2. Keepalive请求在tcp套接字(link)的级别上指定。
  3. Postgres 8.0在指定连接字符串时不支持keepalive选项(link到9.0版本更改,libpq上的E.19.3.9.1节)
  4. Ruby中的PG gem是关于libpq的包装器
  5. 根据以上事实,Redshift不支持tcp keepalive。但是,PG允许您检索已建立连接中使用的套接字。这意味着即使libpq没有设置keepalive功能,我们仍然可以手动使用它。因此解决方案:

     class Connection
    
          attr_accessor :socket, :pg_connection
    
          def initialize(conn, socket)
            @socket = socket
            @pg_connection = conn
          end
    
          def method_missing(m, *args, &block)  
            @pg_connection.send(m, *args, &block)
          end        
    
          def close
            @socket.close
            @pg_connection.close
          end
    
          def finish
            @socket.close
            @pg_connection.close
          end
        end     
    
    def get_connection
          conn = PGconn.open(...)
          socket_descriptor = conn.socket
          socket = Socket.for_fd(socket_descriptor)
          # Use TCP keep-alive feature
          socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
          # Maximum keep-alive probes before asuming the connection is lost
          socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPCNT, 5)
          # Interval (in seconds) between keep-alive probes
          socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPINTVL, 2)
          # Maximum idle time (in seconds) before start sending keep-alive probes
          socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPIDLE, 2)
          socket.autoclose = true
          return Connection.new(conn, socket)
     end
    

    我之所以引入代理Connection类,是因为Ruby在超出范围时倾向于垃圾收集IO对象(如套接字)。这意味着我们现在需要连接和套接字在同一范围内,这是通过此代理类实现的。我的Ruby知识不深,所以可能有更好的方法来处理套接字对象。

    这种方法有效,但我很乐意了解是否有更好/更清洁的解决方案。

答案 1 :(得分:0)

The link you provided has the answer。我想你只想按照顶部的部分,它有3个不同操作系统的设置,选择你正在运行代码的那个(客户端到亚马逊服务)。

查看此部分:更改TCP / IP超时设置 - 这是运行代码的操作系统(即Amazon服务的客户端可能是您的服务器)

Linux - 如果您的客户端在Linux上运行,请以root用户身份运行以下命令。

- 详情遗漏 -

Windows - 如果您的客户端在Windows上运行,请在HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ Tcpip \ Parameters下编辑以下注册表设置的值:

- 详情遗漏 -

Mac - 如果您的客户端是Mac,请使用以下值创建或修改/etc/sysctl.conf文件:

- 省略详情 -