monitoring MySQL slave status - mysql

I'm using Nagios with the mysql_check_health pugin to monitor my MySQL databases. I need to be able to return a numeric value to my plugin from an sql query to tell me if the replicated database is up and running.
so here is what I have...
SHOW GLOBAL STATUS like 'slave_running'
will return:
Variable_name Value
Slave_running OFF/ON
I need to retrun a numeric value from a simple query for the plugin, anyone have any ideas... my thought was to return 3-LENGTH(Slave_running) that would == 1 for ON 0 for off but having trouble using the return values in that way.

The global status variable will be accessible in the information_schema.GLOBAL_STATUS table, from which you can query just the value. That makes it easy to conditionally convert it to a 0 or 1 based on the ON/OFF state.
For example:
> SELECT VARIABLE_VALUE
FROM information_schema.GLOBAL_STATUS
WHERE VARIABLE_NAME = 'slave_running';
+----------------+
| VARIABLE_VALUE |
+----------------+
| ON |
+----------------+
So to convert that into a zero or one, there are a few possibilities. MySQL will treat booleans as 0 or 1, so you can just compare it = 'ON'
Wrapping the above in a subquery (since it returns one value) and comparing to 'ON':
> SELECT (
'ON' = (SELECT VARIABLE_VALUE
FROM information_schema.GLOBAL_STATUS
WHERE VARIABLE_NAME = 'slave_running')
) AS state;
+-------+
| state |
+-------+
| 1 |
+-------+
Or a similar expression formatted as a CASE:
> SELECT CASE WHEN (
SELECT VARIABLE_VALUE
FROM information_schema.GLOBAL_STATUS
WHERE VARIABLE_NAME = 'slave_running') = 'ON' THEN 1
ELSE 0 END AS state;
+-------+
| state |
+-------+
| 1 |
+-------+
In both of the above, I aliased the result as 'state', but you could use any column alias name to read output, replacing AS state accordingly.
What's already out there?
I couldn't help but wonder if there was already a Nagios plugin built for this purpose, and found this as a possibility.

