В этой статье будет рассказано, как реализовать систему распределенного чата (IM) на основе веб-сокета.
Используя golang для реализации связи через веб-сокет, одна машина может поддерживать миллионы подключений, используя структуру gin, загрузку nginx, горизонтальное развертывание, взаимную связь внутри программ и протокол связи grpc.
Содержание этой статьи относительно длинное. Если вы хотите напрямую познакомиться с проектом клонирования, введите его напрямую.Опыт проекта скачать проект goWebSocket, Текст начинается с введения в то, что такое webSocket, затем начинается введение в этот проект и настройка доменного имени в Nginx для переадресации webSocket, а затем рассказывается, как построить распределенную систему.
содержание
- 1. Описание проекта
- 1.1 goWebSocket
- 1.2 Опыт проекта
- 2. Представляем веб-сокет
- 2.1 Что такое веб-сокет
- 2.2 Совместимость веб-сокета
- 2.3 Зачем использовать веб-сокет
- 2.4 Процесс создания веб-сокета
- 3. Как реализовать систему длинных соединений на основе webSocket
- 3.1 Используйте go для реализации сервера webSocket
- 3.1.1 Начать прослушивание порта
- 3.1.2 Протокол обновления
- 3.1.3 Управление клиентскими подключениями
- 3.1.4 Зарегистрировать асинхронный обработчик, написанный клиентским сокетом
- 3.1.5 Зарегистрировать асинхронный обработчик для чтения клиентского сокета
- 3.1.6 Получение клиентских данных и обработка
- 3.1.7 Использование маршрутизации для обработки данных запроса клиента
- 3.1.8 Предотвратить переполнение памяти и не перезапускать Goroutine
- 3.2 Реализовать клиент webSocket с помощью javaScript
- 3.2.1 Запустите и зарегистрируйте прослушиватель
- 3.2.2 Отправка данных
- 3.1 Используйте go для реализации сервера webSocket
- 4. проект goWebSocket
- 4.1 Описание проекта
- 4.2 Зависимости проекта
- 4.3 Старт проекта
- 5, конфигурация Nginx проекта webSocket
- 5.1 Зачем настраивать Nginx
- 5.2 Конфигурация nginx
- 5.3 Устранение неполадок
- 6. Измерение давления
- 6.1 Оптимизация ядра Linux
- 6.2 Подготовка к стресс-тестам
- 6.3 Данные измерения давления
- 7. Как реализовать распределенный Im на базе webSocket
- 7.1 Описание
- 7.2 Архитектура
- 7.3 Развертывание распределенной системы
- 8. Обзор и размышление
- 8.1 Применение в других системах
- 8.2 Необходимо улучшить и оптимизировать
- 8.3 Резюме
- 9. Ссылки
1. Описание проекта
1.1 goWebSocket
В этой статье рассказывается, как реализовать распределенную систему на основе веб-чата (IM).
Используйте golang для реализации связи через веб-сокет, одна машина поддерживает миллионы подключений, использует структуру gin, загрузку nginx, может быть развернута горизонтально, взаимодействует друг с другом внутри программы и использует протокол связи grpc.
- Схема архитектуры, используемая webSocket в общих проектах
1.2 Опыт проекта
- Адрес проекта
- IM-чат Главнаяили открыть в новом окнеim.91vh.com/home/index
- После открытия соединения войдите в интерфейс чата
- Мультигрупповой чат может открывать два окна одновременно
2. Представляем веб-сокет
2.1 Что такое веб-сокет
Протокол WebSocket родился в 2008 году и стал международным стандартом в 2011 году. Все браузеры уже поддерживают его.
Его самая большая особенность заключается в том, что сервер может активно передавать информацию клиенту, а клиент также может активно отправлять информацию серверу.Это настоящий двусторонний равноправный диалог и относится к разновидности серверной технологии push.
-
Сравнение HTTP и WebSocket в процессе коммуникации
-
И HTTP, и webSocket поддерживают настройку сертификатов,
ws://
нет сертификатаwss://
Настройте идентификатор протокола сертификата
2.2 Совместимость веб-сокета
- Совместимость с браузером, версия, которая начинает поддерживать webSocket
- поддержка сервера
golang, java, php, node.js, python, nginx имеют хорошую поддержку
- Поддержка Android и IOS
Android может использовать java-webSocket для поддержки webSocket
iOS 4.2 и выше имеют поддержку WebSockets
2.3 Зачем использовать веб-сокет
-
- С точки зрения бизнеса требуется возможность активного доступа к клиенту.
В настоящее время большинство запросов выполняется с использованием HTTP.Клиент инициирует запрос, который обрабатывается сервером, а затем возвращает результат.Сервер не может активно отправлять данные клиенту.
-
- В большинстве сценариев нам необходимо активно уведомлять пользователей, например: система чата, пользователи активно информируют пользователей, когда они выполняют задачи, и о некоторых операционных действиях необходимо уведомлять онлайн-пользователей.
-
- Получить онлайн-статус пользователя
-
- Активный опрос клиента для получения данных при отсутствии длительного соединения
-
- Его можно реализовать одним способом и использовать на разных платформах (H5/Android/IOS).
2.4 Процесс создания веб-сокета
-
- Сначала клиент инициирует запрос на обновление протокола.
Клиент инициирует запрос на обновление протокола, используя стандартный формат сообщения HTTP и добавляя информацию заголовка к сообщению.
Connection: Upgrade
Указывает, что соединение необходимо обновить
Upgrade: websocket
Необходимо перейти на протокол веб-сокета
Sec-WebSocket-Version: 13
Версия протокола 13
Sec-WebSocket-Key: I6qjdEaqYljv3+9x+GrhqA==
Это значение кодировки base64, которое генерируется браузером случайным образом и на которое отвечает сервер.Sec-WebSocket-Accept
соответствовать
# Request Headers
Connection: Upgrade
Host: im.91vh.com
Origin: http://im.91vh.com
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: I6qjdEaqYljv3+9x+GrhqA==
Sec-WebSocket-Version: 13
Upgrade: websocket
-
- Протокол обновления ответа сервера
Сервер получает запрос на обновление протокола, и если сервер поддерживает протокол обновления, он ответит следующим образом.
возвращение:
Status Code: 101 Switching Protocols
Указывает на поддержку протоколов переключения
# Response Headers
Connection: upgrade
Date: Fri, 09 Aug 2019 07:36:59 GMT
Sec-WebSocket-Accept: mB5emvxi2jwTUhDdlRtADuBax9E=
Server: nginx/1.12.1
Upgrade: websocket
-
- После завершения протокола обновления клиент и сервер могут отправлять данные друг другу.
3. Как реализовать систему длинных соединений на основе webSocket
3.1 Используйте go для реализации сервера webSocket
3.1.1 Начать прослушивание порта
- websocket должен слушать порт, поэтому он должен быть в
golang
успешныйmain
Функция использует сопрограмму для запуска программы - main.goосуществить запуск
go websocket.StartWebSocket()
- init_acc.goстартовая программа
// 启动程序
func StartWebSocket() {
http.HandleFunc("/acc", wsPage)
http.ListenAndServe(":8089", nil)
}
3.1.2 Протокол обновления
- Клиент отправляется на сервер через http-запрос, нам нужно обновить протокол http до протокола websocket.
- Обновите библиотеку golang протокола HTTP-запросов.gorilla/websocketЭто уже сделано хорошо, мы можем использовать его напрямую
- При реальном использовании рекомендуется использовать две сопрограммы для каждого соединения для обработки данных клиентского запроса и отправки данных клиенту.Хотя открытие сопрограммы займет некоторую память, разделение чтения уменьшит возможность блокировки отправки и получения данных.
- init_acc.go
func wsPage(w http.ResponseWriter, req *http.Request) {
// 升级协议
conn, err := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
fmt.Println("升级协议", "ua:", r.Header["User-Agent"], "referer:", r.Header["Referer"])
return true
}}).Upgrade(w, req, nil)
if err != nil {
http.NotFound(w, req)
return
}
fmt.Println("webSocket 建立连接:", conn.RemoteAddr().String())
currentTime := uint64(time.Now().Unix())
client := NewClient(conn.RemoteAddr().String(), conn, currentTime)
go client.read()
go client.write()
// 用户连接事件
clientManager.Register <- client
}
3.1.3 Управление клиентскими подключениями
- Сколько пользовательских подключений имеет текущая программа, и потребность в пользовательских трансляциях, здесь нам нужен менеджер (clientManager) для обработки этих событий:
- Запишите все подключения, пользователи входа могут пройтиappId+uuidПроверить подключение пользователя
- Использование хранилища карт связано с проблемой одновременного чтения и записи нескольких сопрограмм, поэтому вам необходимо добавить блокировки чтения-записи.
- Определите четыре канала для обработки установления клиентского соединения, входа пользователя в систему, отключения и событий полной трансляции соответственно.
// 连接管理
type ClientManager struct {
Clients map[*Client]bool // 全部的连接
ClientsLock sync.RWMutex // 读写锁
Users map[string]*Client // 登录的用户 // appId+uuid
UserLock sync.RWMutex // 读写锁
Register chan *Client // 连接连接处理
Login chan *login // 用户登录处理
Unregister chan *Client // 断开连接处理程序
Broadcast chan []byte // 广播 向全部成员发送数据
}
// 初始化
func NewClientManager() (clientManager *ClientManager) {
clientManager = &ClientManager{
Clients: make(map[*Client]bool),
Users: make(map[string]*Client),
Register: make(chan *Client, 1000),
Login: make(chan *login, 1000),
Unregister: make(chan *Client, 1000),
Broadcast: make(chan []byte, 1000),
}
return
}
3.1.4 Зарегистрировать асинхронный обработчик, написанный клиентским сокетом
- Предотвратите сбои программы, поэтому вам нужно перехватывать исключения
- Чтобы отобразить здесь место ненормального сбоя, используйте
string(debug.Stack())
распечатать информацию о стеке вызовов - Если запись данных не удалась, возможно проблема с соединением, закройте соединение
- client.go
// 向客户端写数据
func (c *Client) write() {
defer func() {
if r := recover(); r != nil {
fmt.Println("write stop", string(debug.Stack()), r)
}
}()
defer func() {
clientManager.Unregister <- c
c.Socket.Close()
fmt.Println("Client发送数据 defer", c)
}()
for {
select {
case message, ok := <-c.Send:
if !ok {
// 发送数据错误 关闭连接
fmt.Println("Client发送数据 关闭连接", c.Addr, "ok", ok)
return
}
c.Socket.WriteMessage(websocket.TextMessage, message)
}
}
}
3.1.5 Зарегистрировать асинхронный обработчик для чтения клиентского сокета
- Прочитайте данные, отправленные клиентом в цикле, и обработайте их.
- Если прочитать данные не удается, закройте канал
- client.go
// 读取客户端数据
func (c *Client) read() {
defer func() {
if r := recover(); r != nil {
fmt.Println("write stop", string(debug.Stack()), r)
}
}()
defer func() {
fmt.Println("读取客户端数据 关闭send", c)
close(c.Send)
}()
for {
_, message, err := c.Socket.ReadMessage()
if err != nil {
fmt.Println("读取客户端数据 错误", c.Addr, err)
return
}
// 处理程序
fmt.Println("读取客户端数据 处理:", string(message))
ProcessData(c, message)
}
}
3.1.6 Получение клиентских данных и обработка
-
Согласен на отправку и получение формата данных запроса, для удобства обработки js, использование
json
Отправлять и получать данные в формате данных (человекочитаемый формат более удобен для использования в разработке работы) -
Войдите, чтобы отправить пример данных:
{"seq":"1565336219141-266129","cmd":"login","data":{"userId":"马远","appId":101}}
- Пример данных ответа на вход:
{"seq":"1565336219141-266129","cmd":"login","response":{"code":200,"codeMsg":"Success","data":null}}
-
Websocket — это двусторонняя передача данных, которую можно отправлять непрерывно.Если отправленные данные требуют ответа от сервера,seqЧтобы определить, на какие данные запроса отвечает сервер
-
cmd используется для определения действия, websocket не имеет URL-адреса, похожего на http, поэтому укажите, что такое действие cmd
-
Текущие действия: login/heartbeat используется для отправки запросов на вход и поддержания соединения (долгие соединения без передачи данных в течение длительного времени легко разрываются браузерами, мобильными посредниками, nginx и серверными программами)
-
Зачем нужен AppId?UserId – это единственное поле, которое представляет пользователя. Чтобы сделать его универсальным, AppId предназначен для указания того, на какой платформе пользователь входит в систему (веб, приложение, ios и т. д.), что удобно для последующее расширение.
-
request_model.goСогласованный формат данных запроса
/************************ 请求数据 **************************/
// 通用请求数据格式
type Request struct {
Seq string `json:"seq"` // 消息的唯一Id
Cmd string `json:"cmd"` // 请求命令字
Data interface{} `json:"data,omitempty"` // 数据 json
}
// 登录请求数据
type Login struct {
ServiceToken string `json:"serviceToken"` // 验证用户是否登录
AppId uint32 `json:"appId,omitempty"`
UserId string `json:"userId,omitempty"`
}
// 心跳请求数据
type HeartBeat struct {
UserId string `json:"userId,omitempty"`
}
- response_model.go
/************************ 响应数据 **************************/
type Head struct {
Seq string `json:"seq"` // 消息的Id
Cmd string `json:"cmd"` // 消息的cmd 动作
Response *Response `json:"response"` // 消息体
}
type Response struct {
Code uint32 `json:"code"`
CodeMsg string `json:"codeMsg"`
Data interface{} `json:"data"` // 数据 json
}
3.1.7 Использование маршрутизации для обработки данных запроса клиента
- Используйте маршрутизацию для обработки данных запроса, отправленных клиентом.
- После добавления типа запроса в дальнейшем можно использовать класс для его обработки аналогично http (маршрутизатор-контроллер).
- acc_routers.go
// Websocket 路由
func WebsocketInit() {
websocket.Register("login", websocket.LoginController)
websocket.Register("heartbeat", websocket.HeartbeatController)
}
3.1.8 Предотвратить переполнение памяти и не перезапускать Goroutine
-
- Запланированные задачи для очистки тайм-аута соединений Соединение без входа в систему и соединение с входом в систему будут разорваны, если в течение 6 минут не будет пульса.
client_manager.go
// 定时清理超时连接
func ClearTimeoutConnections() {
currentTime := uint64(time.Now().Unix())
for client := range clientManager.Clients {
if client.IsHeartbeatTimeout(currentTime) {
fmt.Println("心跳时间超时 关闭连接", client.Addr, client.UserId, client.LoginTime, client.HeartbeatTime)
client.Socket.Close()
}
}
}
-
- Если одна из горутин чтения и записи выходит из строя, они закрывают друг друга.
write()
Горутине не удалось записать данные, закрытьc.Socket.Close()
соединение будет закрытоread()
Goroutineread()
Горутине не удалось прочитать данные, закрытьclose(c.Send)
соединение будет закрытоwrite()
Goroutine
- Если одна из горутин чтения и записи выходит из строя, они закрывают друг друга.
-
- Клиент активно закрывается
Закройте горутины чтения и записи
от
ClientManager
удалить соединение
- Клиент активно закрывается
Закройте горутины чтения и записи
от
-
- Мониторинг пользовательских подключений и количество горутин Девять из десяти переполнений памяти связаны с горутинами Добавьте http-интерфейс для просмотра состояния системы и предотвращения перезапуска горутин.Просмотр состояния системы
-
- Nginx настраивает время освобождения неактивного соединения, чтобы не забыть закрыть соединение.
-
- Используйте pprof для анализа производительности, затрат времени
3.2 Реализовать клиент webSocket с помощью javaScript
3.2.1 Запустите и зарегистрируйте прослушиватель
- js устанавливает соединение и обрабатывает события успешного соединения, получения данных и отключения.
ws = new WebSocket("ws://127.0.0.1:8089/acc");
ws.onopen = function(evt) {
console.log("Connection open ...");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
data_array = JSON.parse(evt.data);
console.log( data_array);
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
3.2.2 Отправка данных
- Примечание. Данные могут быть отправлены только после успешного установления соединения.
- Пример отправки данных от клиента на сервер после установления соединения
登录:
ws.send('{"seq":"2323","cmd":"login","data":{"userId":"11","appId":101}}');
心跳:
ws.send('{"seq":"2324","cmd":"heartbeat","data":{}}');
ping 查看服务是否正常:
ws.send('{"seq":"2325","cmd":"ping","data":{}}');
关闭连接:
ws.close();
4. проект goWebSocket
4.1 Описание проекта
-
Этот проект представляет собой распределенную систему обмена мгновенными сообщениями, основанную на реализации веб-сокетов.
-
Клиент случайным образом назначает имена пользователей, и каждый входит в комнату чата, чтобы реализовать функцию группового чата.
-
Одна машина (24 ядра и 128 ГБ памяти) поддерживает миллионы клиентских подключений.
-
Поддержка горизонтального развертывания, развернутые машины могут взаимодействовать друг с другом
-
Диаграмма архитектуры проекта
4.2 Зависимости проекта
- В этом проекте нужно использовать только Redis и Golang.
- Этот проект использует govendor для управления зависимостями, клонируйте этот проект, и вы можете использовать его напрямую
# 主要使用到的包
github.com/gin-gonic/gin@v1.4.0
github.com/go-redis/redis
github.com/gorilla/websocket
github.com/spf13/viper
google.golang.org/grpc
github.com/golang/protobuf
4.3 Старт проекта
- клонировать проект
git clone git@github.com:link1st/gowebsocket.git
# 或
git clone https://github.com/link1st/gowebsocket.git
- Изменить конфигурацию проекта
cd gowebsocket
cd config
mv app.yaml.example app.yaml
# 修改项目监听端口,redis连接等(默认127.0.0.1:3306)
vim app.yaml
# 返回项目目录,为以后启动做准备
cd ..
- Описание файла конфигурации
app:
logFile: log/gin.log # 日志文件位置
httpPort: 8080 # http端口
webSocketPort: 8089 # webSocket端口
rpcPort: 9001 # 分布式部署程序内部通讯端口
httpUrl: 127.0.0.1:8080
webSocketUrl: 127.0.0.1:8089
redis:
addr: "localhost:6379"
password: ""
DB: 0
poolSize: 30
minIdleConns: 30
- Стартовый проект
go run main.go
- Введите адрес чатаhttp://127.0.0.1:8080/home/index
- Здесь вы можете испытать систему обмена мгновенными сообщениями на основе веб-сокета.
5, конфигурация Nginx проекта webSocket
5.1 Зачем настраивать Nginx
- Используйте nginx для разделения внутренней и внешней сетей и открывайте внешнему миру только IP-адрес Nginx (обычные интернет-компании добавят уровень LVS перед nginx для балансировки нагрузки), чтобы уменьшить вероятность вторжения.
- Использование Nginx может использовать функцию загрузки Nginx.Когда внешний интерфейс используется снова, необходимо подключить только фиксированное доменное имя, а трафик распределяется по разным машинам через Nginx.
- При этом мы также можем использовать разные стратегии загрузки Nginx (опрос, вес, ip_hash)
5.2 Конфигурация nginx
- Используйте доменное имяim.91vh.comДля примера обратитесь к конфигурации
- каталог первого уровняim.91vh.com/accОн используется для webSocket, и он использует функцию переадресации потока nginx (nginx 1.3.31 начинает ее поддерживать, и конфигурация Tengine такая же), и перенаправляет его на порт golang 8089 для обработки.
- Другие каталоги используются для HTTP и перенаправляются на порт golang 8080 для обработки.
upstream go-im
{
server 127.0.0.1:8080 weight=1 max_fails=2 fail_timeout=10s;
keepalive 16;
}
upstream go-acc
{
server 127.0.0.1:8089 weight=1 max_fails=2 fail_timeout=10s;
keepalive 16;
}
server {
listen 80 ;
server_name im.91vh.com;
index index.html index.htm ;
location /acc {
proxy_set_header Host $host;
proxy_pass http://go-acc;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Connection "";
proxy_redirect off;
proxy_intercept_errors on;
client_max_body_size 10m;
}
location /
{
proxy_set_header Host $host;
proxy_pass http://go-im;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_redirect off;
proxy_intercept_errors on;
client_max_body_size 30m;
}
access_log /link/log/nginx/access/im.log;
error_log /link/log/nginx/access/im.error.log;
}
5.3 Устранение неполадок
- Запустите тестовую команду nginx, чтобы проверить правильность файла конфигурации.
/link/server/tengine/sbin/nginx -t
- Если есть ошибка
nginx: [emerg] unknown "connection_upgrade" variable
configuration file /link/server/tengine/conf/nginx.conf test failed
- Подход
- существуетnginx.comДобавить к
http{
fastcgi_temp_file_write_size 128k;
..... # 需要添加的内容
#support websocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
.....
gzip on;
}
- Причина: Nginx столкнется с проблемами дизайна, когда прокси-сервер Nginx webSocketEnd-to-end and Hop-by-hop Headers
6. Измерение давления
6.1 Оптимизация ядра Linux
- Установите количество дескрипторов открытия файла
ulimit -n 1000000
- Установить параметры подключения к сокетам
vim /etc/sysctl.conf
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
6.2 Подготовка к стресс-тестам
- Чтобы пройти испытание под давлением, если у вас есть результаты испытания под давлением, добро пожаловать, чтобы добавить
- В будущем будут специальные туториалы, от подачи заявки на машины, написания кейсов стресс-тестов, оптимизации ядра и получения данных стресс-тестов.
6.3 Данные измерения давления
- Когда проект фактически используется, каждое соединение занимает около 24 КБ памяти, а одна горутина занимает около 11 КБ.
- 22G памяти требуется для поддержки одного миллиона подключений
Количество онлайн-пользователей | cup | ОЗУ | I/O | net.out |
---|---|---|---|---|
1W | ||||
10W | ||||
100W |
7. Как реализовать распределенный Im на базе webSocket
7.1 Описание
-
Обратитесь к исходному коду этого проекта
-
Для удобства демонстрации система обмена мгновенными сообщениями и система webSocket(acc) объединены в одну систему.
-
Интерфейс системы обмена мгновенными сообщениями: Получить всех пользователей онлайн, запросить всех пользователей сервиса перед заказом + всех пользователей сервиса в кластере Для отправки сообщения здесь используется http-интерфейс (веб-версия WeChat также является http-интерфейсом для отправки сообщений), здесь следует учитывать два основных момента: 1. Разделение сервисов, сделать систему акк максимально простой, не смешивая другую бизнес-логику 2. Отправка сообщений осуществляется через http интерфейс, вместо использования webSocket соединения используется метод разделения данных от получения и отправки, что позволяет ускорить эффективность отправки и получения данных.
7.2 Архитектура
- Схема регистрации запуска проекта и последовательности подключения пользователей
- Схема последовательности отправки сообщений из других систем (IM, задачи) пользователям, подключенным к системе webSocket (acc)
7.3 Развертывание распределенной системы
- Демонстрация подразвертывания с горизонтальным развертыванием двух проектов (gowebsocket и gowebsocket1)
- Как общаться друг с другом между проектами: после запуска проекта зарегистрируйте Ip проекта и rpcPort в Redis, чтобы другие проекты могли его найти, и используйте gRpc для связи, когда требуется связь.
- gowebsocket
# app.yaml 配置文件信息
app:
logFile: log/gin.log
httpPort: 8080
webSocketPort: 8089
rpcPort: 9001
httpUrl: im.91vh.com
webSocketUrl: im.91vh.com
# 在启动项目
go run main.go
- gowebsocket1
# 将第一个项目拷贝一份
cp -rf gowebsocket gowebsocket1
# app.yaml 修改配置文件
app:
logFile: log/gin.log
httpPort: 8081
webSocketPort: 8090
rpcPort: 9002
httpUrl: im.91vh.com
webSocketUrl: im.91vh.com
# 在启动第二个项目
go run main.go
- Конфигурация Nginx
Добавьте IP и порт второй машины в предыдущий элемент конфигурации Nginx.
upstream go-im
{
server 127.0.0.1:8080 weight=1 max_fails=2 fail_timeout=10s;
server 127.0.0.1:8081 weight=1 max_fails=2 fail_timeout=10s;
keepalive 16;
}
upstream go-acc
{
server 127.0.0.1:8089 weight=1 max_fails=2 fail_timeout=10s;
server 127.0.0.1:8090 weight=1 max_fails=2 fail_timeout=10s;
keepalive 16;
}
- Перезапустите Nginx после завершения настройки.
- После перезапуска запроса убедитесь, что он соответствует ожиданиям:
Посмотрите, падает ли запрос на оба проекта Поэкспериментируйте, могут ли два пользователя также отправлять сообщения друг другу, подключившись к разным проектам (gowebsocket и gowebsocket1).
- О распределенном развертывании
Этот проект просто демонстрирует, как проект развертывается распределенным образом и как модули взаимодействуют друг с другом после распределенного развертывания. Полностью решить систему без единой точки отказа, но также нужен кластер Nginx, кластер Redis и т. д.
8. Обзор и размышление
8.1 Применение в других системах
- Первоначальная цель системного дизайна состоит в том, чтобы поддерживать длительное соединение с клиентом и иметь два интерфейса с внешней системой (для проверки того, находится ли пользователь в сети, и для отправки сообщений онлайн-пользователям), чтобы реализовать разделение услуг.
- Он может использоваться несколькими службами только в том случае, если он отделен от бизнеса, вместо установления длинного соединения для каждого бизнеса.
8.2 Реализованные функции
- журнал журнала gin (журнал запросов + журнал отладки)
- чтение файла конфигурации сделано
- Временный скрипт для очистки просроченных неподдерживаемых подключений Завершено
- http интерфейс, получить количество логинов и подключений Готово
- http-интерфейс, отправка push-уведомлений, запрос количества людей в сети Завершено
- Внутренняя связь программы grpc, отправка сообщения завершена
- appIds, когда пользователь входит в систему на нескольких платформах
- интерфейс, собрать всех онлайн-людей в группу, отправить сообщение, завершить
-
чат один на один, групповой чат завершен - Распределенное горизонтальное расширение Завершено
- Скрипт стресс-теста
- Документация
- Каталог документов, реализация миллионов длинных подключений, зачем внедрять IM, как реализовать IM
- Схема архитектуры и расширение
Детали реализации IM:
- Определить структуру текстового сообщения Готово
- html отправить текстовое сообщение готово
- Интерфейс получает текстовое сообщение и отправляет его всей группе Готово
- html получает сообщение и отображает его в завершенном интерфейсе
- Оптимизация интерфейса требует постоянной оптимизации
- После того, как кто-то присоединяется, вся трансляция завершается.
- Определите структуру сообщения присоединения к чату
- Представляем робота, который будет определен
8.2 Необходимо улучшить и оптимизировать
- Войдите в систему, используйте WeChat для входа в систему, чтобы получить никнейм, аватар и т. д.
- Система учета, система данных
- Оптимизация интерфейса, адаптация под мобильные телефоны
- Сообщение Текстовое сообщение (поддержка смайлика), изображение, голос, видеосообщение
- Регистрация микросервисов, обнаружение, автоматический выключатель и т. д.
- Добавить элементы конфигурации, максимальное количество подключений на машину
8.3 Резюме
- Несмотря на то, что реализован распределенный обмен мгновенными сообщениями, есть много деталей, которые не были обработаны (логин не аутентифицирован, интерфейс еще не оптимизирован и т. д.), но вы можете узнать из этого примера: Решить многие бизнес-задачи через WebSocket
- Хотя в этой статье утверждается, что одна машина может иметь миллионы длинных подключений (которые могут быть удовлетворены в памяти), реальная ситуация намного сложнее, чем это (процессор несколько загружен).Конечно, если у вас такой большой бизнес объем, вы можете купить больше машин.Хорошо для поддержки вашего бизнеса, эта программа просто демонстрирует, как использовать webSocket на практике.
- Со ссылкой на эту статью вы можете реализовать программу, соответствующую вашим потребностям
9. Ссылки
Руан Ифэн Учебное пособие по WebSocket
Протокол WebSocket: 5 минут от входа до освоения
поиск на github: link1st Посмотреть проект gowebsocket