Re: "clone" syscall in keepalived healthchecking child takes more time after switching

Damien Clabaut <[email protected]> Tue, 3 Oct 2017 09:45:37 -0400
Newsgroups gmane.linux.keepalived.devel
Message-ID <[email protected]>
Quentin,

If I understand your point 2. correctly, what I am doing today with a 
json file read by a python script could be handled by keepalived 
directly, provided I write in one separate file per instance ?

This would be awesome. Does it include the same safety I have on Python 
script (if the file is not present or does not contain expected data, 
then it is seen as a 0) ?

I will try adding my patch (json output) to your branch. It looks like 
it conflicts, but nothing unsolvable IMHO.

I will keep you updated.

Regards,


On 2017-10-02 03:46 PM, Quentin Armitage wrote:
> Damien,
>
> The track_scripts are invoked from function vrrp_script_thread() in
> vrrp_scheduler.c, and the following function vrrp_script_child_thread()
> handles the termination of the scripts. The calls from there should be
> quite straight forward to follow, but if not by all means ask any
> further questions.
>
> I don't think it is relevant to what you are looking at but the notify
> scripts are invoked via notify_exec() in notify.c
>
> I have a version that is planned to be made available as a beta in the
> near future. This has a large number of performance enhancements,
> including some in the area of executing track scripts. The updated code
> is available at: https://github.com/pqarmitage/keepalived/commits/fixes
> .quick , and I would be very interested to hear if makes any
> improvements for you. The enhancements that may be relevant to what you
> are doing are:
> 1. Use execve() instead of system() to invoke scripts, with any
> parameters parsed at initialisation rather than when the script is run
> (my understanding is that this changes it from 2 forks to 1 fork per
> script invocation)
> 2. Ability to use track_files instead of track_scripts. keepalived uses
> inotify() to monitor changes to files, and reads a number from the file
> when the it changes, which is treated in the same way that the exit
> code from a track_script is used. This means that scripts do not need
> to be executed on a periodic basis, but rather when an external event
> occurs, if the track_file is written to, keepalived will immediately
> read the file and update the vrrp instances accordingly.
> 3. In relation to notify scripts, keepalived can write to a FIFO
> instead of executing a notify script. A process can then monitor the
> FIFO for any notifications (this has the side benefit that it can be
> guaranteed that notifications can be processed in the correct
> sequence). keepalived can be configured to execute a script to monitor
> the FIFO to initiate any desired actions, just as though a notify
> script had been executed, but again it saves the overhead of executing
> a script.
>
> I hope this helps, and if you do try the code that is soon to be
> released as beta, I would be very glad to hear any feedback you have in
> relation to it.
>
> Regards,
>
> Quentin
>
> On Mon, 2017-10-02 at 15:16 -0400, Damien Clabaut wrote:
>> Hello again Quentin,
>>
>> I played a bit more with the templates and with strace.
>>
>> As it turns out:
>>
>> - One clone call means one vrrp script is launched. If I have 16
>> instances, each launching a vrrp script every 5 seconds, I get 32
>> clone
>> calls over a 10 second period.
>>
>> - The more instances, the longer each clone call (see attached:
>> usec_per_instance_count.png)
>>
>> - The more switch (master->backup->master), the longer each clone
>> call
>> (see attached: usec_per_vrrp_switch.png)
>>
>> The graphs are pretty poor quality since this is a ML and I don't
>> want
>> to pollute everyone's inboxes.
>>
>> Could you point me to the part of the code which calls all the
>> vrrp_scripts ? I would like to study it and see if I can make some
>> progress on it.
>>
>> Regards,
>>
>>
>> On 2017-10-02 11:40 AM, Damien Clabaut wrote:
>>>
>>> On 2017-10-02 11:25 AM, Damien Clabaut wrote:
>>>> Hello Quentin and thank you very much for your answer,
>>>>
>>>> My setup is a bit compilcated and built on top of Keepalived PR
>>>> for
>>>> json output (https://github.com/acassen/keepalived/pull/633).
>>>>
>>>> I will try to describe it as clearly as possible here, please
>>>> tell me
>>>> if this is not clear.
>>>>
>>>>
>>>> The network configuration is as follows:
>>>>
>>>> I have 2 Linux machines connected to each other (through a switch
>>>> in
>>>> my case, but that is not relevant).
>>>>
>>>> Using attached templates, I create N vlans interfaces on each
>>>> side of
>>>> the link connecting both servers (from 2 to N+1).
>>>>
>>>> On top of each of those vlan interfaces I make 2 keepalived
>>>> instances
>>>> (one in version 2 for IPv4, one in version 3 for IPv6)
>>>>
>>>> instances are names: <ip_version><vlan id>. For example, IPv6
>>>> instance on vlan 42 is called 642.
>>>>
>>>>
>>>> As you can see in the attached templates, each instances is
>>>> tracking
>>>> a different script called offset_instance_<instance name>
>>>>
>>>> All those track_scripts launch the (attached) script
>>>> "/usr/bin/get_vrrp_offset <instance name>"
>>>>
>>>> get_vrrp_offset queries a JSON file (which is in a ramdisk for
>>>> performance), which contains a boolean for each VRRP instance.
>>>>
>>>> If the boolean is 1, then the script returns 1, and the VRRP
>>>> priority
>>>> for this instance is lowered by 100.
>>>>
>>>> In any other case (JSON file not present or not valid, data not
>>>> present,...) the script returns 0 and nothing happens.
>>>>
>>>>
>>>> The json script is populated with the (attached)
>>>> "/usr/bin/isolate"
>>>> script.
>>>>
>>>> Ran without arguments, it will set the boolean in the json file
>>>> to
>>>> "1" for all existing instances (collected from the json output).
>>>>
>>>> Ran with "-r", it will do the opposite.
>>>>
>>>> The interesting point is, it will change 1 instance every
>>>> second,
>>>> which allows us to move a large number of floating IPs without
>>>> interruption.
>>>>
>>>>
>>>> Please find attached:
>>>>
>>>> - /usr/bin/isolate
>>>>
>>>> - /usr/bin/get_vrrp_offset
>>>>
>>>> - /usr/bin/vrrp_recap (This will print a table with data from
>>>> the
>>>> json output)
>>>>
>>>> - make_conf.py (this will generate the keepalived config)
>>>>
>>>> - template_vrrp_instance, which is called by make_conf.py
>>>>
>>>>
>>>> To mount the ramdisk:
>>>>
>>>> mkdir /mnt/ramdisk
>>>>
>>>> mount -t tmpfs -o size=512m tmpfs /mnt/ramdisk
>>>>
>>>> I will keep working on this today, and keep you updated on my
>>>> findings.
>>>>
>>>> Regards,
>>>>
>>>>
>>>> On 2017-10-01 10:00 AM, Quentin Armitage wrote:
>>>>> On Thu, 2017-09-28 at 16:02 -0400, Damien Clabaut wrote:
>>>>>> Hello Keepalived devs,
>>>>>>
>>>>>> While testing Keepalived version 1.3.6 on Debian8, I came
>>>>>> accross a
>>>>>> strange issue.
>>>>>>
>>>>>> Tl;DR: It seems that after every vrrp state change, the
>>>>>> "clone" system
>>>>>> call takes a little more time, slowly eating up all CPU.
>>>>>>
>>>>>> Details:
>>>>>>
>>>>>> I start keepalived with 200 instances (100 IPv4 + 100 IPv6).
>>>>>> Each instance tracks a different script.
>>>>>> The keepalived healthcheck children (as described on
>>>>>> http://keepalived.org/documentation.html) has PID 177548:
>>>>>>
>>>>>> [root@bz-perflab-6-vr /home/dclabaut/mac_flap] echo $(($(cat
>>>>>> /var/run/keepalived.pid) + 2))
>>>>>> 177458
>>>>>>
>>>>>> All instances are in the MASTER state on this machine. Strace
>>>>>> -c gives
>>>>>> me the count of system calls on a 60 second time period:
>>>>>>
>>>>>> [root@bz-perflab-6-vr /home/dclabaut/mac_flap] timeout 60
>>>>>> strace
>>>>>> -cp 177458
>>>>>> % time     seconds  usecs/call     calls    errors syscall
>>>>>> ------ ----------- ----------- --------- --------- ----------
>>>>>> ------
>>>>>>     84.96    2.676412         880      3041       689 clone
>>>>>>
>>>>>> Using vrrp_scripts, I move all instances to BACKUP state,
>>>>>> then back to
>>>>>> MASTER state, and run the same command
>>>>>>
>>>>>> [root@bz-perflab-6-vr /home/dclabaut/mac_flap] timeout 60
>>>>>> strace
>>>>>> -cp 177458
>>>>>> % time     seconds  usecs/call     calls    errors syscall
>>>>>> ------ ----------- ----------- --------- --------- ----------
>>>>>> ------
>>>>>>     97.85   15.866534        4887      3247       901 clone
>>>>>>
>>>>>>
>>>>>> Again, I move all instances to BACKUP then MASTER, and take a
>>>>>> trace.
>>>>>>
>>>>>> There are about the same number of "clone" syscalls, but now
>>>>>> they take
>>>>>> 8651 usecs/call
>>>>>>
>>>>>> To make sure this a consequence of state change, I wait 10
>>>>>> then 20
>>>>>> minutes and take new traces.
>>>>>>
>>>>>> There is still the same number of "clone" syscalls, and now
>>>>>> they take
>>>>>> 7440 usecs/call.
>>>>>>
>>>>>> On a separate experiment where I kept changing the VRRP
>>>>>> state, I
>>>>>> saw an
>>>>>> entire core being used by this process.
>>>>>>
>>>>>> Is this a known issue?
>>>>>>
>>>>>> What can I do to help fix it?
>>>>>>
>>>>>> Kind regards,
>>>>>>
>>>>> Hi Damian,
>>>>>
>>>>> This sounds an interesting problem. In the first place could
>>>>> you please
>>>>> provide a copy of your configuration files (presumably from at
>>>>> least
>>>>> two system  as close as possible to what you are running, and
>>>>> also
>>>>> copies of the scripts. I'll then see if I can reproduce the
>>>>> problem in
>>>>> a Debian VM, and if so see if other distros exhibit the same
>>>>> problem.
>>>>> I'll also have a look so see if my latest development version,
>>>>> which
>>>>> has quite a few changes in the way scripts are run, also
>>>>> exhibits the
>>>>> same problem.
>>>>>
>>>>> It would be helpful if you could explain what you do to force
>>>>> all the
>>>>> instances into backup and then back to master, and over what
>>>>> timescale.
>>>>>
>>>>> At the moment I haven't a clue what the problem might be.
>>>>>
>>>>> Could you write a program that could issue a few hundred
>>>>> clone() system
>>>>> calls, and see what happens to the performance of those around
>>>>> the time
>>>>> you see the different results for keepalived?
>>>>>
>>>>> BTW, echo $(($(cat /var/run/keepalived.pid) + 2)) isn't a
>>>>> reliable way
>>>>> of getting the pid of the keepalived_vrrp process. I sometimes
>>>>> see the
>>>>> keepalived parent and children processes having consecutive
>>>>> pids, and
>>>>> sometimes there are gaps of one or two in between. Better to
>>>>> use
>>>>> vrrp.pid.
>>>>>
>>>>> Many thanks for reporting this issue.
>>>>>
>>>>> Quentin Armitage

-- 
Damien Clabaut
R&D vRouter
ovh.qc.ca


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot