mysql事件不运行的原因_手动实现MySQL需要哪些技术?(1)

f835caabdb74916c836f77ebab54e9e5.png

序言

作为一名后端java开发工程师,在日常的开发过程中,我们除了与业务打交道以外,我们还需要面对我们自己编写的各式样的复杂代码(这其中包括了编写运行与服务端以及数据库端)。

早期在接触数据库技术的时候,一直对SQL以及关系型数据库有兴趣,但是由于各种各样的原因不得不停止对数据库的进一步探索。平常开发过程中所接触到的都是面向于业务,如何设计表结构,如何设计字段,如何编写各个查询接口所需要的复杂的SQL。这些SQL背后的运行的原理,一直无法去深入的理解。

一个典型的例子就是,生产上某个SQL运行导致数据库服务器的硬件CPU飚高,导致数据库内存久久不能释放,运维同事各种各样的紧急处理操作。而作为开发者,实在无法去理解,一个面向集合的语言,是什么原因导致自己编写的SQL在生产环境上出现如此的问题。

再有对于数据库索引的理解。之前只是知道索引是为了减少扫描磁盘次数而建立的一种数据结构,是持久化在硬盘上的一种结构,但是并不清楚B+Tree索引背后的原理。

鉴于此,我在这里撰写一个系列的篇章,我将如何基于现有的数据库资料来实现一个数据库,它需要兼容mysql协议。

我打开了github,除了官方公布的mysql数据库源码,

MySQL-SERVER​github.com

还有PingCAP的tidb

tidb​github.com

这些数据库在实际的生产环境上大量的被用于各种场景的使用。

就mysql本身而言,mysql的内核引擎分为了多种,有innodb,有myisam。

就mysql的变种,facebook的mysql,阿里的mysql,以及其他大厂的mysql。

在开始我的介绍之前,我看到了一位大佬的mysql实战操作。

https://github.com/alchemystar/Freedom​github.com MySQL多版本并发控制机制(MVCC)-源码浅析 - 无毁的湖光-Al的个人空间 - OSCHINA - 中文开源技术交流社区​my.oschina.net
f806083e31db519899c117b08f1a8b2c.png

这里向大佬致敬,我的代码,不少思路是参考了alchemystar的代码,帮助了我加深了对mysql的理解。

本系列将面向于和我一样的C++新手或者从事java想深入理解各个中间件的人,各位C++大佬看了我的代码,请批评。

第一章

muduo的hello world

大佬是用java实现的mysql的实现。为了和大佬有所区别,我采用了C++来实现mysql。

我们都知道mysql数据库服务器在实际的过程中有两种方式来实现链接:

一是TCP/IP协议(常见的jdbc协议);二是socket方式(也就是所谓的套接字)。

在服务器上,通常为了安装和管理的方便的,是走socket协议。这个socket协议在本系列当中不做详细的描述。本章从tcp/ip协议方式介绍我是怎么实现链接的。

在考察了大佬alchemystar的代码后,我发现他是基于netty来实现了mysql协议的管理解析,mysql链接的管理。那么在C++中,我就采用了陈硕大佬的muduo(木铎?)网络库来实现数据库tcp/ip协议的实现处理。

Muduo首页、文档和下载 - Linux C++ 网络库 - OSCHINA - 中文开源技术交流社区​www.oschina.net
67eff9962f465a7699f5b2ba3ba9e73a.png

这里给出了muduo的github地址

https://github.com/chenshuo/muduo​github.com

在陈硕大佬的介绍下,我知道了muduo网络库的优势以及特点。

muduo 是一个基于 Reactor 模式的现代 C++ 网络库,它采用非阻塞 IO 模型,基于事件驱动和回调,原生支持多核多线程,适合编写 Linux 服务端多线程网络应用程序。

在日常开发中,念念不忘的高并发,在这里出现了。所谓的非阻塞IO模型,实质就是和node.js中所使用的模型的是差不多的。而事实是大佬的依赖中就再一次使用了libuv。

8494e13f34cefa8770ef9eda81fd4955.png

在陈硕大佬给出的demo实例中我们看到了如下项目结构,因此我们需要借助他给出的项目,来定制化我们的目录结构。

