-
Notifications
You must be signed in to change notification settings - Fork 35
BIND DLZ scheduled.
Gustaf Ankarloo edited this page Mar 27, 2020
·
2 revisions
The MySQL views based on a UNION query can be slow to respond.
mysql> select ttl, type, host, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum from dns_records where zone = 'myzone.example.com' and view in ('DEFAULT', 'ALL');
+--------+------+------------+-------------+--------------------------+-------------+-----------+---------+-------+---------+---------+
| ttl | type | host | mx_priority | data | resp_person | serial | refresh | retry | expire | minimum |
+--------+------+------------+-------------+--------------------------+-------------+-----------+---------+-------+---------+---------+
| 172800 | A | dns1 | | 192.168.2.1 | | | | | | |
| 172800 | NS | @ | | dns1.myzone.example.com. | | | | | | |
| 172800 | A | test | | 192.168.2.2 | | | | | | |
| 172800 | SOA | @ | | dns1.myzone.example.com. | hostmaster. | 730170427 | 21600 | 3600 | 3600000 | 172800 |
+--------+------+------------+-------------+--------------------------+-------------+-----------+---------+-------+---------+---------+
7 rows in set (2.16 sec)
But the exact same query using 2 seperate and more simple views (no union to construct them) you get your results much quicker :
mysql> select ttl, type, host, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum from v_dns_clients where zone = 'myzone.example.com' and view in ('DEFAULT', 'ALL')
-> UNION
-> select ttl, type, host, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum from v_dns_zones where zone = 'myzone.example.com' and view in ('DEFAULT', 'ALL');
+--------+------+------------+-------------+--------------------------+-------------+-----------+---------+-------+---------+---------+
| ttl | type | host | mx_priority | data | resp_person | serial | refresh | retry | expire | minimum |
+--------+------+------------+-------------+--------------------------+-------------+-----------+---------+-------+---------+---------+
| 172800 | A | dns1 | | 192.168.2.1 | | | | | | |
| 172800 | NS | @ | | dns1.myzone.example.com. | | | | | | |
| 172800 | A | test | | 192.168.2.2 | | | | | | |
| 172800 | SOA | @ | | dns1.myzone.example.com. | hostmaster. | 730170427 | 21600 | 3600 | 3600000 | 172800 |
+--------+------+------------+-------------+--------------------------+-------------+-----------+---------+-------+---------+---------+
7 rows in set (0.88 sec)
In order to avoid this kind of issue, you can build a "materialized view". It'll just consist of a table regularly updated with the data we need for BIND. The frequency for that table to refresh can be adjusted to your need.
USE ona_default;
DROP TABLE vm_dns_records;
CREATE TABLE vm_dns_records (
ttl int(11) unsigned,
type varchar(15) ,
host varchar(255) DEFAULT NULL,
mx_priority varbinary(11) ,
data longtext DEFAULT NULL,
resp_person varchar(256) ,
serial varbinary(11) ,
refresh varbinary(11) ,
retry varbinary(11) ,
expire varbinary(11) ,
minimum varbinary(11) ,
zone varchar(255) ,
view varchar(255) ,
INDEX vm_dns_records_idx_host (host),
INDEX vm_dns_records_idx_data (data(16))
);
DROP PROCEDURE refresh_vm_dns_records;
DELIMITER $$
CREATE PROCEDURE refresh_vm_dns_records(OUT rc INT)
BEGIN
TRUNCATE TABLE vm_dns_records;
INSERT INTO vm_dns_records
SELECT (case when (dns.ttl > 0) then dns.ttl else domains.default_ttl end) AS ttl, dns.type AS type,
cast((case when (dns.type = 'ptr') then trim(trailing concat('.',domains.name) from concat_ws('.',(interfaces.ip_addr % 256),((interfaces.ip_addr >> 8) % 256),((interfaces.ip_addr >> 16) % 256),((interfaces.ip_addr >> 24) % 256),'in-addr.arpa')) when (dns.name = '') then '@' else dns.name end) as char charset utf8) AS host,
(case when (dns.type = 'mx') then dns.mx_preference else '' end) AS mx_priority,
cast((case when (dns.type = 'txt') then concat('"',dns.txt,'"') when (dns.type = 'srv') then concat_ws(' ',dns.srv_pri,dns.srv_weight,dns.srv_port,(select concat(dns2.name,'.',domains.name,'.') from (dns dns2 join domains on((domains.id = dns2.domain_id))) where (dns.dns_id = dns2.id))) when (dns.type in ('ptr','cname','mx','ns')) then (select concat(dns2.name,'.',domains.name,'.') from (dns dns2 join domains on((domains.id = dns2.domain_id))) where (dns.dns_id = dns2.id)) when (dns.type = 'a') then inet_ntoa(interfaces.ip_addr) collate utf8_general_ci end) as char charset utf8) AS data,
'' AS resp_person, '' AS serial, '' AS refresh, '' AS retry, '' AS expire, '' AS minimum, domains.name AS zone, dns_views.name AS view
FROM (
((dns join domains on ((dns.domain_id = domains.id)) )
join dns_views on ((dns.dns_view_id = dns_views.id)) )
left join interfaces on ((interfaces.id = dns.interface_id)) )
WHERE ((dns.ebegin > 0) and (now() >= dns.ebegin))
UNION
SELECT
domains.default_ttl AS ttl, 'SOA' AS type, '@' AS host, '' AS mx_priority,
concat(trim(trailing '.' from domains.primary_master),'.') AS data,
concat(trim(trailing '.' from domains.admin_email),'.') AS resp_person,
domains.serial AS serial, domains.refresh AS refresh, domains.retry AS retry, domains.expiry AS expire,
domains.minimum AS minimum, domains.name AS zone, 'ALL' AS view
FROM (domains join dns_server_domains on
(( (domains.id = dns_server_domains.domain_id) and (dns_server_domains.role in ('master','slave')))) );
SET rc=0;
END;
$$
DELIMITER ;
It can even be issued every 30 seconds since the procedure takes about 3 seconds only, here it's done every 2 minutes.
-- The scheduler is only available since version 5.1.6 of MySQL
-- don’t forget to declare it in /etc/my.cnf so it gets activated on startup :
-- [mysqld]
-- event_scheduler=ON
SET GLOBAL event_scheduler = 1;
-- Here we schedule the procedure to be executed every 2 minutes from now + 1 second for the first execution.
DROP EVENT event_refresh_vm_dns_records;
CREATE EVENT event_refresh_vm_dns_records
ON SCHEDULE EVERY 2 MINUTE
STARTS CURRENT_TIMESTAMP + INTERVAL 1 SECOND
DO CALL refresh_vm_dns_records(@rc);
show variables like 'event_scheduler';
select count(*) from vm_dns_records;
show procedure status;
select name, body, execute_at, interval_value, interval_field, created, last_executed, starts, ends, status from mysql.event;
Just replace the view name dns_records
by the name of our new table vm_dns_records
dlz "ONA Default" {
database "mysql {host=localhost dbname=ona_default user=ona_sys pass=******** ssl=tRue}
{select zone from vm_dns_records where zone = '$zone$' and type = 'SOA' limit 1}
{select ttl, type, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
from vm_dns_records where zone = '$zone$' and host = '$record$' and view in ('DEFAULT', 'ALL')}
{}
{select ttl, type, host, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
from vm_dns_records where zone = '$zone$' and view in ('DEFAULT', 'ALL')}
{select zone from xfr_table where zone = '$zone$' and client = '$client$'}";
};
Before (bind using the dns_records
view you might have had very slow replies :
[root@dns1 ~]# dig @localhost test.myzone.example.com
...
;; ANSWER SECTION:
test.myzone.example.com. 172800 IN A 192.168.2.2
...
;; Query time: 1383 msec
[root@dns1 ~]#
Now it should reply in less than a msec :
[root@dns1 ~]# dig @localhost test.myzone.example.com
...
;; ANSWER SECTION:
test.myzone.example.com. 172800 IN A 192.168.2.2
...
;; Query time: 1 msec
[root@dns1 ~]#