3

In neo4j there's the transactional cypher endpoint. This allows the client to spawn a database transaction over multiple REST requests. The first request opens a new transaction and gets back the URL to be used for subsequent requests to the same transaction in a http Location header containing the transaction id, e.g.

Location: http://192.168.0.10:7474/db/data/transaction/24

The number at the end is the internal transaction id. A subsequent request to close the transaction gets send to http://192.168.0.10:7474/db/data/transaction/24/commit.

To accomplish that I'm using the following snippet for haproxy's backend configuration:

backend neo4j-all
    option httpchk GET /db/manage/server/ha/available
    stick-table type integer size 1k expire 10m
    stick match path,word(4,/) 
    stick store-response hdr(Location),word(6,/) 
    server s1 127.0.0.1:7474 maxconn 32 check
    server s2 127.0.0.1:7475 maxconn 32 check
    server s3 127.0.0.1:7476 maxconn 32 check

A sticky table gets populated with the transaction id (6th word in location header). The subsequent request's path contains the transaction id as 4th word. This part works fine.

However I want to limit down the usage of the stick table to paths starting with /db/data/transaction since Neo4j might have other endpoints as well with different behaviour.

My first naive approach was to simple add an acl to the backend:

 acl tx_cypher_endpoint path_beg /db/data/transaction

and then amend the stick match and stick store-response from above with an if tx_cypher_endpoint. Upon start this causes the following message:

parsing [haproxy.cfg:32] : acl 'tx_cypher_endpoint' will never match because it only involves keywords that are incompatible with 'backend stick-store rule'

Question #1: can someone please explain the reason for this?

As a workaround I've moved the acl to the frontend section and conditionally store a variable with txn scope that gets used in the backend:

frontend http-in
    bind *:8090
    acl tx_cypher_endpoint path_beg /db/data/transaction
    http-request set-var(txn.tx_cypher_endpoint) bool(true) if tx_cypher_endpoint
    default_backend neo4j-all

backend neo4j-all
    option httpchk GET /db/manage/server/ha/available
    acl tx_cypher_endpoint var(txn.tx_cypher_endpoint),bool
    stick-table type integer size 1k expire 10m
    stick match path,word(4,/) if tx_cypher_endpoint
    stick store-response hdr(Location),word(6,/) if tx_cypher_endpoint
    server s1 192.168.0.10:7474 maxconn 32 check
    server s2 192.168.0.11:7474 maxconn 32 check
    server s3 192.168.0.12:7474 maxconn 32 check

Question #2: is the above setup the most elegant approach or is there a simpler setup possible?

Question #3: how can I see what's going on internally in haproxy, e.g. what values get stored in a variable or in a stick table? Is the stats socket the way to go? Or is there a more verbose console output than using -d?

  • What's the purpose of your setup, is it a kind of load balancing with sticky sessions? – Axel Morgner Aug 17 '15 at 15:15
  • Exactly. Fronting a neo4j ha cluster and make sure the tx endpoint works transparently. – Stefan Armbruster Aug 17 '15 at 15:17
  • Did you try cookie or source based balancing? This would more or less bind a client to one of the servers unless the cookie or the source IP address changes, but that's by far the most simple solution IMHO. – Axel Morgner Aug 17 '15 at 15:28
  • cookie based balancing would require cookie handling on client side - which I want to avoid. Source based might be an option. However that means you send all requests from a given IP sticky to one neo4j instance. Assume you have one app server between your client and the neo4j layer - that means all cypher requests originate in the very same IP. So all Cypher is processed on the same machine and you can't scale the read operations. – Stefan Armbruster Aug 17 '15 at 16:46
  • Understood. Why am I not surprised that your request is heavily non-trivial. :-) Will check our haproxy setups and report back if I find sth. – Axel Morgner Aug 17 '15 at 23:02

0 Answers0