我们需要使用一个IDE,也就是Clion,jetbrains出品的。

35b8c436b4ddcc85b2bab494de53d775.png

在完成了clion操作后,我们开始创建一个叫做XSQL的项目,C++编译器支持C++14,为了不那么高,我改成了C++11。

8c4b41f2bf189eefc4a4972b48c4d518.png

创建成功后,clion自带的cmake,会帮助我把cmakelist生成出来。

它大概长这样:

e7adf0c631540081e8327b0ed04ba636.png

当前这个项目只能运行helloworld,这对我们需要去编写一个mysql是远远不够的,对我们去实现mysql的内部机制是远远不够的。我们需要引入陈硕大佬的网络库。

好在大佬给出了muduo的cmakelist以及muduo的安装脚本过程。

为了能够成功的安装muduo网络库,我参考了网上的过程

LINUX实战:Ubuntu下muduo库的安装与使用-LINUX入门-维易PHP培训学院​www.vephp.com

86b406d11ce11cceed8570e8cf33bcf8.png

这样的过程对我而言是一个陌生的过程,为了不出现错误,我在安装的时候,决定基于大佬官方给出的安装教程

https://github.com/chenshuo/muduo-tutorial​github.com

现在得知如下,安装某一版本的muduo网络库的时候,muduo依赖了boost库。那么boost库是用来干嘛的?

这里给出boost库的介绍。

https://www.boost.org/​www.boost.org

原来C++学习起来那么复杂的一个原因就是,各个厂商对C++的编译器编译是不一样的,也就是除了系统函数的调用以外,不能保证同样一段代码在不同的系统上运行的结果是一致的。各个公司对一些函数的实现是不一致的,而官方又没有内置的API供实际的开发者去调用,因此,有必要像jdk当中的“java.lang.”或者“java.util.”一样,提供一些基本函数给开发者去使用,从而降低C++在实际开发的难度。

说白了还是java好,“一次编写,处处运行”。

限于篇幅这里就不介绍了。

我们照着如上的安装教程,我们安装boost以及相关依赖后,我们继续我们编写代码的操作。

cmake_minimum_required(VERSION 3.15)
project(XSQL)

set(CMAKE_CXX_STANDARD 11)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "release-install-cpp11")
endif()
message(${CMAKE_BUILD_TYPE})
message(MUDUO_PATH)
if (NOT MUDUO_PATH)
    set(MUDUO_PATH "/home/$ENV{USER}/wk/build/release-install-cpp11")
endif ()
message("开始发现")
message(${MUDUO_PATH})
set(CXX_FLAGS
        -g
        # -DVALGRIND
        # -DMUDUO_STD_STRING
        -Wall
        -Wextra
        # -m32
        #-Werror
        -Wconversion
        -Wno-unused-parameter
         -Wold-style-cast
        -Woverloaded-virtual
        -Wpointer-arith
        #-Wshadow
        -Wwrite-strings
        -march=native
        # -MMD
         -std=c++0x
        -rdynamic
        )
string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}")

set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS_DEBUG "-O0")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -finline-limit=1001 -DNDEBUG")
message(${PROJECT_BINARY_DIR})
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

find_path(Muduo_INCLUDE_DIR muduo "${MUDUO_PATH}/include")
find_path(Muduo_LIBRARY_DIR libmuduo_net.a "${MUDUO_PATH}/lib")
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} ${Muduo_LIBRARY_DIR})
message(STATUS ${Muduo_INCLUDE_DIR})
message(STATUS ${Muduo_LIBRARY_DIR})

include_directories(${Muduo_INCLUDE_DIR})
find_library(muduo_base muduo_base)
find_library(muduo_net muduo_net)
message(STATUS ${muduo_base})
message(STATUS ${muduo_net})

