kingshard(https://github.com/flike/king...开源有一段时间了,有些热心的用户发邮件来咨询kingshard的设计和实现问题。因而周末抽空写了一篇介绍kingshard架构和功能实现的文章,但愿经过本文可以让用户对kingshard有更深的了解。下面分模块来介绍kingshard的核心组件的设计和实现。node
kingshard采用Go开发,充分地利用了Go语言的并发特性。Go语言在并发方面,作了很好的封装,这大大简化了kingshard的开发工做。kingshard的总体工做流程入下所述:git
kingshard工做总体流程可参考下面这幅图。github
kingshard总体架构图以下所示web
要将kingshard的功能作的足够强大,就不得不进行SQL的词法和语义分析。SQL语句的词法分析指的是将SQL语句切分红一个一个的关键字。例如对SQL语句:select name from stu where id < 13
进行词法分析,获得的结果是:{"select","name","from","stu","where","id","<","13"}
。
这样作的目的主要为了生成一棵抽象语法树,也就是你们常说的AST(abstract syntax tree),语义分析就是基于这棵语法树来操做的。语义分析的目的主要有如下几个方面:算法
kingshard并无考虑彻底兼容MySQL全部语法,由于彻底兼容MySQL语法会使得词法和语义分析模块变得异常复杂,并且低效。对于DDL语句其实不必解析,只要能正确转发到后端相应的DB上就能够。sql
kingshard只对部分DML语句(select,update,insert,delete,replace)
进行了解析,这样能够知足绝大部分的分表操做。对于其余语句,kingshard会将其发送到一个默认的DB,或者经过kingshard特有的方式将其发送到指定的DB上,例如:/*node2*/insert into stu(id,name) values(12,'xiaoming')
,对于这种带有注释的的sql语句,kingshard可以识别出,而后将这条sql语句发送到node2节点的Master DB上。数据库
用户使用Mysql Proxy目的很大一部分就是为了下降单台DB的负载,将读压力分担到多台DB上。kingshard支持多个slave,不一样的slave能够配置不一样的读权重,权重越大分担的读请求越多。kingshard读请求负载均衡采用的是权重轮询调度算法。后端
大部分系统采用该算法时,都是转发SQL语句时,动态地计算出本次选取DB的序号。而后将读请求的SQL语句发送到该DB。仔细分析一下,这样作实际上是没有必要的。由于DB的权重是相对固定的,不会常常变更,因此彻底能够计算出一个固定的轮询序列,而后将这个序列保存在一个数组中。这样不须要动态计算,每次读取数组就能够。举个例子来讲,在kingshard的node配置项中配置slave选项:slave:192.168.0.12@2,192.168.0.13@3
kingshard在读取配置信息初始化系统的时候,就生成了一个轮询数组:[0,0,1,1,1]。在kingshard中会将这个数组打乱顺序,变成:[0,1,1,0,1]。这样就避免了动态计算DB下标的问题,对性能提高有必定帮助。数组
首选须要介绍两个概念:安全
发送SQL语句时,kingshard会识别出须要分表的SQL语句,并改写该SQL。例如,客户端发送过来的SQL语句是:select name from stu where id =10;
kingshard收到该SQL语句后,从配置信息中识别出该表是一个Hash类型的分表。根据分表规则,将该SQL改写成:select name from stu_2 where id =10;
而后发送给对应的DB。
kingshard的sharding采用了两级映射的思想,首选根据SQL语句的分表条件计算出这条SQL语句落在哪一个子表上,而后再根据配置信息找到该子表
落在哪一个node上。采用两级映射的思想,对于MySQL的扩容和缩容都能很方便地支持。目前kingshard sharding支持insert, delete, select, update和replace语句, 全部这五类操做都支持跨子表。但写操做仅支持单node上的跨子表,select操做则能够跨node,跨子表。
对于有些表没有分表,操做该表的SQL语句会发往default node。或者用户能够选择在SQL语句前面加上注释,指定该SQL要发往的node,kingshard接收到语句后,识别出注释中指定的node,而后将该SQL发往对应node中合适的DB。例如用户发送/*node1*/select * from member where id=100
,kingshard接收到该SQL后会将其发送到node1的salve上。这样kingshard就能很好地兼容分表和不分表的各类应用场景了。
全部proxy支持shard后都会面临一个问题:支不支持分布式事务?出于性能和可用性考虑,
kingshard只支持单台DB上的事务,不容许跨DB的事务。kingshard处理单DB上的事务流程以下:
kingshard每一个node启动了一个goroutine用于检测后端master和slave的状态。当goroutine持续一段时间(由配置文件中down_after_noalive参数设置)ping不通后端的DB后,会将该DB的状态设置为down,后续kingshard就不会将sql语句发往该DB了。
有时候用户为了安全考虑,但愿只能某几台server可以链接kingshard。在kingshard的配置文件中有一个参数:allow_ips,用于实现客户端白名单机制。当管理员设置了该参数,则意味着只有allow_ips指定的IP可以链接kingshard,其余IP都会被kingshard拒绝链接。若是不设置该参数,则链接kingshard的客户端不受限制。
kingshard的管理端口复用了工做端口,经过特定的关键字(admin)来标示。kingshard是经过对管理端特定的SQL进行词法和语义分析,将SQL语句解析为一条kingshard能够识别的命令。目前支持平滑上下线master和slave,和查看kingshard配置和后端DB状态。后续打算将web页面集成到管理端,这样用户就能够不用输入命令行操做,而是在网页上操做。大大下降用户使用kingshard的门槛。
上述各个模块都是kingshard中比较核心的模块,经过这篇文章的介绍,我想读者应该对kingshard的架构和实现有了初步的了解。不少功能的设计和实现,都是做者慢慢地摸索和实践。若是有读者对kingshard的设计或实现感兴趣或者对上述设计有不一样的想法,欢迎发邮件(flikecn#126.com)给我。
欢迎关注后端技术快讯公众号,有关kingshard的最新消息与后端架构设计类的文章,都会在这个公众号分享。