Or Fun in using MySQL8 with ProxySQL and MysqlJ connector
I am recently working on testing MySQL8 and try the several solution attach to it,like ProxySQL but not only.
After I had setup the set of servers, and configured ProxySQL to redirect the incoming connection from my user m8_test to my MySQL8 setup, I had turn on my Java test application ... and with my surprise I received an error:
Caused by:
1 |
com.mysql.cj.core.exceptions.CJException: Unknown system variable 'query_cache_size'
|
Well ok MySQL8 doesn't have Query cache, but why I got this error?
I did point the application to MySQL8 directly and it worked fine.
Just to be sure this is something restricted to the Java connector, I did a test with a perl, and I was able to access and write my MySQL8 servers from ProxySQL without problem.
So the issue is restricted to MySQLJ and ProxySQL. Not the first time I have issue with that connector, and not the first time I see ProxySQL not 100% compatible. But this was weird.
I downloaded the latest MYSQLJ connector and put the source in my development environment.
Then I started to dig in to the issue.
MySQL Connector send a "SHOW VARIABLES" and then parse the result to "configure" the connector accordingly.
In the class MysqlaSession.loadServerVariables() is the method that will decide what variables should be included and what not.
The process is a bit rude and basic, with a series of IF condition checking the Server Version.
Finally at line 1044 I found the why the connector was failing:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
if (versionMeetsMinimum(8, 0, 3)) { queryBuf.append(", @@have_query_cache AS have_query_cache"); } else { queryBuf.append(", @@query_cache_size AS query_cache_size"); queryBuf.append(", @@query_cache_type AS query_cache_type"); } |
So if Version is at least 8.0.3 check for the variable have_query_cache, otherwise read query_cache_size and type.
Here we go, ProxySQL by default in version 1.4.6 declare itself as:
1 |
Server version: 5.5.30 (ProxySQL)
|
One of the good things in ProxySQL is that most of the important settings can be dynamically change, including the Server Version.
This is it, ProxySQL can impersonate whichever MySQL just modifying the Server Version variable.
Given that I did:
1 2 3 4 5 |
update global_variables set variable_value="8.0.4 (ProxySQL)" where variable_name='mysql-server_version'; load mysql variables to run;save mysql variables to disk; |
At this point I had run my java app again, and all was running fine.
While there I tested several different scenarion and mostly worked as expected.
But once I set ProxySQL to impersonate a MySQL 5.5, yes right as 5.5 not as 5.5.x
Just to see if the connector was reading the version correctly. And with no big surprise... it was not.
Why? Bcause MySQL Connector once opened the channel with the server, reads some of the parameters directly from the connection, one of them is the Server Version.
The Server Version is parse in the class ServerVersion.parseVersion() method, and here the connector expect to find the server version following the standard major.sub.subminor (5.5.30) if this is not declare exactly like that, then the connector will just set the Server Version to 0.0.0. With the side effect that nothing will work correctly afterwards.
Conclusion
This short blog post was to share a simple issue I had and his resolution using the flexibility in ProxySQL to modify the declared MySQL Server Version.
Still, attention must be made given the MySQLJ is not flexible and standard (major.sub.subminor) must be used.