MyCat源碼解析(1)


客戶端輸入mysql -h 127.0.0.1 -uroot -proot -DDTEST發生了什麼:mysql

一、首先mycat在啓動的時候 使用一下代碼啓動一個服務線程 NIOAcceptor server = new NIOAcceptor(BufferPool.LOCAL_BUF_THREAD_PREX+ NAME + "Server", system.getBindIp(), system.getServerPort(),frontFactory, reactorPool); server.start(); 二、在NIOAcceptor的構造器中進行了NIO服務端的建立過程     具體以下:     一、打開ServerSocketChannel、用於監聽客戶端的鏈接、他是全部客戶端鏈接的父通道     this.serverChannel = ServerSocketChannel.open();     二、綁定監聽端口、設置爲非阻塞狀態     this.serverChannel.configureBlocking(false); serverChannel.bind(new InetSocketAddress(bindIp, port), 100); 三、建立多路複用器 this.selector = Selector.open(); 四、將ServerSocketChannel註冊到多路複用器上、監聽Accetp事件 this.serverChannel.register(selector, SelectionKey.OP_ACCEPT); 五、在多路複用器NIOAcceptor線程的run方法中不斷的輪訓準備就緒的key,代碼以下 for (;;) { ++acceptCount; try { selector.select(1000L); Set<SelectionKey> keys = selector.selectedKeys(); try { for (SelectionKey key : keys) { if (key.isValid() && key.isAcceptable()) { accept(); } else { key.cancel(); } } } finally { keys.clear(); } } catch (Throwable e) { LOGGER.warn(getName(), e); } } 六、客戶端在終端輸入mysql -h127.0.0.1 -uroot -proot -P8066 -DDTEST的時候、可使用WireShark等抓包工具、發現客戶端首先向服務端發送一個 一個帶SYN標誌的TCP報文到服務器。這是三次握手過程當中的報文 七、此時NIOAcceptor多路複用器發現新的鏈接請求、調用accept方法進行後續的處理、包括TCP的三次握手信息 SocketChannel channel = serverChannel.accept(); 設置爲非阻塞狀態 channel.configureBlocking(false);            八、此時利用客戶端SocketChannel構造一個Connection對象(實現爲MySQLConnection對象)此時Connection對象中保存了新鏈接的客戶端SocketChannel對象 Connection c = factory.make(channel); c.setDirection(Connection.Direction.in); c.setId(ConnectIdGenerator.getINSTNCE().getId()); InetSocketAddress remoteAddr = (InetSocketAddress) channel.getRemoteAddress(); c.setHost(remoteAddr.getHostString()); c.setPort(remoteAddr.getPort()); 九、將第八步生成的Connection對象傳遞到網絡處理器NIOReactor中進行處理 //派發此鏈接到某個Reactor處理 NIOReactor reactor = reactorPool.getNextReactor(); 十、Reactor爲網絡反應器、具體建立過程在MyCatServer中、 在Reactor中有一個內部類RW爲一個Runnable任務、 在RW 中保存着一個線程安全的鏈表隊列、用於保存步驟8生成的Connection對象、放在隊列中、基於消費者生產者的模式去處理連接Connection請求 十一、在MyCat啓動的時候、建立了自定義的幾個網絡反應器線程、線程的執行方法體被NIOReactor封裝在一個RW任務當中、 具體代碼在MyCatServer當中 //網絡事件反應 NIOReactorPool reactorPool = new NIOReactorPool(BufferPool.LOCAL_BUF_THREAD_PREX + "NIOREACTOR", processorCount); 十二、在RW的run方法中發現Connection隊列中不爲空、說明已經有了新的鏈接任務了、則使用第8步驟構造的Connection註冊客戶端鏈接通道Channel processKey = channel.register(selector, SelectionKey.OP_READ, this); this.handler.onConnected(this); 1三、使用Connection當中NIOHandler對象來處理這次鏈接請求具體友MYSQLFrontConnectionHandler來處理 發送TCP三次認證數據 byte[] rand1 = RandomUtil.randomBytes(8); byte[] rand2 = RandomUtil.randomBytes(12); // 保存認證數據 byte[] seed = new byte[rand1.length + rand2.length]; System.arraycopy(rand1, 0, seed, 0, rand1.length); System.arraycopy(rand2, 0, seed, rand1.length, rand2.length); this.seed = seed; // 發送握手包信息 HandshakePacket hs = new HandshakePacket(); hs.packetId = 0; hs.protocolVersion = Versions.PROTOCOL_VERSION; hs.serverVersion = Versions.SERVER_VERSION; hs.threadId = id; hs.seed = rand1; hs.serverCapabilities = getServerCapabilities(); hs.serverCharsetIndex = (byte) (charsetIndex & 0xff); hs.serverStatus = 2; hs.restOfScrambleBuff = rand2; hs.write(this); 1四、隨後客戶端服務端完成TCP三次握手信息、處理流程和以上相同 當處理完成以後、服務器才接受到客戶端你發送過來的連接語句 mysql -h127.0.0.1 -uroot -proot -P8066 -DDTEST 完成認證具體請求