I would strongly consider using:
SHOW SLAVE STATUS
As your informational query. This gives you a few more key fields to monitor on.
From this, you might consider alarming on the following fields:
Slave_IO_Running: Yes / No (tells you if binary log feed from master is working)
Slave_SQL_Running: Yes / No (tells you if slave's SQL execution thread is runing)
Seconds_Behind_Master: INT value (you should set appropriate low value here to alarm off of)
The Slave_running global status is OK for determining overall state (that value is only 'On' when both IO thread and SQL thread on slave are running), but may not give you what you want in terms of more granular monitoring. For example, an interruption in the IO thread may be considered a higher severity event than the SQL thread breaking (and may have totally different recovery scenarios). The Seconds_Behind_Master may also be key to monitor, as you might have both IO and SQL threads happily running, while not realizing that the slave can't keep up for some reason.
If you need to convert to INT value results for slave status values, you could do something like:
SELECT
(CASE WHEN a.Slave_IO_Running = 'Yes' THEN 1 ELSE 0 END)
AS Slave_IO_Running,
(CASE WHEN a.Slave_SQL_Running = 'Yes' THEN 1 ELSE 0 END)
AS Slave_SQL_Running,
a.Seconds_Behind_Master AS Seconds_Behind_Master
FROM (SHOW SLAVE STATUS) AS a

Related

How to receive any changes in MySQL database in real time from client code in a timed function?

I have a database with a log record table which looks like this:
+-----------+------------------------+--------+
| Timestamp | Symbol_name | Status |
+-----------+------------------------+--------+
| 1 | Group2 | 1 |
| 2 | Group1-Device3-Signal1 | 1 |
| 3 | Group2-Device1-Signa13 | 0 |
+-----------+------------------------+--------+
Where Timestamp is a double, Symbol_name is a varchar, and Status is an int.
Log records which contain the above data are going to be inserted into the table in real time, and my client code is supposed to query those records and analyze them. The problem I am having right now is reading a unique record each query. Currently, I have this function:
/* Called every 1000 ms (1 second). */
gboolean app_models_timed_query(gpointer data) {
FwApp *app = data;
char query[APP_MAXIMUM_STRING_CHARS];
strncpy(query, "SELECT * FROM ", APP_MAXIMUM_STRING_CHARS);
strncat(query, app->query_db_table_name, APP_MAXIMUM_STRING_CHARS);
strncat(query, " WHERE Timestamp <> #lastSeenTimestamp AND Symbol_name <> #lastSeenSymbolName AND Status <> #lastSeenStatus;", APP_MAXIMUM_STRING_CHARS);
if (mysql_query(app->query_db_con, query))
{
printf("Unable to retrieve data from query table.\n");
return TRUE;
}
MYSQL_RES *result = mysql_store_result(app->query_db_con);
if (result == NULL) return TRUE;
/* Analyze the resulting row(s) here. */
/* How to set #lastSeenTimestamp, #lastSeenSymbolName and #lastSeenStatus here? */
return TRUE;
}
The function gets called every second, and in it, I query the database using the following statement:
SELECT * FROM table1 WHERE Timestamp <> #lastSeenTimestamp AND Symbol_name <> #lastSeenSymbolName AND Status <> #lastSeenStatus;
No two records will ever be exactly the same, but they can have the same timestamp, status, or symbol name.
Note that before I enable app_models_timed_query to be called each second, I set the user-defined variables like so:
SET #lastSeenTimestamp = -1, #lastSeenSymbolName = '', #lastSeenStatus = 0;
And since timestamps will never be negative, the first time app_models_timed_query is called, the first row will be in the result of the query.
However, my question is how to set the user-defined variables to the last row of the result of my query. Also, I want to know if there is a better way of reading only newly inserted rows each time app_models_timed_query is called.
Many thanks,
Vikas
You should be using a message queue like RabbitMQ for this sort of application. Message queues have an API associated with fetching from the top of a queue. Even if you store the main data in MySQL, you can use the message queue for the primary key. With this choice of suited infrastructure your application doesn't need to preserve state.

Monitoring progress of a SQL script with many UPDATEs in MariaDB

I'm running a script with several million update statements like this:
UPDATE data SET value = 0.9234 WHERE fId = 47616 AND modDate = '2018-09-24' AND valueDate = '2007-09-01' AND last_updated < '2018-10-01';
fId, modDate and valueDate are the 3 components of the data table's composite primary key.
I initially ran this with AUTOCOMMIT=1 but I figured it would speed up if I set AUTOCOMMIT=0 and wrapped the transactions into blocks of 25.
In autocommit mode, I used SHOW PROCESSLIST and I'd see the UPDATE statement in the output, so from the fId foreign key, I could tell how far the script had progressed.
However without autocommit, watching it running now, I haven't seen anything with SHOW PROCESSLIST, just this:
610257 schema_owner_2 201.177.12.57:53673 mydb Sleep 0 NULL 0.000
611020 schema_owner_1 201.177.12.57:58904 mydb Query 0 init show processlist 0.000
The Sleep status makes me paranoid that other users on the system are blocking the updates, but if I run SHOW OPEN TABLES I'm not sure whether there's a problem:
MariaDB [mydb]> SHOW OPEN TABLES;
+----------+----------------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+----------------+--------+-------------+
| mydb | data | 2 | 0 |
| mydb | forecast | 1 | 0 |
| mydb | modification | 0 | 0 |
| mydb | data3 | 0 | 0 |
+----------+----------------+--------+-------------+
Is my script going to wait forever? Should I go back to using autocommit mode? Is there any way to see how far it's progressed? I guess I can inspect the data for the updates but that would be laborious to put together.
Check for progress by actually checking the data.
I assume you are doing COMMIT?
It is reasonable to see nothing -- each UPDATE will take very few milliseconds; there will be Sleep time between UPDATEs.
Time being 0 is your clue that it is progressing.
There won't necessarily be any clue in the PROCESSLIST of how far it has gotten.
You could add SELECT SLEEP(1), $fid; in the loop, where $fid (or whatever) is the last UPDATEd row id. That would slow down the progress by 1 second per 25 rows, so maybe you should do groups of 100 or 500.

How PHPMyAdmin get query statics?

Dear friends: I'm developing a php server monitor for a client. One of the monitor's sections is related to MySQL.
In PHPmyadmin the section Server Status > Status queries show an amount of queries. I thought that was extracted from the "SHOW STATUS" mysql command. But... Differs!
When i go in PHPmyadmin to the section Server Status > Server Status Variables, the system displays the same values that "Status Queries" section.
But when i get the results of "SHOW STATUS" command, the values is not the same".
My English level is too poor to explain the case correctly. So, I will show an example:
In Server Status > Status Queries i can see, in the table:
Sentences | # | per hour| %
---------------------------------
select | 365 | 51.4 |25.29
set option | 266 | 37.4 |18.43
When i go to Server Status > Server Status Variables, i can see:
Variable | Value | Description
---------------------------------
Com select | 365 | Blah Blah....
Com set Option | 266 | Blah Blah....
But if i run "SHOW STATUS", i obtain:
Variable | Value
-----------------------------
com_select | 1
com_set_Option | 2
And, in this point, my brain explode....
Can do you enlighten me?
PD: Again, Sorry if my English is too poor...
Use:
SHOW GLOBAL STATUS;
To get the server status values as shown in PhpMyAdmin
With a GLOBAL modifier, the statement displays the global status values. A global status variable may represent status for some aspect of the server itself (for example, Aborted_connects), or the aggregated status over all connections to MySQL (for example, Bytes_received and Bytes_sent). If a variable has no global value, the session value is displayed.
With a SESSION modifier, the statement displays the status variable values for the current connection. If a variable has no session value, the global value is displayed. LOCAL is a synonym for SESSION.
If no modifier is present, the default is SESSION.

Strange casting behavior in mysql

Here is the code
mysql> SELECT id FROM tbl WHERE id = '1h';
+----+
| id |
+----+
| 1 |
+----+
1 row in set
There is indeed a field with id 1 (but not '1h').
Here is an extraction from MySQL docs: http://dev.mysql.com/doc/refman/5.1/en/type-conversion.html
mysql> SELECT 1 > '6x';
-> 0
mysql> SELECT 7 > '6x';
-> 1
So this bug is documented, so to say. The question is what's the reason for such behavior and how to correct it to make this not cast strings with char symbols? I can cast all field values like
mysql> SELECT id FROM tbl WHERE cast(`id`, BINARY) = '1h';
but i don't like this variant too much
This is not a bug.
The solution is not to query on numeric columns using a string value for your condition.
Never rely on implicit type casting.
None of your observations are bugs. They are the result of relying in implicit type casting.
In all of your examples, you're requiring MySQL to convert a string to an int. If you read the very page that you linked to, you will see that MySQL follows some rules in achieving this. As a result
'1h' -> 1
'6x' -> 6
'x6' -> 0
So, if you follow these rules, you'll be OK.
Better still, just don't put MySQL in a position where it needs to be doing these conversion. Such situations usually point to some kind of logic bug elsewhere in the system.

Command to check read/write ratio?

Is there a command in MySQL that returns the read-to-write ratio of queries so that I'm able to know on what MySQL spends time, and whether the load would lower significantly by splitting data over two servers?
This SQL command will give you an indication as to the read/write ratio:
SHOW GLOBAL STATUS WHERE Variable_name = 'Com_insert'
OR Variable_name = 'Com_update'
OR Variable_name = 'Com_select'
OR Variable_name = 'Com_delete';
3rd party edit
On one of our servers gave this result
Variable_name | Value
Com_delete | 6878
Com_insert | 5975
Com_select | 101061
Com_update | 9026
Bytes_received | 136301641 <-- added by 3rd party
Bytes_sent | 645476511 <-- added by 3rd party
I assume that update and insert have different IO implications but i combined them like this Com_insert + Com_update / Com_select to get a "write/read" idea. I also use Bytes_received and Bytes_sent - but this might lead to false conclusions since bytes received do not have to lead to a write on disk (for example a long where clause).
SELECT (136263935/1000000) AS GB_received
, (644471797/1000000) AS GB_sent
, (136263935/644471797) AS Ratio_Received_Sent
, (6199+9108)/106789 AS Ins_Upd_Select_ratio;
This gave this result
GB_received | GB_sent | Ratio_Received_Sent | Ins_Upd_Select_ratio
136 | 644 | 0,2114 | 0,1433
You can use the "show status" and check the "Com_%" variables for read/write ratios.
As for splitting the data, you'll have to check the slow query log (Google mysqlsla) and find out if those queries are amicable to being split.
http://forums.mysql.com/read.php?10,328920,337142#msg-337142
"SHOW GLOBAL STATUS LIKE 'Com%'. This will give overall counts (since last restart) of each statement type. This will not necessarily tell you whether you are mostly SELECT-bound versus write-bound. You might have a small number in Com_select, but the selects are terribly slow. "