First of all: This is a great piece of software - just what I was looking for!
Second: This is my first post here and I'm wearing my newbie hat. Feel free to
ask me to go back to school if I'm way off mark.
I'm currently running Nfacctd with MySQL plugins (one for each direction) on a
fairly busy link with heavy log aggregation in order to keep the number of rows
down. At present I use a 5min sql_history which results in a total of around
1500 rows per 5min period. With the default sql_refresh_time, I end up with
multiple plugin and mysql instances, presumably because the cache flush
procedure doesn't always complete within the sql_refresh_time period. Changing
sql_refresh_time to the sql_history value reduced the number of UPDATE queries
and made it run without forking. Still it takes around 2:45 to complete a cache
flush to MySQL (even with a small database - it is currently around 200MB).
This would be acceptable with current traffic loads if it wasn't for
mysql_plugin locking the table during this time, making it almost impossible to
get any data out of the database with reasonable response time.
So, looking at INTERNALS, CONFIG_KEYS and mysql_plugin.* I'm wondering:
1: It seems like the current approach on cache flush is roughly (in
meta-language by creative unfolding of functions from MY_cache_purge):
LOCK TABLE
for all cache entries
do
// Maybe the row exists, try update
UPDATE TABLE
// No it didn't, insert the row instead
if update_failed then
INSERT TABLE
endif
done
UNLOCK TABLE
There is support for the sql_dont_try_update flag, which would be nice if it
was a way to synchronize with my sql_history periods as it would prevent as
manye UPDATE attempts as there are INSERT attempts. I can't see how that can be
done with NetFlow, however, as flow packets may arrive later with more
information for the same SQL history epoch. Are there ways to do this with
Netflow?
2: In INTERNALS Paolo writes: "Because we, at this moment, don't known if
INSERT queries
would create duplicates, an UPDATE query is launched first and only if no rows
are affected,
then an INSERT query is trapped."
This is a bit cryptic to me. What is meant by this? A plain INSERT will yield
the normal duplicate error if the row already exists (given default primary
key). A 4.1+ compatible INSERT... ON DUPLICATE KEY UPDATE... seems to me to do
all that's required and doing so in a single query, e.g:
insert into acct (ip_src, ip_dst, src_port,dst_port, ip_proto, packets,
bytes,stamp_inserted, stamp_updated) VALUES ("213.180.130.206", "81.93.160.46",
0, 0, "ip", 100, 1000,"2005-12-01 00:00", now()) ON DUPLICATE KEY UPDATE
packets=packets+100, bytes=bytes+1000, stamp_updated=now();
(Note: I've removed the MAC entries from my DBs and compile with HAVE_L2
undefined)
Are there doubts about the reliability of this approach that is behind the
comment in INTERNALS?
3: Ultimately performance enhancement is only of interest to me to ensure
proper logging of all Netflow data. Whether the CPU spends 5% or 50% of its
time doing this is irrelevant to me. What is not fine is that it locks the
table while doing it, thereby preventing concurrent analysis of Netflow
information.
This brings me to my last question: Why is the table locked? Is it only because
of the UPDATE/INSERT combination on multi-threading, where a failed UPDATE will
yield a failed INSERT if the row is inserted by another process in the mean
time? Could an INSERT... ON DUPLICATE KEY UPDATE... strategy enable us to
remove the dreaded locks or are there other issues?
All the best,
-- Inge