上篇内容咱们讲到 OBProxy 的问题排查,将大家在应用 OBProxy 时可能遇到的问题一一剖析,并给出通过实际验证的解决方案。从本篇开始,我将介绍 OBProxy 在OceanBase分布式架构中的作用和原理,帮忙你更透彻地理解OBProxy,实现“好用”和“用好”。 同时,OBProxy 在上百家企业的继续运行,咱们积攒了大量的工程实践经验,也将遇到的问题作为案例,随同 OBProxy 的原理解说分享给你,供大家参考。
本篇从 OBProxy 的重要个性连贯治理讲起,其中,对连贯映射关系、session状态同步等内容,你能够将其与单机数据库比拟,领会分布式系统和单机零碎的异同。
OBProxy的连贯治理步骤及原理
在正式解说之前,我先介绍一下本篇内容的技术背景。咱们晓得,OBProxy 为用户提供了数据库接入和路由性能,用户连贯 OBProxy 就能够失常应用OceanBase数据库。用户在应用数据库性能时,OBProxy和OBServer进行交互,且交互流程对用户通明,连贯治理就是该交互过程中的关键点之一。
OBProxy的连贯治理有三个个性:
- 代理个性:OBProxy 既是客户端,也是服务端,还须要保障交互行为合乎MySQL协定标准。
- 性能个性:OBProxy实现了很多的连接功能个性,如拜访不同集群、不同租户,再如反对主备库、分布式下的ps性能,以及兼容kill、show processlist等命令。
- 高可用个性:OBProxy能够解决超时、机器状态变动、网络状态变动等问题,屏蔽后端异样,让用户无感知。
接下来咱们按应用 OBProxy 的操作步骤一步一步来解说连贯治理内容。
第一步:用户登录
1. 登录信息
在登录 OBProxy 时,咱们须要填写数据库IP和PORT、用户名、明码等信息,对于用户名,OBServer 的格局为user_name@tenant_name。因为 OBProxy 能够代理不同的集群,所以格局又变为user_name@tenant_name#cluster_name,字段含意如下:
- user_name:登录的用户名,明码保留在OBServer中,OBProxy只做登录报文转发不做明码校验。
- tenant_name:OBServer是多租户架构,tenant_name示意拜访的租户名。
- cluster_name:集群名,OBProxy反对拜访多个集群,不同集群通过cluster_name辨别。
有了这些信息,咱们就能够通过JDBC驱动、MySQL命令行、Navicat等工具连贯 OBProxy 拜访数据库了。
你可能会纳闷,用户登录时 OBProxy 如何找到对应的机器呢?这就要依赖OCP零碎(通过obproxy_config_server_url配置项指定OCP的url地址拜访),OCP会保留集群名和集群的机器列表,OBProxy通过拜访OCP获取这些信息,整个流程如下图。
有了租户的机器列表,咱们就能够进行路由转发了。这里须要留神的是,本系列第二篇介绍的rslist启动形式会省略上图中的步骤2和步骤3,这种形式只反对拜访一个集群。
2. 登录认证
找到机器后,咱们就能够登录认证了,要害信息是用户名和明码,MySQL协定中(官网图片中展现了Handshake相干报文,理论流程中第2步完结后服务端须要回复一个OK或者Error报文给客户端)的交互流程如下图。
OBProxy 作为代理组件,要兼容MySQL行为,会有更多步骤。咱们以Java程序连贯数据库为例阐明整个流程,在Java程序中,登录代码只有一行:
conn = (Connection) DriverManager.getConnection(URL, USER_NAME, PASSWORD);
但背地的原理比较复杂,如下图所示。
在实现协定的登录步骤(第8步)后,MySQL协定层的登录交互就完结了,但JDBC会发送一些初始化SQL,也属于登录过程一部分,图中第9步示意该过程。初始化SQL有多条,内容如下:
set autocommit=1, sql_mode = concat(@@sql_mode,',STRICT_TRANS_TABLES')set names utf8SELECT @@max_allowed_packet,@@system_time_zone,@@time_zone,@@auto_increment_increment,@@tx_isolation AS tx_isolation,@@session.tx_read_only AS tx_read_onlyselect @@version_comment, @@version limit 1
下面SQL执行实现后,Java程序就能够发送业务SQL了。
3. 常见登录问题
当初的你曾经明确了 OBProxy 的登录原理,就能够在登录失败时疾速地定位和解决问题了。常见的问题及起因如下:
- 用户名或明码谬误,能够通过直连OBServer确定。
- OCP故障,无奈拉取集群机器列表,能够通过curl命令拜访OCP的url确定。
- OBServer执行获取机器列表或初始化SQL失败,须要日志排查定位。
- 超过最大连接数设置或不在白名单中,后文将为你具体解读。
对于上述问题,你能够通过本系列第三篇文章提到的查看obproxy_error.log形式解决。
第二步:连贯治理
登录胜利后,客户端<->OBProxy<->OBServer之间的网络连接便建设起来,此时 OBProxy 只是和其中一台OBServer建设了连贯。随着SQL申请的到来,如果路由到新的OBServer,会和新的OBServer建设连贯。在此过程中波及连贯的映射关系、状态同步和连接功能个性,接下来一一解读。
1. 连贯的映射关系
连贯映射次要讲客户端连贯和服务端连贯之间的关系,咱们先从一个客户端连贯说起。当客户端和 OBProxy 建设一个连贯后,OBProxy 会和前面N个OBServer建设连贯,整个关系如下图所示。
能够看到,OBProxy 按需和两台OBServer建设了连贯。这两个连贯只属于这一个客户端连贯,不会被其余客户端连贯复用。连贯映射的关键点就是须要用id标识出每一个连贯并记录id之间的映射关系,咱们能够将上图形象成模型:
App<-----[proxy_sessid1]---->OBProxy<---[server_sessid1]----->OBServer1
<---[server_sessid3]----->OBServer3
这样咱们就能够用proxy_sessid惟一标识App和OBProxy之间的连贯,用server_sessid惟一标识OBProxy和OBServer之间的连贯。当SQL执行谬误、执行慢等状况呈现,会将映射关系打印到日志中,这样就将App和OBServer关联起来,进行全链路问题定位。
2. 状态同步
一个客户端连贯对应多个服务端连贯,要保障执行后果的正确性,就要求多个服务端连贯的session状态是统一的。那么,状态不同步会导致什么问题?咱们举个反例,假如用户执行上面的SQL命令:
set autocommit=1;insert into t1 values(1);insert into t2 values(2);
执行过程如下:
- set autocommit=0发给OBServer1
- insert into t1 values(1)发给OBServer1
- 进行连贯切换,insert into t2 values(2)发给OBServer2
对于第三条SQL,OBProxy 和 OBServer2 的连贯并未同步连贯状态autocommit=1,这样就可能导致第三条语句insert into t2并未提交事务。
正确的步骤是OBProxy在给OBServer2发送INSERT SQL前,先同步autocommit变量的值。OBProxy通过版本号机制解决了状态同步的问题,实现了database、session variables、last_insert_id、ps prepare语句的状态同步,保障性能的正确性。
3. 连接功能个性
和单机数据库不同,OBProxy扭转了连贯的映射关系为M:N,因而有些连接功能须要做额定解决。举个例子,用户通过show processlist查看连接数,此时他心愿看到的是客户端和 OBProxy 之间的连接数,而不是 OBProxy 和OBServer之间的连接数。上面咱们对常见的连接功能开展具体介绍。
连贯粘性。OBProxy还未实现所有性能的状态同步,如事务状态、长期表状态、cursor状态等。对于这些性能,OBProxy只会将后续申请都发往状态开始的节点,这样就不须要进行状态同步,而毛病是无奈充分发挥分布式系统的劣势。因而,咱们依据性能重要水平,逐渐反对相干性能的分布式化。
show processlist和kill命令配套应用。show processlist用于展现客户端和服务端之间的连贯,对于OBProxy,show processlist只展现客户端和OBProxy之间的连贯,不展现OBProxy和OBServer之间的连贯。kill命令用于杀死一个客户端连贯,客户端连贯敞开后,OBProxy也会敞开对应的服务端连贯。对于OBProxy的kill命令,须要先获取对应的id,如下图的Id列内容(show proxysession和show processlist性能相似,show proxysession是OBProxy专属命令)。
负载平衡影响。因为 OBProxy 对show processlist和kill命令做了解决,所以show processlist和kill命令只有都发往同一台 OBProxy 能力失常工作。在私有云等环境,OBProxy后面有负载平衡,负载平衡前面挂在多个OBProxy上,此时,如果执行show prcesslist和kill命令是两个不同的连贯,负载平衡组件可能将申请发往不同的OBProxy,在这种状况下,咱们最好不要应用相干命令。
介绍完OBProxy的连贯映射关系、状态同步和连接功能个性的技术原理后,你可能会感觉如果用HAProxy等一般代理,很多中央就会简略很多,比方:
- 用户连贯一般代理后,一般代理只会和一台OBServer建设连贯,连贯映射是1:1的治理。
- 一般代理的连贯映射为1:1的关系,就不须要做状态同步,连接功能也不须要非凡解决,间接转发即可。
那么,为什么还举荐应用OBProxy,它的劣势在哪里呢?
- 一般代理无奈做高可用容灾,OBProxy通过外部表、错误码等信息,会探测出OBServer状态(降级、宕机等),对OBServer节点进行拉黑和洗白。
- 一般代理无奈充分发挥OceanBase数据库的性能,连贯建设后,一般代理无奈将SQL发往其余OBServer节点,有时执行链路会更长。OBProxy能够精准路由,并实现读写拆散等个性。
- 一般代理性能无限,无奈适配OceanBase主备库、复制表、LDC架构等个性。
以上就是应用OBProxy 的步骤及其原理,如果想理解更深层次的连贯原理常识,咱们须要追溯到TCP协定。因为OBProxy的连贯基于TCP协定,理解TCP协定的连贯机制就能更透彻的把握连贯治理的性能及连贯问题定位等常识。
延长知识点1:基于TCP协定的连贯机制
TCP参数
OBProxy在代码层面设置了TCP的no_delay和keepalive属性,以保障低提早、高可用等个性。
- no_delay属性通过禁用TCP Nagle算法解决提早问题。在Linux的网络栈中默认启用Nagle算法,用于解决网络报文小分组呈现,但会导致网络报文发送提早。咱们曾在生产环境中遇到TCP未禁用Nagle算法的状况,导致一条SQL发送耗时40ms左右,这是不满足业务要求的。
- keepalive属性用于故障探测。及时发现机器故障,将有效的连贯敞开,是TCP层高可用一部分。
这两个属性能够通过OBProxy的配置项进行配置,举荐配置如下:
## 和OBServer的tcp连贯设置sock_option_flag_out = 3; -- 这是个二进制位参数,bit 0 示意否是启用 no_delay,bit 1 示意是否启用 keepalive。3的二进制是 11,示意启用 no_delay 和 keepaliveserver_tcp_keepidle = 5; -- 启动keepalive探活前的idle工夫,5秒。server_tcp_keepintvl = 5; -- 两个keepalive探活包之间的工夫距离,5秒server_tcp_keepcnt = 2; -- 最多发送多少个keepalive包,2个。最长5+5*2=15秒发现dead_socket。## 和客户端的tcp连贯设置client_sock_option_flag_out = 3; -- 同上client_tcp_keepidle = 5; -- 同上client_tcp_keepintvl = 5; -- 同上client_tcp_keepcnt = 2; -- 同上
咱们在生产环境中曾经验证了no_delay和keepalive属性,你能够放心使用。对于其余TCP参数,咱们间接应用默认值,还没有调参的需要。
超时参数
咱们在排查问题时,偶然会遇到TCP连贯断了的状况,但无奈确定是客户端断连还是服务端断连。依据教训判断,往往是超时机制触发的。这里针对几种超时机制介绍一下全链路解决方案。
1.JDBC超时
(1)socketTimeout
socketTimeout是Java socket的超时工夫,指的是业务程序和后端数据库之间TCP通信的超时工夫,如果业务程序发送一个MySQL Packet后,超过socketTimeout的工夫还没有从后端数据库收到Response报文,这时候JDBC会抛出异样,程序执行失败。
socketTimeout单位是毫秒,能够通过以下形式设置:
jdbc:mysql://$ip:$port/$database?socketTimeout=60000
(2) connectTimeout
connectTimeout是业务程序应用jdbc跟后端数据库建设TCP连贯的超时工夫,也相当于是在connect阶段的socketTimeout,如果TCP连贯超过这个工夫没有建胜利,jdbc会抛出异样。
connectTimeout的单位是毫秒,能够通过以下形式设置:
jdbc:mysql://$ip:$port/$database?socketTimeout=60000&connecTimeout=5000
(3)queryTimeout
queryTimeout是业务程序执行SQL时,jdbc设置的本地的超时工夫。在业务调用jdbc的接口执行SQL时,jdbc外部会开启这个超时机制,超过quertTimeout没有执行完结,jdbc会在以后连贯上发送一个kill query给后端数据库,并给下层业务抛一个MySQLTimeoutException。
queryTimeout单位是秒,能够通过以下形式进行设置:
1、通过jdbc的Statement.setQueryTimeout接口来设置 int queryTimeout = 10;java.sql.Statement stmt = connection.CreateStatement();stmt.setQueryTimeout(queryTimeout);
这里须要特地阐明的是,如果要应用queryTimeout,倡议设置一个比socketTimeout小的值,否则会先触发网络超时从而导致断连贯。但咱们并不举荐应用queryTimeout,你能够应用OceanBase数据库的ob_query_timeout属性。
(4)JDBC超时实际
JDBC 重要的几个超时参数,均能够设置到连接池的 ConnectionProperties 中,或者 JDBC URL 上:
参数 | 阐明 | 推荐值 |
---|---|---|
socketTimeout | 网络读超时工夫,如果不设置默认是 0,应用 OS 默认超时工夫 | 5000ms |
connectTimeout | 链接建设超时工夫,如果不设置默认是 0,应用 OS 默认超时工夫 | 500ms |
这些参数是咱们依据蚂蚁外部OLTP业务总结而来,供你参考。
2.OceanBase数据库超时
OceanBase数据库有本人特定的超时参数,这些参数和JDBC的不同在于OceanBase触发超时后的行为是返回ERROR报文而不是断连贯。
(1) ob_query_timeout
ob_query_timeout是OBServer SQL级别的超时参数,能够通过hint或者session变量设置,示意执行一个SQL超时工夫。当业务的SQL在数据库执行工夫超过ob_query_timeout设置的值后,OBServer会返回一个ERROR包给客户端,错误码是4012。 ob_query_timeout的默认值是10000000(10s), 单位是微秒。能够通过以下几种形式设置:
// Java程序示例// 1、通过sql设置session变量或者global变量,设置实现之后,以后连贯失效stmt.execute("set @@ob_query_timeout = 10000000");stmt.execute("set @@global.ob_query_timeout = 10000000");// 2、通过在业务sql中增加hint设置,以后sql失效String sql = "/*+ QUERY_TIMEOUT(10000000)*/ select count(*) from XXX";stmt.execute(sql);
(2)ob_trx_timeout
ob_trx_timeout是OBServer的事务超时工夫,是一个session变量,当一个事务执行超过ob_trx_timeout还没有完结时,OBServer同样会返回4012的ERROR报文给客户端。如果超时产生时,事务还没有提交,那么OBServer会回滚这个事务;如果产生在commit阶段,因为事务状态未定,OBServer不会被动回滚它。ob_trx_timeout默认值是100000000(100s),单位是微秒,能够通过以下形式设置:
// Java程序示例// 通过sql设置session变量或者global变量,设置实现之后,以后连贯失效stmt.execute("set @@ob_trx_timeout = 100000000");stmt.execute("set @@global.ob_trx_timeout = 100000000");
(3)兼容MySQL超时
除了上述OceanBase数据库特有的超时参数,OceanBase数据库还兼容了MySQL的超时参数,能够参考MySQL 超时文档,MySQL的超时参数会导致断连贯,有三个参数。
- wait_timeout:闲暇session工夫,默认为8个小时,超过该工夫未发送任何SQL就会断连。
- net_read_timeout:期待从连贯上读取数据的超时工夫。超时会导致连贯敞开。
- net_write_timeout:期待从连贯上写入数据的超时工夫。超时会导致连贯敞开。
因为大部分超时机制触发后会间接敞开连贯,并且不打印超时日志,所以不理解超时机制的话很难确定TCP断连的起因,但理解后通过观察执行工夫或调整参数根本就能确定问题。OBProxy 作为代理层,并没有减少超时机制,不会让机制更加简单,同时,OBProxy 会感知数据库超时参数的设置,让整体体现合乎超时机制。
延长知识点2:罕用网络工具
在很多时候咱们须要理解零碎网络行为,从而更好地解决问题。比方,在OBProxy 日志中呈现了Connect Error,咱们就能够通过ping命令进一步证实两台机器之间网络不通。接下来为你介绍一些罕用的网络工具。
ping和telnet命令
ping和telnet命令简略好用,ping命令能够确定两台机器之间的网络是否连通,并且能够理解网络之间的提早,这对解决很多问题都十分有用。比方,提早几十毫秒,断定为路由到了其余城市的机房,这在oltp业务中是不合乎预期的。telnet命令能够进一步确定机器端口是否在监听,从而发现服务程序未启动、程序core掉等问题。
抓包工具
当问题波及多个模块的协定交互时,只剖析日志无奈取得更多有用信息,此时能够应用tcpdump工具获取网络真实情况。举个例子,如果在OBProxy日志看到数据库执行SQL慢,而在OBServer看到SQL执行很快,此时就会狐疑网络问题,只有依据TCP报文能力确定是否是网络问题。
规范部署中,OBProxy的端口是2881,OBServer的端口是2883,如果抓OBProxy和OBServer的交互报文,能够在OBProxy的机器执行:
sudo tcpdump -i any port 2881 -w xxx.cap
TCP报文就会保留在xxx.cap中。失去该文件拷贝到本地机器应用wireshark软件剖析即可。
除了下面介绍的命令,还有ifconfig、ss、lsof、curl等命令都十分有用,网络上材料很多,此处就不作更多介绍了。
总之,在分布式系统中,网络问题很常见。理解背地的起因,须要对操作系统、数据库系统、网络工具都十分相熟,因而减少了判断难度。上述内容对这些知识点都做了具体介绍,帮忙你更好地理解分布式数据库系统。
延长知识点3:连贯治理的常见问题
尽管连贯治理的知识点很多,但当呈现连贯问题后,客户端报错根本都是Communications link failure。这里关键点就是通过“要害信息”将TCP的两端分割起来,取得更多有用信息去进一步剖析。如“要害信息”是SQL和工夫点,那么就能够去obproxy_error.log中去查看,找到日志记录后,能够依据本系列第三篇文章介绍的内容去进一步排查。
这里咱们举两个例子阐明。例子1客户端报错:
--- Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failureThe last packet successfully received from the server was 70,810 milliseconds ago. The last packet sent successfully to the server was 5,005 milliseconds ago.
剖析报错信息,能够看到客户端上次从服务端收到申请是70810ms之前,客户端上次往服务端发送数据是5005ms(5s)之前。这是在执行SQL过程中呈现了问题,个别是Java自身设置了sockettimeout=5s导致的,这能够向利用开发者确认。
例子2客户端报错:
--- Cause: com.alipay.oceanbase.obproxy.druid.pool.GetConnectionTimeoutException: get connection timeout, maxWait=500ms, maxCount=10, currentCount=11,
能够看到这是个Druid连接池的报错,获取连贯超时。此时SQL还没有执行,但从连接池曾经拿不到连贯了,问题起因就比较复杂。个别起因有:
- 连接池自身配置连接数太少不够用,参考maxCount的值,个别调大能够解决。
- 有慢SQL导致连贯没有及时偿还,这种问题就须要排查哪些SQL执行慢。
可见报错只是一种表象,很难一下就确定根本原因,须要收集更多信息去深刻排查。
总结
连贯治理波及的综合知识点多,波及的模块(包含驱动、OBProxy和OBServer)也多,因而变得复杂,但这也是微服务、分布式数据库的独特“痛点”。本文咱们从用户登录讲起,别离介绍了连贯治理、网络技术和常见问题,将相干原理和实际介绍给你。OBProxy经验多年实际,解决了很多连贯治理的问题,n也欢送大家学习交换。
课后互动
上期互动答案
小明想查看所有通过 OBProxy 的 SQL,请问有什么方法?
答:obproxy_digest.log是审计日志,记录了所有执行工夫大于query_digest_time_threshold的SQL,因而能够批改query_digest_time_threshold的值为1us,就能够在obproxy_digest.log中看到所有通过OBProxy的日志了。
本期互动问题
JDBC和OBProxy建设了一个连贯,早晨OBProxy被kill掉重启,请问此时JDBC会抛出异样吗?
欢送你在问答区发帖探讨,下篇文章揭晓答案。