从Ruby长期运行Redshift事务

Tim*_*Tim 3 ruby pg amazon-redshift

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

我的代码如下:

conn = RedshiftHelper.get_redshift_connection
begin
  conn.transaction do
    # run my queries
  end
ensure
  conn.flush
  conn.finish
end
Run Code Online (Sandbox Code Playgroud)

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

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

Tim*_*Tim 5

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

  1. Redshift基于Postgres 8.0.要检查它,使用psql连接到Redshift实例,并看到它显示"服务器版本8.0"
  2. Keepalive请求在tcp socket(链接)级别指定.
  3. Postgres 8.0在指定连接字符串时不支持keepalive选项(链接到9.0版本更改,libpq上的E.19.3.9.1节)
  4. Ruby中的PG gem是关于libpq的包装器

根据上述事实,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
Run Code Online (Sandbox Code Playgroud)

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

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