{"id":20532885,"url":"https://github.com/la3rence/websocket-cluster","last_synced_at":"2025-07-30T01:39:09.475Z","repository":{"id":37358850,"uuid":"351066444","full_name":"la3rence/websocket-cluster","owner":"la3rence","description":"一致性哈希实现有状态应用集群。Scalable spring-cloud project for WebSocket cluster with consistent-hashing algorithm.","archived":false,"fork":false,"pushed_at":"2024-12-19T21:13:47.000Z","size":694,"stargazers_count":137,"open_issues_count":10,"forks_count":48,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-24T18:04:15.069Z","etag":null,"topics":["consistent-hashing","distributed-systems","gateway-microservice","hashring","spring-cloud","websocket-cluster"],"latest_commit_sha":null,"homepage":"https://lawrenceli.me/blog/websocket-cluster","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/la3rence.png","metadata":{"files":{"readme":"README-en.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-24T12:10:27.000Z","updated_at":"2025-05-21T08:00:51.000Z","dependencies_parsed_at":"2024-09-15T01:30:41.429Z","dependency_job_id":"bef4e30e-5c6f-4139-b42d-0606f0ef9862","html_url":"https://github.com/la3rence/websocket-cluster","commit_stats":null,"previous_names":["la3rence/websocket-cluster","lonor/websocket-cluster"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/la3rence/websocket-cluster","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/la3rence%2Fwebsocket-cluster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/la3rence%2Fwebsocket-cluster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/la3rence%2Fwebsocket-cluster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/la3rence%2Fwebsocket-cluster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/la3rence","download_url":"https://codeload.github.com/la3rence/websocket-cluster/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/la3rence%2Fwebsocket-cluster/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267793530,"owners_count":24145056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["consistent-hashing","distributed-systems","gateway-microservice","hashring","spring-cloud","websocket-cluster"],"created_at":"2024-11-16T00:17:35.804Z","updated_at":"2025-07-30T01:39:09.416Z","avatar_url":"https://github.com/la3rence.png","language":"Java","readme":"# WebSocket Cluster (Spring Cloud) in action\n\nThis is a Spring Cloud project for WebSocket cluster servers.\n\n[中文](README.md)\n\n## Principle\n\nUsing a consistent hashing algorithm, we construct a hash ring where the gateway listens to the up and down event of the\nWebSocket service instances and dynamically updates the hash ring according to the changes of the instances. Each time a\nnew service comes online, the corresponding virtual node is added, and the WebSocket clients that need to change are\nreconnected to the new instance. Clients that need to be changed are reconnected to the new instance, which is the least\nexpensive; of course, it also depends on the count of the virtual nodes and the fairness of the hashing algorithm. When\nthe service goes offline, it is easier -- just disconnect all clients from the current instance, and the clients will\nalways reconnect. At the same time, the core role of the hash ring is reflected in the load balancing. When the gateway\ndoes its request forwarding, it goes through our rewritten custom load balancing filter, which implements real node\nrouting based on the fields that need to be hashed for business purposes.\n\n## Middleware / Environment Preparation\n\n- Docker (with API accessible)\n- Redis\n- RabbitMQ\n- Nacos\n\n## Development\n\nCreate a docker-compose network for [docker-compose.yml](./docker-compose.yml):\n\n```shell\ndocker network create compose-network\n```\n\nLocal build and deploy by docker-compose:\n\n```shell\nmvn clean\nmvn install -pl gateway -am -amd\nmvn install -pl websocket -am -amd\ndocker build -t websocket:1.0.0 websocket/.\ndocker build -t gateway:1.0.0 gateway/.\ndocker-compose up -d\ndocker ps\n```\n\nScale the websocket instance by: `docker-compose scale websocket-server=3`. Actually, I wrote a front-end web page to\nstart a new instance for websocket service.\n\nDon't forget to enable the docker remote api (e.g., check out `docker -H tcp://0.0.0.0:2375 ps`):\nThe following steps may help:\n\n### Access docker API on Linux\n\nAppend `-H tcp://0.0.0.0:2375` to the line started of `ExecStart` in the file named `docker.service`\n\n```shell\n# cat /usr/lib/systemd/system/docker.service\nExecStart=...... -H tcp://0.0.0.0:2375\n# after saved, restart the docker process\nsystemctl daemon-reload\nsystemctl restart docker\n```\n\n### Access docker API on macOS\n\nThe best practice is using the image `alpine/socat` to expose a tcp socket. (\nsee: [usage of socat](https://github.com/alpine-docker/socat#example)).\n\n```shell\ndocker run -itd --name socat \\\n    -p 0.0.0.0:6666:2375 \\\n    -v /var/run/docker.sock:/var/run/docker.sock \\\n    alpine/socat \\\n    tcp-listen:2375,fork,reuseaddr unix-connect:/var/run/docker.sock\n```\n\nFor the record, the Docker-desktop client for macOS provides the `docker.for.mac.host.internal` hostname for accessing\nthe host in the container of docker. I also add this domain to my `/etc/hosts` and point it to the localhost address. So\nI use this address in `application.yml` to set up configuration for the redis, the rabbitmq and the nacos servers(they\nare all deployed in the container). You can change this address if you deploy on your machine or other linux servers.\nBTW, the Makefile is only for self usage, which makes me build and restart the service faster during the development\nphase because I didn't prepare a CI/CD pipeline for this project. Please use it as needed.\n\n## Front-end\n\nCheck out [this react app](https://github.com/Lonor/websocket-cluster-front). It looks like:\n\n![Demo](./demo.gif)\n\n## Contribution\n\nIf this project helps, please star it. Submit an issue if you have any question. You can contribute code by forking this\nproject and submit your Pull Request.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fla3rence%2Fwebsocket-cluster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fla3rence%2Fwebsocket-cluster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fla3rence%2Fwebsocket-cluster/lists"}