天天看點

pgpool-II的性能缺陷(二)

接上文 pgpool-II的性能缺陷:

前文已經說到,pgpool-II在replication mode狀态下,是順次而非并行執行SQL文給各個DB節點。

從Source的角度,可以看到:

SimpleQuery → pool_send_and_wait  → send_simplequery_message      
/*                                    
 * Process Query('Q') message                                    
 * Query messages include an SQL string.                                    
 */                                    
POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, 
                POOL_CONNECTION_POOL *backend, int len, char *contents){
    ……                                
    /* log query to log file if necessary */                                
    if (pool_config->log_statement){                                
        pool_log("statement: %s", contents);                            
    }else{                                
        pool_debug("statement2: %s", contents);                            
    }                                
    ……                                
    string = query_context->original_query; 
    if (!RAW_MODE){                                
        ……                            
        /*                            
         * Query is not commit/rollback                            
         */                            
        if (!commit){                            
            char *rewrite_query;                        
            ……                        
            /*                        
             * Optimization effort: If there's only one session, we do 
             * not need to wait for the master node's response, and 
             * could execute the query concurrently.                        
             */                        
            if (pool_config->num_init_children == 1){                        
                /* Send query to all DB nodes at once */                    
                status = pool_send_and_wait(query_context, 0, 0); 
                /*                    
                free_parser();                    
                */                    
                return status;                    
            }                     
                                    
            /* Send the query to master node */                        
            if (pool_send_and_wait(query_context, 1, MASTER_NODE_ID) 
                       != POOL_CONTINUE) {                        
                free_parser();                    
                return POOL_END;                    
            }                        
        }                         
        /*                            
         * Send the query to other than master node.                            
         */                            
        if (pool_send_and_wait(query_context, -1, MASTER_NODE_ID) 
               != POOL_CONTINUE{
            free_parser();                        
            return POOL_END;                        
        }                            
        ……                            
    }else{                                
        ……                            
    }                                
    return POOL_CONTINUE;                                
}                                
                                    
      

/*

* Send simple query and wait for response

* send_type:

* -1: do not send this node_id

* 0: send to all nodes

* >0: send to this node_id

*/

POOL_STATUS pool_send_and_wait(POOL_QUERY_CONTEXT *query_context,

int send_type, int node_id)

{

  ……

  /* Send query */

  for (i=0;i<NUM_BACKENDS;i++){

     ……

     per_node_statement_log(backend, i, string);

    if ( send_simplequery_message(CONNECTION(backend, i),

           len, string, MAJOR(backend)) != POOL_CONTINUE) { 

          return POOL_END;

    }

  }

  /* Wait for response */

    ……

    if (wait_for_query_response(frontend, CONNECTION(backend, i),

          MAJOR(backend)) != POOL_CONTINUE){

           /* Cancel current transaction */

           CancelPacket cancel_packet;

          cancel_packet.protoVersion = htonl(PROTO_CANCEL);

          cancel_packet.pid = MASTER_CONNECTION(backend)->pid;

          cancel_packet.key= MASTER_CONNECTION(backend)->key;

          cancel_request(&cancel_packet);

  }

return POOL_CONTINUE;

}

/* Send query */ 一段,無阻塞方式向各節點發送SQL文。      
/* Wait for response */ 一段,雖然也是個循環,但是是串行。
不過好在向各節點發SQL文的時候,幾乎是同時地發送指令,
是以 Wait for response 對一個節點檢查獲得SQL文執行結束消息以後,
幾乎同時也會獲得下一個節點SQL文執行結束的消息。

綜合以上:如果對一個節點單獨執行一段批處理耗時1小時,那麼在replication mode 多個節點運作條件下,執行時間将變成 2小時。

至于為何 pgpool-II把對 Master Node和 其他Node的執行分開,也許有特殊考慮,也許是為了保證Master Node的正确性。