set(Boost_USE_STATIC_LIBS        ON)
set(Boost_USE_MULTITHREADED      ON)
set(BOOST_ROOT "/usr/include/boost")
find_package(Boost REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
message(STATUS ${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR})



find_package(Boost
        COMPONENTS
        serialization
        system
        filesystem
        program_options
        regex
        )
add_executable(XSQL ${src_dir} main.cpp
        )


link_directories(... ${Boost_LIBRARY_DIRS})
target_link_libraries(XSQL ${muduo_net})
target_link_libraries(XSQL ${muduo_base})
target_link_libraries(XSQL pthread rt ${Boost_LIBRARIES})

我们reload下我们的代码cmakelist,控制台上会有如下的字样。

037337710c41d4e9bff4ce44f20cb4d5.png

说明我们引入的boost以及muduo网络库是成功的。

至于上面各式各样的cmake编译参数是什么含义,本文末端有介绍的链接。

在项目路径下,我们创建文件夹server,用来定义一个run起来的webserver。

然后创建一个叫做xdbserver的类文件,它包括了头文件以及body。

在xdbserver中,我们暂且定义如下

deb8479f9a22d4647a95fd2fbaef00f2.png

显然,在C++中,类当中的public和private的作用,与java中的public和private是一样的。

我们定义了XdbServer对象,以及该对象的start()方法。用于成功启动我们所编写的数据库网络实例。

在XdbServer的构造函数中,我们需要传入两个参数,即eventloop对象(事件循环),以及实际的网络ip地址。

私有对象是一个muduo::net::tcpserver类型的server。我们后面的所有的网络请求,都将依赖于该server_对象。

在大佬的muduo网络库中,我们看到server_对象的具体定义如下:

e35532c754c326230ee8995c39837806.png

可见该类是不可变对象,也就是在运行时是不可以通过复制该对象来生成一个新的对象。就道理而言,不大可能再拷贝出一个新的server对象出来,因此,就所有的网络请求,该对象是唯一的。

在该类中清晰的定义了线程池,线程的回调函数,ip地址,以及服务器名称等等。也就是说,我们封装的xdbserver,实质是该tcpserver的一个远房亲戚。

我们需要更改我们的关于xdbserver的定义,让我们的xdbserver也是一个不可复制的对象。

如下所示

048f80a421631bffaf5f9eb083539bae.png

我们在XdbServer.cpp中实现body。

77344d1c24556adcca9ec1dfda24fca7.png
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
XdbServer::XdbServer(EventLoop* loop,const InetAddress& listenAddress) : server_(loop,listenAddress,"XDBServer"){
    std::cout<<"所传入的IP地址为:"<<listenAddress.toIpPort()<<std::endl;
}

void XdbServer::start() {
    this->server_.start();
    std::cout<<"恭喜你,你已经成功的启动了服务器"<<std::endl;
}

为了能够让我们的这个服务器真正的run起来,我们需要在我们的主方法中做如下的处理,也就是main.cpp中。

为了能够让我们的这个服务器真正的run起来,我们需要在我们的主方法中做如下的处理,也就是main.cpp中。

int main() {
    std::cout << "Hello, World!" << std::endl;
    muduo::net::EventLoop loop;
    muduo::net::InetAddress listenAddr(3307);
    XdbServer miniServer(&loop,listenAddr);
    miniServer.start();
    loop.loop();
}

然后编译。

我们惊喜的发现控制台上已经有了结果了。

2461cd449168f4a18afe0c362fa3a29c.png

一股自豪感和成就感出现了。

本章到这里就结束了。代码将在后面放到github上。

下一章,我们将实现一个交互性质的terminal界面,以及如何实现terminal和服务器端的交互。

参考书目:

  1. 《MySQL 技术内幕 InnoDB存储引擎》----姜承尧。
  2. 《数据库系统内幕》Alex Petrov
  3. 《Linux多线程服务端编程 使用muduo C++ 网络库》 陈硕

概念

1,reactor模型

每天晒白牙:Reactor线程模型​zhuanlan.zhihu.com
81ce619d09ddc6c95eccd84a6abc8b4d.png

2,

libuv | Cross-platform asynchronous I/O​libuv.org

3,

学习C++有没有必要学习boost库?​www.zhihu.com

4,cmake的介绍

https://cmake.org/​cmake.org

5,cmake的学习和入门

https://github.com/xiaoweiChen/CMake-Cookbook​github.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值