• dbporxy-mysql 协议流转图


     dbproxy 支持 in 查询, 当in 中的字段 属于不同的分表时, QPS约为 5000左右, 如果为 等值查询,  qps的30000左右

    主要原因是 对于in操作,会产生多个不同分表的sql, 这些sql的发送完全是顺序的, 发送第二个sql, 要完全等到 第一个SQL结果的返回,

     src/network-mysqld.c

    void network_mysqld_con_handle(int event_fd, short events, void *user_data) {
        switch (con->state) {
             case CON_STATE_INIT:
                //执行NETWORK_MYSQLD_PLUGIN_PROTO(proxy_init)
                plugin_call(srv, con, con->state);
                break;
    
            case CON_STATE_CONNECT_SERVER:
                //执行NETWORK_MYSQLD_PLUGIN_PROTO(proxy_connect_server)
                //准备发给client的随机挑战数
                plugin_call(srv, con, con->state);
                break;
    
            case CON_STATE_SEND_HANDSHAKE: 
                //向client发送挑战随机数
                network_mysqld_write(srv, con->client);
                
                //此处没有对应的函数指针, 只是设置下state 为 CON_STATE_READ_AUTH;
                plugin_call(srv, con, con->state);
                break;
    
            case CON_STATE_READ_AUTH:
                //读取client返回数据
                network_mysqld_read(srv, recv_sock);
                
                //NETWORK_MYSQLD_PLUGIN_PROTO(proxy_read_auth) 设置状态为CON_STATE_SEND_AUTH_RESULT
                plugin_call(srv, con, con->state);
            
            case CON_STATE_SEND_AUTH_RESULT:
                //向client写验证返回数据
                network_mysqld_write(srv, con->client);
    
                //没有对应的函数指针, 设置状态为 CON_STATE_READ_QUERY, 在这里开始 读取client 发送来的sql
                plugin_call(srv, con, con->state);
                break;
            
            case CON_STATE_READ_QUERY:
                network_socket *recv_sock = con->client;
                network_mysqld_read(srv, recv_sock);
                
                //执行NETWORK_MYSQLD_PLUGIN_PROTO(proxy_read_query), 读取用户sql, 设置状态为CON_STATE_SEND_QUERY
                plugin_call(srv, con, con->state);
                break;
    
            case CON_STATE_SEND_QUERY:
                //发送到server
                network_mysqld_write(srv, con->server);
    
                //设置状态 CON_STATE_READ_QUERY_RESULT
                break;
    
            case CON_STATE_READ_QUERY_RESULT: 
                //读取server返回数据
                network_mysqld_read(srv, recv_sock);
    
                //执行NETWORK_MYSQLD_PLUGIN_PROTO(proxy_read_query_result), 设置状态为CON_STATE_SEND_QUERY_RESULT
                plugin_call(srv, con, con->state);
                break;
    
             case CON_STATE_SEND_QUERY_RESULT:
                //先发送给client
                network_mysqld_write(srv, con->client);
    
                //执行NETWORK_MYSQLD_PLUGIN_PROTO(proxy_send_query_result) 
                ////如果st->injected.queries队列中无数据, 设置状态为CON_STATE_READ_QUERY, 读取client 的新sql
                //否则, 继续向server发送队列中的sql
                plugin_call(srv, con, con->state)
                break;
        }
    }

     plugins/proxy/proxy-plugin.c

    //初始化
    NETWORK_MYSQLD_PLUGIN_PROTO(proxy_init) {
        network_mysqld_con_lua_t *st = con->plugin_con_state;
        st = network_mysqld_con_lua_new();
        con->plugin_con_state = st;
        con->state = CON_STATE_CONNECT_SERVER;
        return NETWORK_SOCKET_SUCCESS;
    }
    
    //连接backend, 就是准备些随机挑战数,  用于连接real mysql 用
    NETWORK_MYSQLD_PLUGIN_PROTO(proxy_connect_server) {
        con->state = CON_STATE_SEND_HANDSHAKE;
    }
    
    //读取client发来的验证信息
    NETWORK_MYSQLD_PLUGIN_PROTO(proxy_read_auth) {
        con->state = CON_STATE_SEND_AUTH_RESULT;
    }
    
    
    NETWORK_MYSQLD_PLUGIN_PROTO(proxy_read_query) {
        network_injection_queue_reset(st->injected.queries);
        sqls = sql_parse(con, tokens);
        for (i = 0; i < sqls->len; ++i) {
            inj = injection_new(id, sqls->pdata[i]);
            inj->resultset_is_needed = TRUE;
            g_queue_push_tail(st->injected.queries, inj);
        }
    
        inj = g_queue_peek_head(st->injected.queries);
        network_mysqld_queue_reset(send_sock);
        network_mysqld_queue_append(send_sock, send_sock->send_queue, S(inj->query));
    
        con->state = CON_STATE_SEND_QUERY;
    }
    
    
    NETWORK_MYSQLD_PLUGIN_PROTO(proxy_read_query_result) {
        if (0 != st->injected.queries->length) {
            //在读取server返回数据时, 弹出st->injected.queries的头元素
            inj = g_queue_pop_head(st->injected.queries);
    
            con->state = CON_STATE_READ_QUERY;
        }
    }
    
    
    //如果st->injected.queries队列中无数据, 设置状态为CON_STATE_READ_QUERY, 读取client 的新sql
    //否则, 继续向server发送队列中的sql
    NETWORK_MYSQLD_PLUGIN_PROTO(proxy_send_query_result) {
        if (st->injected.queries->length == 0) {
            con->state = CON_STATE_READ_QUERY;
            return NETWORK_SOCKET_SUCCESS;
        }
        //发送给client后, 将st->injected.queries的头元素 放到send_queue中
        inj = g_queue_peek_head(st->injected.queries);
        network_mysqld_queue_reset(send_sock);
        network_mysqld_queue_append(send_sock, send_sock->send_queue, S(inj->query));
        con->state = CON_STATE_SEND_QUERY;
        return NETWORK_SOCKET_SUCCESS;
    }
    network_mysqld_con_lua_t *network_mysqld_con_lua_new() {
        network_mysqld_con_lua_t *st;
        st = g_new0(network_mysqld_con_lua_t, 1);
        st->injected.queries = network_injection_queue_new();
        return st;
    }
  • 相关阅读:
    分布式系统理论基础
    分布式系统理论基础
    RPC框架实现
    分布式服务协调员zookeeper
    LSM Tree存储组织结构介绍
    协程 及 libco 介绍
    回顾2013——新的旅程
    从prototype beandefinition 谈 spring 的关闭流程和 prototype 的特性
    调研 中央空调 地暖 水暖
    物联网安全设计
  • 原文地址:https://www.cnblogs.com/taek/p/9819239.html
Copyright © 2020-2023  润新知