序言
作为一名后端java开发工程师,在日常的开发过程中,我们除了与业务打交道以外,我们还需要面对我们自己编写的各式样的复杂代码(这其中包括了编写运行与服务端以及数据库端)。
早期在接触数据库技术的时候,一直对SQL以及关系型数据库有兴趣,但是由于各种各样的原因不得不停止对数据库的进一步探索。平常开发过程中所接触到的都是面向于业务,如何设计表结构,如何设计字段,如何编写各个查询接口所需要的复杂的SQL。这些SQL背后的运行的原理,一直无法去深入的理解。
一个典型的例子就是,生产上某个SQL运行导致数据库服务器的硬件CPU飚高,导致数据库内存久久不能释放,运维同事各种各样的紧急处理操作。而作为开发者,实在无法去理解,一个面向集合的语言,是什么原因导致自己编写的SQL在生产环境上出现如此的问题。
再有对于数据库索引的理解。之前只是知道索引是为了减少扫描磁盘次数而建立的一种数据结构,是持久化在硬盘上的一种结构,但是并不清楚B+Tree索引背后的原理。
鉴于此,我在这里撰写一个系列的篇章,我将如何基于现有的数据库资料来实现一个数据库,它需要兼容mysql协议。
我打开了github,除了官方公布的mysql数据库源码,
MySQL-SERVERgithub.com还有PingCAP的tidb
tidbgithub.com这些数据库在实际的生产环境上大量的被用于各种场景的使用。
就mysql本身而言,mysql的内核引擎分为了多种,有innodb,有myisam。
就mysql的变种,facebook的mysql,阿里的mysql,以及其他大厂的mysql。
在开始我的介绍之前,我看到了一位大佬的mysql实战操作。
https://github.com/alchemystar/Freedomgithub.com MySQL多版本并发控制机制(MVCC)-源码浅析 - 无毁的湖光-Al的个人空间 - OSCHINA - 中文开源技术交流社区my.oschina.net这里向大佬致敬,我的代码,不少思路是参考了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这里给出了muduo的github地址
https://github.com/chenshuo/muduogithub.com在陈硕大佬的介绍下,我知道了muduo网络库的优势以及特点。
muduo 是一个基于 Reactor 模式的现代 C++ 网络库,它采用非阻塞 IO 模型,基于事件驱动和回调,原生支持多核多线程,适合编写 Linux 服务端多线程网络应用程序。
在日常开发中,念念不忘的高并发,在这里出现了。所谓的非阻塞IO模型,实质就是和node.js中所使用的模型的是差不多的。而事实是大佬的依赖中就再一次使用了libuv。
在陈硕大佬给出的demo实例中我们看到了如下项目结构,因此我们需要借助他给出的项目,来定制化我们的目录结构。
我们需要使用一个IDE,也就是Clion,jetbrains出品的。
在完成了clion操作后,我们开始创建一个叫做XSQL的项目,C++编译器支持C++14,为了不那么高,我改成了C++11。
创建成功后,clion自带的cmake,会帮助我把cmakelist生成出来。
它大概长这样:
当前这个项目只能运行helloworld,这对我们需要去编写一个mysql是远远不够的,对我们去实现mysql的内部机制是远远不够的。我们需要引入陈硕大佬的网络库。
好在大佬给出了muduo的cmakelist以及muduo的安装脚本过程。
为了能够成功的安装muduo网络库,我参考了网上的过程
LINUX实战:Ubuntu下muduo库的安装与使用-LINUX入门-维易PHP培训学院www.vephp.com这样的过程对我而言是一个陌生的过程,为了不出现错误,我在安装的时候,决定基于大佬官方给出的安装教程
https://github.com/chenshuo/muduo-tutorialgithub.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,控制台上会有如下的字样。
说明我们引入的boost以及muduo网络库是成功的。
至于上面各式各样的cmake编译参数是什么含义,本文末端有介绍的链接。
在项目路径下,我们创建文件夹server,用来定义一个run起来的webserver。
然后创建一个叫做xdbserver的类文件,它包括了头文件以及body。
在xdbserver中,我们暂且定义如下
显然,在C++中,类当中的public和private的作用,与java中的public和private是一样的。
我们定义了XdbServer对象,以及该对象的start()方法。用于成功启动我们所编写的数据库网络实例。
在XdbServer的构造函数中,我们需要传入两个参数,即eventloop对象(事件循环),以及实际的网络ip地址。
私有对象是一个muduo::net::tcpserver类型的server。我们后面的所有的网络请求,都将依赖于该server_对象。
在大佬的muduo网络库中,我们看到server_对象的具体定义如下:
可见该类是不可变对象,也就是在运行时是不可以通过复制该对象来生成一个新的对象。就道理而言,不大可能再拷贝出一个新的server对象出来,因此,就所有的网络请求,该对象是唯一的。
在该类中清晰的定义了线程池,线程的回调函数,ip地址,以及服务器名称等等。也就是说,我们封装的xdbserver,实质是该tcpserver的一个远房亲戚。
我们需要更改我们的关于xdbserver的定义,让我们的xdbserver也是一个不可复制的对象。
如下所示
我们在XdbServer.cpp中实现body。
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();
}
然后编译。
我们惊喜的发现控制台上已经有了结果了。
一股自豪感和成就感出现了。
本章到这里就结束了。代码将在后面放到github上。
下一章,我们将实现一个交互性质的terminal界面,以及如何实现terminal和服务器端的交互。
参考书目:
- 《MySQL 技术内幕 InnoDB存储引擎》----姜承尧。
- 《数据库系统内幕》Alex Petrov
- 《Linux多线程服务端编程 使用muduo C++ 网络库》 陈硕
概念
1,reactor模型
每天晒白牙:Reactor线程模型zhuanlan.zhihu.com2,
libuv | Cross-platform asynchronous I/Olibuv.org3,
学习C++有没有必要学习boost库?www.zhihu.com4,cmake的介绍
https://cmake.org/cmake.org5,cmake的学习和入门
https://github.com/xiaoweiChen/CMake-Cookbookgithub.com