Sawyer X > Perlbal-Plugin-SessionAffinity-0.010 > Perlbal::Plugin::SessionAffinity

Download:
Perlbal-Plugin-SessionAffinity-0.010.tar.gz

Dependencies

Annotate this POD

View/Report Bugs
Module Version: 0.010   Source   Latest Release: Perlbal-Plugin-SessionAffinity-0.100

NAME ^

Perlbal::Plugin::SessionAffinity - Sane session affinity (sticky sessions) for Perlbal

VERSION ^

version 0.010

SYNOPSIS ^

    LOAD SessionAffinity

    CREATE POOL backends
      POOL backends ADD 10.20.20.100
      POOL backends ADD 10.20.20.101
      POOL backends ADD 10.20.20.102

    CREATE SERVICE balancer
      SET listen          = 0.0.0.0:80
      SET role            = reverse_proxy
      SET pool            = backends
      SET persist_client  = on
      SET persist_backend = on
      SET verify_backend  = on
      SET plugins         = sessionaffinity
    ENABLE balancer

DESCRIPTION ^

Perlbal doesn't support session affinity (or otherwise known as "sticky sessions") out of the box. There is a plugin on CPAN called Perlbal::Plugin::StickySessions but there are a few problems with it.

This plugin should be do a much better job. Go ahead and read why you should use this one and how it works.

WHY YOU SHOULD USE IT ^

Here are things that are unique in this plugin. I am comparing this with the current available session affinity implementation available on CPAN (Perlbal::Plugin::StickySessions).

HOW DOES IT WORK ^

Basic stuff

Basically, the module creates a SHA1 checksum for each backend node, and provides the user with a cookie request. If the user provides that cookie in return, it will try and find and provide the user with that specific node.

If the node is no longer in the service's pool, or the cookie matches a node that doesn't exist, it will provide the user with a cookie again.

Advanced stuff

The plugin sets up dedicated pools and services for each service's node. This is required since Perlbal has no way of actually allowing you to specify the node a user will go to, only the service. Not to worry, this creation is done lazily so it saves as much memory as it can.

When a user comes in with a cookie of a node that exist in the service's pool it will create a pool for it (if one doesn't exist), and a matching service for it (if one doesn't exist) and then direct to user to it.

The check against nodes and pools is done live and not against the static configuration file. This means that if you're playing with the pools (changing them live, for example), it will still work just fine.

A new service is created using configurations from the existing service. The more interesting details is that reuse is emphasized so no new sockets are created and instead this new service uses the already existing sockets (along with existing connections) instead of firing new ones. It doesn't open a new socket for listening or anything like that. This also means your SSL connections work seamlessly. Yes, it's insanely cool, I know! :)

Incompatibilities

If you've read the Advanced stuff section above, you might have guessed a possible problem with anything that relies on the name of the service.

If you're using a plugin that relies on the name of the service, you might notice it stops working properly. This is because the new service that is generated by SessionAffinity is no longer the previous service, and doesn't contain its name. Instead it has its own name, which is not known to your plugin.

If you're using the header command to add headers to the backend, fear not. We copy over the headers from the original service to the new one. That still works just fine.

One possible way to fix it (implemented and later removed) is to include the previous name in a new unofficial (and unauthorized) key in the service hash.

ATTRIBUTES ^

affinity_cookie_header

The name of the cookie header for the session.

Default: X-SERVERID.

affinity_use_salt

Whether to use a salt or not when calculating SHA1 IDs.

    # both are equal
    affinity_use_salt = 1
    affinity_use_salt = yes

    # opposite meaning
    affinity_use_salt = 0
    affinity_use_salt = no

Default: no.

affinity_salt

The salt that is used to create the backend's SHA1 IDs.

Default: the following code is run when you load Perlbal::Plugin::SessionAffinity to create the salt on start up:

    join q{}, map { $_ = rand 999; s/\.//; $_ } 1 .. 10;

If you want predictability with salt, you can override it as such:

    affinity_salt = helloworld

    # now the calculation will be:
    my $sha1 = sha1hex( $salt . $ip . $port );

affinity_use_domain

Uses domain-mode for finding the backend. This is an alternate way of deciding the backend, which enables backends to persist per domain, allowing you to avoid a fragmented cache. If you have a lot of cache misses because of jumping between backends, try turning this feature on.

This feature ignores the cookie provided (and does not provide its own cookie) since backends are decided by the domain name alone.

    # both are equal
    affinity_use_domain = 1
    affinity_use_domain = yes

    # opposite meaning
    affinity_use_domain = 0
    affinity_use_domain = no

Default: no.

SUBROUTINES/METHODS ^

register

Registers our events.

unregister

Unregister our hooks and setters events.

get_ip_port

Parses a request's cookies and finds the specific cookie relating to session affinity and get the backend details via the ID in the cookie.

find_backend_by_id

Given a SHA1 ID, find the correct backend to which it belongs.

find_backend_by_domain_id

Given a SHA1 ID for a domain, find the correct backend to which it belongs.

create_id

Creates a SHA1 checksum ID using Digest::SHA. The checksum is composed of the IP, port and salt. If you want to have more predictability, you can provide a salt of 0 or string and then the checksum would be predictable.

This should make it clear on how it's created:

    if ( $has_salt ) {
        $checksum = sha1sum( $salt . "$ip:$port" );
    } else {
        $checksum = sha1sum( "$ip:$port" );
    }

create_domain_id

Same concept as the above create_id function, except for the following changes:

Accepts a domain and a list of nodes (which is assumed to be ordered), uses the domain_index function to get the index in the nodes of a domain and picks the correct node from the list it receives by index.

domain_index

This function tries to fetch an index number for a given domain name. It accepts a domain name and the maximum index number.

It translates the domain name to a long number, and uses mod (%) on it.

DEPENDENCIES ^

Perlbal

Obviously.

CGI::Cookies

To parse and create cookies.

Digest::SHA

To provide a SHA1 checksum.

SEE ALSO ^

Perlbal::Plugin::StickySessions

AUTHOR ^

Sawyer X <xsawyerx@cpan.org>

COPYRIGHT AND LICENSE ^

This software is copyright (c) 2013 by Sawyer X.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

syntax highlighting: