# gochat: A Layered Go IM Server with WebSocket, TCP and etcd Service Discovery

> gochat is a lightweight instant messaging server written in pure Go, organized into four horizontally scalable layers (api, connect, logic, task) that communicate over rpc, use etcd for service discovery, and rely on Redis for message queuing and session storage. It targets Go developers who want to study or extend a real IM architecture.

**LockGit/gochat** — goim server write by golang !🚀

- Repository: https://github.com/LockGit/gochat
- Website: http://45.77.108.245:8080
- Stars: 2,931 · Forks: 475
- Language: Go
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/lockgit-gochat

## What problem gochat solves and who it is for

Building an instant messaging server from scratch involves solving several orthogonal problems at once: handling large numbers of persistent connections, routing messages between users who may be on different servers, detecting when a server or user goes offline, and scaling out individual layers without redeploying the whole system. gochat provides a concrete, working implementation of one approach to all of these problems in a single Go codebase.

The README positions the project as a study vehicle. The layered architecture and directory structure are described as intentionally clear so that developers can trace the message flow from an API call through the logic and task layers to the connect layer where the user's WebSocket or TCP connection lives. The audience is Go developers who want to understand IM system design rather than organizations looking for a production-ready chat service. The project also provides a Docker one-click setup that compiles all modules and starts a working chat room, so the bar to running a demo is low.

Support for both WebSocket and TCP in the same codebase is a notable capability. The README notes that the most recent version added interoperability between the two transports, so a user connected over WebSocket and a user connected over TCP can exchange messages in the same room. The connect layer is split accordingly into connect_tcp and connect_websocket submodules.

## Four-layer architecture and message delivery flow

gochat is divided into four layers, each of which can be scaled horizontally:

- api: exposes a REST API, receives user requests and forwards them to the logic layer via rpc
- connect: holds all persistent user connections (WebSocket or TCP), pushes messages to connected users, and calls logic via rpc
- logic: the central coordination layer that records which connect server a given user is on, manages room membership and pushes messages into the Redis queue
- task: consumes from the Redis queue and calls the appropriate connect layer server to deliver each message

The README describes a full private message flow in five steps. User A logs in through the api layer, which calls logic to record that A is on a given connect server. User B does the same. When A sends a message to B, the api layer rpc-calls logic, which pushes the message to Redis. The task layer pulls from Redis, looks up which connect server B is on, and rpc-calls that server. The connect server then pushes the message to B's open connection.

For room broadcasts, the connect layer pushes to all sessions in the room on its server. For private messages, the task layer uses the userId to locate the right connect server before the final push.

Service discovery between layers uses etcd. When a connect server starts, it registers itself in etcd with its serverId. Other layers watch etcd for changes and update their known server addresses dynamically, which the README describes as the mechanism that allows scaling connect without downtime.

## Internal connection management: buckets, CityHash and snowflake IDs

A single connect server may hold thousands of concurrent user sessions. Managing these sessions under a single lock would create contention. gochat divides sessions into buckets, reducing the scope of each lock to a fraction of the total session pool. The README names this bucket subdivision as the mechanism for reducing lock competition.

Within each bucket, sessions for a room are stored in a doubly linked list. The README shows a diagram of this internal structure but does not document the bucket count or the default room structure in the cleaned text. The directory structure lists pkg/ as a top-level directory where the stickpackage utilities for TCP framing live.

Message IDs use the snowflakeId algorithm, which the README states is capable of 4.096 million IDs per second in theory. The comment in the README is candid: no internet company would actually hit that throughput unless under a DDoS attack. CityHash is used to distribute sessions across buckets more evenly than a naive modulo approach.

For TCP connections, the client must implement a framing protocol to split the byte stream into messages. The README points to pkg/stickpackage/stickpackage_test.go and its Test_TcpClient method as the reference for testing TCP delivery. The Pack and Unpack functions in stickpackage.go handle the framing. The test uses port 7001 or 7002 and requires an authToken that can be found in the API login response or queried from Redis directly.

## Installing and running gochat with Docker

The Docker path is the recommended way to start a demo. It pulls the pre-built image from Docker Hub and compiles all modules:

```bash
docker pull lockgit/gochat:1.18
git clone git@github.com:LockGit/gochat.git
cd gochat && sh run.sh dev 127.0.0.1
```

Once the compilation finishes, open http://127.0.0.1:8080/login and sign in with one of the default test accounts (demo, test or admin, each with password 111111). The README recommends using Chrome's incognito mode with multiple tabs to simulate different users in the same room.

For a manual install without Docker, you must start etcd and Redis first and ensure ports 7000, 7070 and 8080 are free. Then compile the binary:

```bash
go build -o gochat.bin -tags=etcd main.go
```

Start each layer in order:

```bash
./gochat.bin -module logic
./gochat.bin -module connect_websocket
./gochat.bin -module task
./gochat.bin -module api
./gochat.bin -module site
```

The README notes that the 2025-11-27 update added support for starting modules in any order, removing an earlier sequencing constraint. If scaling the connect layer, each connect server must have a unique serverId in its configuration.

For public deployment on a VPS, pass the public IP to run.sh instead of 127.0.0.1 and ensure the firewall allows the relevant ports. TCP testing additionally requires ports 7001 and 7002.

## Limitations: no message persistence, SQLite default and TCP framing requirement

Messages are not stored. The README states explicitly that messages flow through the Redis queue and are delivered once, then discarded. Adding persistence requires custom code. Teams who need chat history must implement their own storage layer before deploying gochat beyond a demo.

The default database is SQLite via gorm and stores only user account data. The README describes this as a convenience choice for the demo scenario and invites replacement with MySQL or another relational database by changing the database driver. The SQLite file at db/gochat.sqlite3 is included in the repository.

TCP clients must implement the Pack and Unpack protocol from pkg/stickpackage. The README provides a Go test client as a reference, but Android or iOS clients would need to reimplement the framing logic in their respective languages. There is no documented client SDK.

The vendor directory is included in the repository and adds approximately 66 MB, which makes the initial clone larger than typical. The README acknowledges this and attributes it to network accessibility issues that make downloading dependencies at build time unreliable in some regions.

The Go version requirement is 1.18 or later. The README warns against compiling on lower versions after the May 2022 update.

## Comparing gochat to a standard WebSocket broker approach

A common alternative for Go-based real-time messaging is to use a Redis Pub/Sub broker directly: each WebSocket server subscribes to a user or room channel, and publishing a message to that channel delivers it to all subscribers. This approach requires less custom infrastructure than gochat's four-layer model.

gochat's layered design trades simplicity for explicit control over each concern. The logic layer owns routing and can be scaled independently of the connect layer. The task layer buffers delivery without the connect layer needing to know the queue implementation. The README uses Redis as the queue and notes it could be replaced with Kafka or RabbitMQ.

For a team that only needs room broadcast and simple private messaging, the direct Pub/Sub approach needs fewer moving parts. gochat's architecture becomes more valuable when the team wants to understand how each layer scales independently, needs different scaling factors for API handling versus connection holding, or wants a reference for how etcd-based service discovery integrates with a rpc layer.

## Conclusion

gochat is a well-organized learning reference for Go developers who want to understand how a layered IM system is assembled from first principles: etcd service discovery, rpc between layers, Redis-backed queuing, snowflakeId generation and both WebSocket and TCP transports in one binary. The README is written in Chinese with an English translation in readme.en.md, which is a practical limitation for English-only teams. The project uses SQLite with gorm as its default database for demo convenience, and the README explicitly invites callers to swap in MySQL or another relational database when the sqlite3 constraint is a problem. Messages are not persisted by design; the queue delivers and discards them. Teams who need message history, a production-grade database layer or long-term vendor support should evaluate this as a starting point for a custom implementation rather than a ready-to-deploy service. The last push was on 2026-09-01.

## FAQ

### What database does gochat use by default?

gochat uses SQLite via gorm for the demo, storing only basic user account data. The README says this can be replaced with MySQL or another relational database by swapping the database driver, and the schema contains one user table with id, username, password and create_time.

### Does gochat store chat messages?

No. The README states explicitly that messages flow through the Redis queue and are delivered once without being stored. Adding message history requires writing custom storage logic on top of the existing architecture.

### What Go version does gochat require?

The go.mod specifies go 1.18. The README warns that the project should not be compiled on lower versions following the May 2022 dependency updates, and the Docker image uses the 1.18 tag.

## Sources

- [Issues](https://github.com/LockGit/gochat/issues)
- [License: MIT](https://github.com/LockGit/gochat/blob/master/LICENSE)
- [LockGit/gochat on GitHub](https://github.com/LockGit/gochat)
- [Project website](http://45.77.108.245:8080)
- [README](https://github.com/LockGit/gochat/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lockgit-gochat
