keydb+socket.io 进行实时应用开发

socket.io 是一个很不错的实时应用开发框架,基于socket.io 开发的实时系统不少,而且socket.io 也支持不少语言框架的集成

参考图

 

 

玩法说明

通过keydb 的active-Replica 能力,可以实现一个快速的ha 能力,同时对于业务为了方便业务集成,添加了haproxy 作为lb,对于socket.io server 实例使用haproxy 提供的lb地址,对于业务应用可以基于nginx 通过路由规则将链接请求路由到不同的socket.io 单元中(按照业务的分离,对于跨业务的通信需要调整下)

参考集成

  • keydb docker-compose
version: '3'
services:
  db: 
    image: eqalpha/keydb
    command: keydb-server /etc/keydb/keydb.conf --requirepass dalong  --masterauth dalong --active-replica yes --replicaof db2  6379
    ports:
     - 6379:6379
  db2: 
    image: eqalpha/keydb
    command: keydb-server /etc/keydb/keydb.conf   --requirepass dalong  --masterauth dalong --active-replica yes --replicaof db  6379
    ports:
     - 6380:6379
  haproxy: 
    image: haproxytech/haproxy-debian:2.7.5
    volumes:
      - "./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg"
    ports:
    - "5002:6379"

haproxy 配置

global
    chroot /var/lib/haproxy
    stats timeout 30s
    user haproxy
    group haproxy
    # The lines below enable multithreading. This should correlate to number of threads available you want to use.
    nbthread 4
    maxconn 40000
 
defaults
    log global
    mode    tcp
    timeout connect 5000
    timeout client  50000
    timeout server  50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http
 
frontend  main
    bind :6379
    maxconn 40000 
    mode tcp
    option tcplog
    default_backend  app
 
backend app
    balance first
    option tcp-check
    server keydb3 db:6379 maxconn 20000 check inter 1s
    server keydb2 db2:6379 maxconn 20000 check inter 1s
  • socket.io 实例服务
    集成redis adapter
 
const app = require("express")();
const http = require("http").createServer(app);
const {Server} = require("socket.io")
 
const { createClient } = require('redis');
const { createAdapter } = require('@socket.io/redis-adapter');
 
const io = new Server(http,{
    cors: {
      origin: "*",
      methods: ["GET", "POST"]
    }
});
 
app.get("/", (req, res) => res.sendFile(__dirname + "/index.html"));
 
io.on("connection", function (socket) {
    console.log("socket connecte");
    io.emit("user connected");
    socket.on("message", function (msg) {
        io.emit("message", msg);
    });
});
 
const pubClient = createClient({ host: 'localhost', port: 5002,password:'dalong' });
const subClient = pubClient.duplicate();
Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
    io.adapter(createAdapter(pubClient, subClient));
    http.listen(3000, () => console.log("listening on http://localhost:3000"))
  });

index.html

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Socket.io Example</title>
</head>
 
<body>
    <h1>Our Socket.io Chat Application</h1>
    <div>
        <h2>Messages</h2>
        <ul></ul>
    </div>
    <form action="">
        <input type="text" />
        <button>Send</button>
    </form>
    <script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
    <script>
        // select relevant elements
        const form = document.querySelector("form");
        const input = document.querySelector("input");
        messageList = document.querySelector("ul");
 
        // establish socket.io connection
        const socket = io();
 
        // handle sending message to server & input reset
        function sendMessage(e) {
            // prevent form submission refreshing page
            e.preventDefault();
            // send input value to server as type 'message'
            socket.emit("message", input.value);
            // reset input value
            input.value = "";
        }
 
        // add listener to form submission
        form.addEventListener("submit", sendMessage);
 
        // add message to our page
        function addMessageToHTML(message) {
            // create a new li element
            const li = document.createElement("li");
            // add message to the elements text
            li.innerText = message;
            // add to list of messages
            messageList.append(li);
        }
        socket.on("message", addMessageToHTML);
        function alertUserConnected() {
            addMessageToHTML("User connected");
        }
        socket.on("user connected", alertUserConnected);
    </script>
</body>
 
</html>
  • java 集成
    基于官方的socket.io-client 客户端
 
public static void main(String[] args) {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .readTimeout(1, TimeUnit.MINUTES) // important for HTTP long-polling
                .build();
        IO.Options options = new IO.Options();
        options.callFactory = okHttpClient;
        Socket socket = IO.socket(URI.create("http://localhost:3001"), options);
        socket.on("message", new Emitter.Listener() {
            @Override
            public void call(Object... objects) {
                System.out.println(objects[0].toString());
            }
        });
        socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                System.out.println("EVENT_CONNECT");
            }
        });
        socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                System.out.println("EVENT_DISCONNECT");
            }
        });
        socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                System.out.println("EVENT_CONNECT_ERROR");
            }
        });
        socket.connect();
    }

说明

以上是一个简单的集成,实际上如果需要基于socket.io 做一个完备的实时系统还有不少事情需要做,权限,认证,安全,规则路由,成员管理,消息存储,离线消息处理
但是利用keydb提供的一些能力以及利用socket.io 周边的扩展,我们还是可以快速的开发一个简单但是可靠的实时应用的

参考资料

https://github.com/socketio/socket.io
https://github.com/socketio/socket.io-redis-adapter
https://socket.io/docs/v4/
https://socketio.github.io/socket.io-client-java/installation.html
https://github.com/rongfengliang/socket.io-keydb-learning

posted on 2023-03-20 19:57  荣锋亮  阅读(60)  评论(0编辑  收藏  举报

导航