[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-8058":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":16,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":19,"hasPages":19,"topics":21,"createdAt":10,"pushedAt":10,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":16,"starSnapshotCount":16,"syncStatus":25,"lastSyncTime":26,"discoverSource":27},8058,"synapse","airbnb\u002Fsynapse","airbnb","A transparent service discovery framework for connecting an SOA","",null,"Ruby",2063,248,315,27,0,59.19,"MIT License",false,"master",[],"2026-06-12 04:00:37","[![Build Status](https:\u002F\u002Ftravis-ci.org\u002Fairbnb\u002Fsynapse.png?branch=master)](https:\u002F\u002Ftravis-ci.org\u002Fairbnb\u002Fsynapse)\n[![Inline docs](http:\u002F\u002Finch-ci.org\u002Fgithub\u002Fairbnb\u002Fsynapse.png)](http:\u002F\u002Finch-ci.org\u002Fgithub\u002Fairbnb\u002Fsynapse)\n\n# Synapse #\n\nSynapse is Airbnb's new system for service discovery.\nSynapse solves the problem of automated fail-over in the cloud, where failover via network re-configuration is impossible.\nThe end result is the ability to connect internal services together in a scalable, fault-tolerant way.\n\n## Motivation ##\n\nSynapse emerged from the need to maintain high-availability applications in the cloud.\nTraditional high-availability techniques, which involve using a CRM like [pacemaker](http:\u002F\u002Flinux-ha.org\u002Fwiki\u002FPacemaker), do not work in environments where the end-user has no control over the networking.\nIn an environment like Amazon's EC2, all of the available workarounds are suboptimal:\n\n* Round-robin DNS: Slow to converge, and doesn't work when applications cache DNS lookups (which is frequent)\n* Elastic IPs: slow to converge, limited in number, public-facing-only, which makes them less useful for internal services\n* ELB: ultimately uses DNS (see above), can't tune load balancing, have to launch a new one for every service * region, autoscaling doesn't happen fast enough\n\nOne solution to this problem is a discovery service, like [Apache Zookeeper](http:\u002F\u002Fzookeeper.apache.org\u002F).\nHowever, Zookeeper and similar services have their own problems:\n\n* Service discovery is embedded in all of your apps; often, integration is not simple\n* The discovery layer itself is subject to failure\n* Requires additional servers\u002Finstances\n\nSynapse solves these difficulties in a simple and fault-tolerant way.\n\n## How Synapse Works ##\n\nSynapse typically runs on your application servers, often every machine. At the heart of Synapse\nare proven routing components like [HAProxy](http:\u002F\u002Fhaproxy.1wt.eu\u002F) or [NGINX](http:\u002F\u002Fnginx.org\u002F).\n\nFor every external service that your application talks to, we assign a synapse local port on localhost.\nSynapse creates a proxy from the local port to the service, and you reconfigure your application to talk to the proxy.\n\nUnder the hood, Synapse supports `service_watcher`s for service discovery and\n`config_generators` for configuring local state (e.g. load balancer configs)\nbased on that service discovery state.\n\nSynapse supports service discovery with pluggable `service_watcher`s which\ntake care of signaling to the `config_generators` so that they can react and\nreconfigure to point at available servers on the fly.\n\nWe've included a number of default watchers, including ones that query zookeeper and ones using the AWS API.\nIt is easy to write your own watchers for your use case, and install them as gems that\nextend Synapse's functionality. Check out the [docs](#createsw) on creating\na watcher if you're interested, and if you think that the service watcher\nwould be generally useful feel free to pull request with a link to your watcher.\n\nSynapse also has pluggable `config_generator`s, which are responsible for reacting to service discovery\nchanges and writing out appropriate config. Right now HAProxy, and local files are built in, but you\ncan plug your own in [easily](#createconfig).\n\n## Example Migration ##\n\nLet's suppose your rails application depends on a Postgres database instance.\nThe database.yaml file has the DB host and port hardcoded:\n\n```yaml\nproduction:\n  database: mydb\n  host: mydb.example.com\n  port: 5432\n```\n\nYou would like to be able to fail over to a different database in case the original dies.\nLet's suppose your instance is running in AWS and you're using the tag 'proddb' set to 'true' to indicate the prod DB.\nYou set up synapse to proxy the DB connection on `localhost:3219` in the `synapse.conf.yaml` file.\nAdd a hash under `services` that looks like this:\n\n```yaml\n---\n services:\n  proddb:\n   default_servers:\n    -\n     name: \"default-db\"\n     host: \"mydb.example.com\"\n     port: 5432\n   discovery:\n    method: \"awstag\"\n    tag_name: \"proddb\"\n    tag_value: \"true\"\n   haproxy:\n    port: 3219\n    server_options: \"check inter 2000 rise 3 fall 2\"\n    frontend: mode tcp\n    backend: mode tcp\n```\n\nAnd then change your database.yaml file to look like this:\n\n```yaml\nproduction:\n  database: mydb\n  host: localhost\n  port: 3219\n```\n\nStart up synapse.\nIt will configure HAProxy with a proxy from `localhost:3219` to your DB.\nIt will attempt to find the DB using the AWS API; if that does not work, it will default to the DB given in `default_servers`.\nIn the worst case, if AWS API is down and you need to change which DB your application talks to, simply edit the `synapse.conf.json` file, update the `default_servers` and restart synapse.\nHAProxy will be transparently reloaded, and your application will keep running without a hiccup.\n\n## Installation\n\nTo download and run the synapse binary, first install a version of ruby. Then,\ninstall synapse with:\n\n```bash\n$ mkdir -p \u002Fopt\u002Fsmartstack\u002Fsynapse\n# If you are on Ruby 2.X use --no-document instead of --no-ri --no-rdoc\n\n# If you want to install specific versions of dependencies such as an older\n# version of the aws-sdk, the docker-api, etc, gem install that here *before*\n# gem installing synapse.\n\n# Example:\n# $ gem install aws-sdk -v XXX\n\n$ gem install synapse --install-dir \u002Fopt\u002Fsmartstack\u002Fsynapse --no-ri --no-rdoc\n\n# If you want to install specific plugins such as watchers or config generators\n# gem install them *after* you install synapse.\n\n# Example:\n# $ gem install synapse-nginx --install-dir \u002Fopt\u002Fsmartstack\u002Fsynapse --no-ri --no-rdoc\n```\n\nThis will download synapse and its dependencies into \u002Fopt\u002Fsmartstack\u002Fsynapse. You\nmight wish to omit the `--install-dir` flag to use your system's default gem\npath, however this will require you to run `gem install synapse` with root\npermissions.\n\nYou can now run the synapse binary like:\n\n```bash\nexport GEM_PATH=\u002Fopt\u002Fsmartstack\u002Fsynapse\n\u002Fopt\u002Fsmartstack\u002Fsynapse\u002Fbin\u002Fsynapse --help\n```\n\nDon't forget to install HAProxy or NGINX or whatever proxy your `config_generator`\nis configuring.\n\n## Configuration ##\n\nSynapse depends on a single config file in JSON format; it's usually called `synapse.conf.json`.\nThe file has a `services` section that describes how services are discovered\nand configured, and then top level sections for every supported proxy or\nconfiguration section. For example, the default Synapse supports three sections:\n\n* [`services`](#services): lists the services you'd like to connect.\n* [`haproxy`](#haproxy): specifies how to configure and interact with HAProxy.\n* [`file_output`](#file) (optional): specifies where to write service state to on the filesystem.\n* [`\u003Cyour config generator here>`] (optional): configuration for your custom\n   configuration generators (e.g. nginx, vulcand, envoy, etc ..., w.e. you want).\n\nIf you have synapse `config_generator` plugins installed, you'll want a top\nlevel as well, e.g.:\n* [`nginx`](https:\u002F\u002Fgithub.com\u002Fjolynch\u002Fsynapse-nginx#top-level-config) (optional):\n  configuration for how to configure and interact with NGINX.\n\n\u003Ca name=\"services\"\u002F>\n\n### Configuring a Service ###\n\nThe `services` section is a hash, where the keys are the `name` of the service to be configured.\nThe name is just a human-readable string; it will be used in logs and notifications.\nEach value in the services hash is also a hash, and must contain the following keys:\n\n* [`discovery`](#discovery): how synapse will discover hosts providing this service (see [below](#discovery))\n\nThe services hash *should* contain a section on how to configure each routing\ncomponent you wish to use for this particular service. The current choices are\n`haproxy` but you can access others e.g. [`nginx`](https:\u002F\u002Fgithub.com\u002Fjolynch\u002Fsynapse-nginx)\nthrough [plugins](createconfig). Note that if you give a routing component at the top level\nbut not at the service level the default is typically to make that service\navailable via that routing component, sans listening ports. If you wish to only\nconfigure a single component explicitly pass the ``disabled`` option to the\nrelevant routing component. For example if you want to only configure HAProxy and\nnot NGINX for a particular service, you would pass ``disabled`` to the `nginx` section\nof that service's watcher config.\n\n* [`haproxy`](#haproxysvc): how will the haproxy section for this service be configured. If the corresponding `watcher` is defined to use `zookeeper` and the service publishes its `haproxy` configure on ZK, the `haproxy` hash can be filled\u002Fupdated via data from the ZK node.\n* [`nginx`](https:\u002F\u002Fgithub.com\u002Fjolynch\u002Fsynapse-nginx#service-watcher-config): how will the nginx section for this service be configured. **NOTE** to use this you must have the synapse-nginx [plugin](#plugins) installed.\n\nThe services hash may contain the following additional keys:\n\n* `default_servers` (default: `[]`): the list of default servers providing this service; synapse uses these if no others can be discovered. See [Listing Default Servers](#defaultservers).\n* `keep_default_servers` (default: false): whether default servers should be added to discovered services\n* `use_previous_backends` (default: true): if at any time the registry drops all backends, use previous backends we already know about.\n\u003Ca name=\"backend_port_override\"\u002F>\n* `backend_port_override`: the port that discovered servers listen on; you should specify this if your discovery mechanism only discovers names or addresses (like the DNS watcher or the Ec2TagWatcher). If the discovery method discovers a port along with hostnames (like the zookeeper watcher) this option may be left out, but will be used in preference if given.\n\n\u003Ca name=\"discovery\"\u002F>\n\n#### Service Discovery ####\n\nWe've included a number of `watchers` which provide service discovery.\nPut these into the `discovery` section of the service hash, with these options:\n\n##### Base #####\n\nThe base watcher is useful in situations where you only want to use the servers in the `default_servers` list.\nIt has the following options:\n\n* `method`: base\n* `label_filters`: optional list of filters to be applied to discovered service nodes\n\n###### Filtering service nodes ######\n\nSynapse can be configured to only return service nodes that match a `label_filters` predicate. If provided, `label_filters` should be an array of hashes which contain the following:\n\n* `label`: The name of the label for which the filter is applied\n* `value`: The comparison value\n* `condition` (one of ['`equals`', '`not-equals`']): The type of filter condition to be applied.\n\nGiven a `label_filters`: `[{ \"label\": \"cluster\", \"value\": \"dev\", \"condition\": \"equals\" }]`, this will return only service nodes that contain the label value `{ \"cluster\": \"dev\" }`.\n\n##### Zookeeper #####\n\nThis watcher retrieves a list of servers and also service config data from zookeeper.\nIt takes the following mandatory arguments:\n\n* `method`: zookeeper\n* `path`: the zookeeper path where ephemeral nodes will be created for each available service server\n* `hosts`: the list of zookeeper servers to query\n* `retry_policy`: the retry policy (exponential back-off) when connecting to zookeeper servers and making network calls: `max_attempts` maximum number of all attempts (including original attempt), `max_delay` maxmimum delay in seconds for all attempts (including original attempt), `base_interval` retry interval in seconds for first retry attempt, `max_interval` maximum interval in seconds for each retry attempt. By default the retry policy is disabled.\n\nThe watcher assumes that each node under `path` represents a service server.\n\nThe watcher assumes that the data (if any) retrieved at znode `path` is a hash, where each key is named by a valid `config_generator` (e.g. `haproxy`) and the value is a hash that configs the generator.   Alternatively, if a `generator_config_path` argument is specified, the watcher will attempt to read generator config from that znode instead.\nIf `generator_config_path` has the value `disabled`, then generator config will not be read from zookeeper at all.\n\nThe following arguments are optional:\n\n* `decode`: A hash containing configuration for how to decode the data found in zookeeper.\n\n###### Decoding service nodes ######\nSynapse attempts to decode the data in each of these nodes using JSON and you can control how it is decoded with the `decode` argument. If provided, the `decode` hash should contain the following:\n\n* `method` (one of ['`nerve`', '`serverset`'], default: '`nerve`'): The kind of data to expect to find in zookeeper nodes\n* `endpoint_name` (default: nil): If using the `serverset` method, this controls which of the `additionalEndpoints` is chosen instead of the `serviceEndpoint` data. If not supplied the `serverset` method will use the host\u002Fport from the `serviceEndpoint` data.\n\nIf the `method` is `nerve`, then we expect to find nerve registrations with a `host` and a `port`.\nAny additional metadata for the service node provided in the hash `labels` will be parsed. This information is used by `label_filter` configuration.\n\nIf the `method` is `serverset` then we expect to find Finagle ServerSet\n(also used by [Aurora](https:\u002F\u002Fgithub.com\u002Fapache\u002Faurora\u002Fblob\u002Fmaster\u002Fdocs\u002Fuser-guide.md#service-discovery)) registrations with a `serviceEndpoint` and optionally one or more `additionalEndpoints`.\nThe Synapse `name` will be automatically deduced from `shard` if present.\n\n##### Zookeeper Poll #####\n\nThis watcher retrieves a list of servers and also service config data from zookeeper.\nInstead of setting Zookeeper watchers, it uses a long-polling method.\n\nIt takes the following mandatory arguments:\n\n* `method`: zookeeper_poll\n* `polling_interval_sec`: the interval at which the watcher will poll Zookeeper. Defaults to 60 seconds.\n\nOther than these two options, it takes the same options as the above ZookeeperWatcher.\nFor all the required options, see above.\n\n##### Docker #####\n\nThis watcher retrieves a list of [docker](http:\u002F\u002Fwww.docker.io\u002F) containers via docker's [HTTP API](http:\u002F\u002Fdocs.docker.io\u002Fen\u002Flatest\u002Freference\u002Fapi\u002Fdocker_remote_api\u002F).\nIt takes the following options:\n\n* `method`: docker\n* `servers`: a list of servers running docker as a daemon. Format is `{\"name\":\"...\", \"host\": \"...\"[, port: 4243]}`\n* `image_name`: find containers running this image\n* `container_port`: find containers forwarding this port\n* `check_interval`: how often to poll the docker API on each server. Default is 15s.\n\n##### AWS EC2 tags #####\n\nThis watcher retrieves a list of Amazon EC2 instances that have a tag\nwith particular value using the AWS API.\nIt takes the following options:\n\n* `method`: ec2tag\n* `tag_name`: the name of the tag to inspect. As per the AWS docs,\n  this is case-sensitive.\n* `tag_value`: the value to match on. Case-sensitive.\n\nAdditionally, you MUST supply [`backend_port_override`](#backend_port_override)\nin the service configuration as this watcher does not know which port the\nbackend service is listening on.\n\nThe following options are optional, provided the well-known `AWS_`\nenvironment variables shown are set. If supplied, these options will\nbe used in preference to the `AWS_` environment variables.\n\n* `aws_access_key_id`: AWS key or set `AWS_ACCESS_KEY_ID` in the environment.\n* `aws_secret_access_key`: AWS secret key or set `AWS_SECRET_ACCESS_KEY` in the environment.\n* `aws_region`: AWS region (i.e. `us-east-1`) or set `AWS_REGION` in the environment.\n\n##### Marathon #####\n\nThis watcher polls the Marathon API and retrieves a list of instances for a\ngiven application.\n\nIt takes the following options:\n\n* `marathon_api_url`: Address of the marathon API (e.g. `http:\u002F\u002Fmarathon-master:8080`)\n* `application_name`: Name of the application in Marathon\n* `check_interval`: How often to request the list of tasks from Marathon (default: 10 seconds)\n* `port_index`: Index of the backend port in the task's \"ports\" array. (default: 0)\n\n##### Multi #####\n\nThe `MultiWatcher` aggregates multiple watchers together. This allows getting\nservice discovery data from multiple sources and combining them into one set of\nbackends.\n\nIt takes the following options:\n\n* `method`: must be `multi`\n* `watchers`: a hash of name --> child watcher config. The name should uniquely identify\n  the child watcher, and the config should be of the same format that the child watcher\n  expects. I.e. a valid config for a Zookeeper child watcher looks like\n  `{\"my_watcher\" => {\"method\" => \"zookeeper\", \"path\" => \"\u002Fsvc\", \"hosts\": [\"localhost:2181\"]} }`\n* `resolver`: an options hash which creates a `Resolver`. The `method` field of that hash\n  is used to decide what `resolver` to use, and the rest of the options are passed to that.\n\n###### S3 Toggle File Resolver ######\n\nThis resolver merges results by picking one of the watchers to treat as the source of truth.\nThat watcher is picked based on the contents of an S3 file, which is periodically polled.\nIn other words, the file in S3 \"toggles\" between different watchers.\n\nIt takes the following options:\n\n* `method`: must be `s3_toggle`\n* `s3_url`: an S3-style URL pointing to the file. Looks like `s3:\u002F\u002F{bucket}\u002F{path...}`.\n* `s3_polling_interval_seconds`: frequency with which to fetch the file\n\nThe S3 file has the following YAML schema:\n\n```yaml\nwatcher_name: weight\nsecond_watcher_name: weight\n```\n\nIt is a simple dictionary in YAML where the key refers to the watcher nam\n(as provided to the `MultiWatcher`) and the value is an integer, non-negative\nweight that determines the probability for that watcher to be chosen.\n\n###### Union Resolver ######\n\nThe `UnionResolver` merges the backends from each child watcher into a single list.\nFor example, with two children watchers that have backends of `[a, b]` and `[c, d]`,\nit will return `[a, b, c, d]`.\n\nThe `config_for_generator` cannot be easily merged; intead, we pick the first non-empty\nconfig. As such, when using `union` you should ensure that only one watcher returns\na config or that all watchers have the same config.\n\n* `method`: must be `union`\n\n###### Sequential Resolver ######\n\nThe `SequentialResolver` goes through a specific ordering of watchers and returns the\nfirst set of backends that did not error or return an empty set.\nIf `sequential_order` is `['primary', 'secondary']`, it will first read the backends from\n`primary`; `secondary` will only be read if the `primary` fails (by returning an empty set\nof backends). The smae method is used for the `config_for_generator`.\n\nIt takes the following options:\n\n* `method`: must be `sequential`\n* `sequential_order`: a list of watcher names that will be read in the provided order\n\n\u003Ca name=\"defaultservers\"\u002F>\n\n#### Listing Default Servers ####\n\nYou may list a number of default servers providing a service.\nEach hash in that section has the following options:\n\n* `name`: a human-readable name for the default server; must be unique\n* `host`: the host or IP address of the server\n* `port`: the port where the service runs on the `host`\n\nThe `default_servers` list is used only when service discovery returns no servers.\nIn that case, the service proxy will be created with the servers listed here.\nIf you do not list any default servers, no proxy will be created.  The\n`default_servers` will also be used in addition to discovered servers if the\n`keep_default_servers` option is set.\n\nIf you do not list any `default_servers`, and all backends for a service\ndisappear then the previous known backends will be used.  Disable this behavior\nby unsetting `use_previous_backends`.\n\n\u003Ca name=\"haproxysvc\"\u002F>\n\n#### The `haproxy` Section ####\n\nThis section is its own hash, which should contain the following keys:\n\n* `disabled`: A boolean value indicating if haproxy configuration management\nfor just this service instance ought be disabled. For example, if you want\nfile output for a particular service but no HAProxy config. (default is ``False``)\n* `port`: the port (on localhost) where HAProxy will listen for connections to\nthe service. If this is null, just the bind_address will be used (e.g. for\nunix sockets) and if omitted, only a backend stanza (and no frontend stanza)\nwill be generated for this service. In the case of a bare backend, you'll need\nto get traffic to your service yourself via the `shared_frontend` or\nmanual frontends in `extra_sections`\n* `bind_address`: force HAProxy to listen on this address (default is localhost).\nSetting `bind_address` on a per service basis overrides the global `bind_address`\nin the top level `haproxy`. Having HAProxy listen for connections on\ndifferent addresses (example: service1 listen on 127.0.0.2:443 and service2\nlisten on 127.0.0.3:443) allows \u002Fetc\u002Fhosts entries to point to services.\n* `bind_options`: optional: default value is an empty string, specify additional bind parameters, such as ssl accept-proxy, crt, ciphers etc.\n* `server_port_override`: **DEPRECATED**. Renamed [`backend_port_override`](#backend_port_override) and moved to the top level hash. This will be removed in future versions.\n* `server_options`: the haproxy options for each `server` line of the service in HAProxy config; it may be left out. This field supports some basic templating: you can add include `%{port}`, `%{host}`, or `%{name}` in this string, and those will be replaced with the appropriate values for the particular server being configured.\n* `frontend`: additional lines passed to the HAProxy config in the `frontend` stanza of this service\n* `backend`: additional lines passed to the HAProxy config in the `backend` stanza of this service\n* `backend_name`: The name of the generated HAProxy backend for this service\n  (defaults to the service's key in the `services` section)\n* `listen`: these lines will be parsed and placed in the correct `frontend`\u002F`backend` section as applicable; you can put lines which are the same for the frontend and backend here.\n* `backend_order`: optional: how backends should be ordered in the `backend` stanza. (default is shuffling).\n  Setting to `asc` means sorting backends in ascending alphabetical order before generating stanza.\n  `desc` means descending alphabetical order.\n  `no_shuffle` means no shuffling or sorting.\n  If you shuffle consider setting `server_order_seed` at the top level so that your backend\n  ordering is deterministic across HAProxy reloads.\n* `shared_frontend`: optional: haproxy configuration directives for a shared http frontend (see below)\n* `cookie_value_method`: optional: default value is `name`, it defines the way your backends receive a cookie value in http mode. If equal to `hash`, synapse hashes backend names on cookie value assignation of your discovered backends, useful when you want to use haproxy cookie feature but you do not want that your end users receive a Set-Cookie with your server name and ip readable in clear.\n* `use_nerve_weights`: optional: this option enables reading the weights from nerve and applying them to the haproxy configuration. By default this is disabled in the case where users apply weights using `server_options` or `haproxy_server_options`.  This option will also remove the weight parameter from `server_options` and `haproxy_server_options`\n\n\u003Ca name=\"haproxy\"\u002F>\n\n### Configuring HAProxy ###\n\nThe top level `haproxy` section of the config file has the following options:\n\n* `do_checks`: whether or not Synapse will validate HAProxy config prior to writing it (default to `false`)\n* `check_command`: the command Synapse will run to validate HAProxy config\n* `candidate_config_file_path`: the path to write the pre-validated (candidate) HAProxy config to for the check command\n* `do_reloads`: whether or not Synapse will reload HAProxy (default to `true`)\n* `reload_command`: the command Synapse will run to reload HAProxy\n* `do_writes`: whether or not the config file will be written (default to `true`)\n* `config_file_path`: where Synapse will write the HAProxy config file\n* `do_socket`: whether or not Synapse will use the HAProxy socket commands to prevent reloads (default to `true`)\n* `socket_file_path`: where to find the haproxy stats socket. can be a list (if using `nbproc`)\n* `global`: options listed here will be written into the `global` section of the HAProxy config\n* `defaults`: options listed here will be written into the `defaults` section of the HAProxy config\n* `extra_sections`: additional, manually-configured `frontend`, `backend`, or `listen` stanzas\n* `bind_address`: force HAProxy to listen on this address (default is localhost)\n* `shared_frontend`: (OPTIONAL) additional lines passed to the HAProxy config used to configure a shared HTTP frontend (see below)\n* `restart_interval`: number of seconds to wait between restarts of haproxy (default: 2)\n* `restart_jitter`: percentage, expressed as a float, of jitter to multiply the `restart_interval` by when determining the next\n  restart time. Use this to help prevent healthcheck storms when HAProxy restarts. (default: 0.0)\n* `state_file_path`: full path on disk (e.g. \u002Ftmp\u002Fsynapse\u002Fstate.json) for\n  caching haproxy state between reloads.  If provided, synapse will store\n  recently seen backends at this location and can \"remember\" backends across\n  both synapse and HAProxy restarts. Any backends that are \"down\" in the\n  reporter but listed in the cache will be put into HAProxy disabled. Synapse\n  writes the state file every sixty seconds, so the file's age can be used to\n  monitor that Synapse is alive and making progress. (default: nil)\n* `state_file_ttl`: the number of seconds that backends should be kept in the\n  state file cache.  This only applies if `state_file_path` is provided.\n  (default: 86400)\n* `server_order_seed`: A number to seed random actions with so that all orders are\n  deterministic. You can use this so that backend ordering is deterministic\n  but still shuffled, for example by setting this to the hash of your machine's\n  IP address you guarantee that HAProxy on different machines have different\n  orders, but within that machine you always choose the same order.\n  (default: ``rand(2000)``)\n* `max_server_id`: Synapse will try to ensure that server lines are written out\n  with HAProxy \"id\"s that are unique and associated 1:1 with a service backend\n  (host + port + name). To ensure these are unique Synapse internally counts\n  up from 1 until `max_server_id`, so you can have no more than this number\n  of servers in a backend. If the default (65k) is not enough, make this higher\n  but be wary that HAProxy internally uses an int to store this id, so ...\n  your mileage may vary trying to make this higher. (default: 65535)\n\nNote that a non-default `bind_address` can be dangerous.\nIf you configure an `address:port` combination that is already in use on the system, haproxy will fail to start.\n\n\u003Ca name=\"file\"\u002F>\n\n### Configuring `file_output` ###\n\nThis section controls whether or not synapse will write out service state\nto the filesystem in json format. This can be used for services that want to\nuse discovery information but not go through HAProxy.\n\n* `output_directory`: the path to a directory on disk that service registrations\nshould be written to.\n\n### HAProxy shared HTTP Frontend ###\n\nFor HTTP-only services, it is not always necessary or desirable to dedicate a TCP port per service, since HAProxy can route traffic based on host headers.\nTo support this, the optional `shared_frontend` section can be added to both the `haproxy` section and each indvidual service definition.\nSynapse will concatenate them all into a single frontend section in the generated haproxy.cfg file.\nNote that synapse does not assemble the routing ACLs for you; you have to do that yourself based on your needs.\nThis is probably most useful in combination with the `service_conf_dir` directive in a case where the individual service config files are being distributed by a configuration manager such as puppet or chef, or bundled into service packages.\nFor example:\n\n```yaml\n haproxy:\n  shared_frontend:\n   - \"bind 127.0.0.1:8081\"\n  reload_command: \"service haproxy reload\"\n  config_file_path: \"\u002Fetc\u002Fhaproxy\u002Fhaproxy.cfg\"\n  socket_file_path:\n    - \u002Fvar\u002Frun\u002Fhaproxy.sock\n    - \u002Fvar\u002Frun\u002Fhaproxy2.sock\n  global:\n   - \"daemon\"\n   - \"user    haproxy\"\n   - \"group   haproxy\"\n   - \"maxconn 4096\"\n   - \"log     127.0.0.1 local2 notice\"\n   - \"stats   socket \u002Fvar\u002Frun\u002Fhaproxy.sock\"\n  defaults:\n   - \"log      global\"\n   - \"balance  roundrobin\"\n services:\n  service1:\n   discovery: \n    method: \"zookeeper\"\n    path:  \"\u002Fnerve\u002Fservices\u002Fservice1\"\n    hosts:\n     - \"0.zookeeper.example.com:2181\"\n   haproxy:\n    server_options: \"check inter 2s rise 3 fall 2\"\n    shared_frontend:\n     - \"acl is_service1 hdr_dom(host) -i service1.lb.example.com\"\n     - \"use_backend service1 if is_service1\"\n    backend: \"mode http\"\n\n  service2:\n   discovery:\n    method: \"zookeeper\"\n    path:  \"\u002Fnerve\u002Fservices\u002Fservice2\"\n    hosts: \"0.zookeeper.example.com:2181\"\n\n   haproxy:\n    server_options: \"check inter 2s rise 3 fall 2\"\n    shared_frontend:\n     - \"acl is_service1 hdr_dom(host) -i service2.lb.example.com\"\n     - \"use_backend service2 if is_service2\"\n    backend:\n     - \"mode http\"\n\n```\n\nThis would produce an haproxy.cfg much like the following:\n\n```\nbackend service1\n        mode http\n        server server1.example.net:80 server1.example.net:80 check inter 2s rise 3 fall 2\n\nbackend service2\n        mode http\n        server server2.example.net:80 server2.example.net:80 check inter 2s rise 3 fall 2\n\nfrontend shared-frontend\n        bind 127.0.0.1:8081\n        acl is_service1 hdr_dom(host) -i service1.lb\n        use_backend service1 if is_service1\n        acl is_service2 hdr_dom(host) -i service2.lb\n        use_backend service2 if is_service2\n```\n\nNon-HTTP backends such as MySQL or RabbitMQ will obviously continue to need their own dedicated ports.\n\n## Contributing\nNote that now that we have a fully dynamic include system for service watchers\nand configuration generators, you don't *have* to PR into the main tree, but\nplease do contribute a [link](#plugins).\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\n\u003Ca name=\"createsw\"\u002F>\n\n### Creating a Service Watcher ###\n\nSee the Service Watcher [README](lib\u002Fsynapse\u002Fservice_watcher\u002FREADME.md) for\nhow to add new Service Watchers.\n\n\u003Ca name=\"createconfig\"\u002F>\n\n### Creating a Config Generator ###\n\nSee the Config Generator [README](lib\u002Fsynapse\u002Fconfig_generator\u002FREADME.md) for\nhow to add new Config Generators\n\n\u003Ca name=\"plugins\"\u002F>\n\n## Links to Synapse Plugins ##\n* [`synapse-nginx`](https:\u002F\u002Fgithub.com\u002Fjolynch\u002Fsynapse-nginx) Is a `config_generator`\n  which allows Synapse to automatically configure and administer a local NGINX\n  proxy.\n","Synapse是Airbnb开发的一款用于服务发现的透明框架，旨在解决云端环境中自动化故障转移的问题。它通过在本地主机上为每个外部服务分配一个端口，并创建代理来实现应用与服务之间的连接，从而达到可扩展和容错的目的。核心组件包括HAProxy或NGINX等成熟的路由工具，支持插件式的`service_watcher`进行服务发现以及`config_generators`根据服务状态自动配置负载均衡器。适用于需要高可用性但缺乏对网络层控制能力的云环境，如Amazon EC2上的内部服务间通信场景。",2,"2026-06-11 03:15:52","top_language"]