簡體   English   中英

制作 netty-socketio 服務器集群

[英]Make cluster of netty-socketio server

我正在使用進行 socketio 設置。 我有 2 個不同的 socketio 服務器(比如 server1 和 server2),使用RedissonStoreFactory在集群中運行

我的問題是,如果任何客戶端與 server1 連接,則 server2 沒有連接客戶端的信息。 即。 如果 2 個客戶端與 server1 連接並且如果我在 server2 上執行server.getAllClients()它返回空列表而不是具有 2 個計數的列表。

這是我在 2 台不同機器上運行的代碼。

@SpringBootApplication
public class Application {


    private static final Logger LOGGER = Logger.getLogger(Application.class);

    @Value("${test.socketio.hostName}")
    private String socketIOHostName;

    @Value("${test.socketio.port}")
    private Integer socketIOport;

    @Value("${test.dedisson.redissonAddress}")
    private String redissonAddress;

    @Autowired
    private RedissonClient redissonClient;

    @Bean
    public SocketIOServer socketIOServer() {
        LOGGER.info("Socket server starting on host=" + socketIOHostName + ", port=" + socketIOport);
        Configuration config = new Configuration();
        config.setHostname(socketIOHostName);
        config.setPort(socketIOport);

        StoreFactory redissonStoreFactory = new RedissonStoreFactory(redissonClient);
        config.setStoreFactory(redissonStoreFactory);
        SocketIOServer server = new SocketIOServer(config);
        server.start();
        LOGGER.info( "Socket server started");
        return server;
    }

    /**
     * 
     * @return
     */
    @Bean
    public RedissonClient getRedissonClient(){
        LOGGER.info("creatting redisson client on redissonAddress="+redissonAddress);
        Config config = new Config();
        config.useSingleServer().setAddress(redissonAddress);
        RedissonClient redisson = Redisson.create(config);
        LOGGER.info("redisson client connected");
        return redisson;
    }


    public Application() {
        //Nothing to be done here
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
    }

    @Bean
    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer ssrv) {
        return new SpringAnnotationScanner(ssrv);
    }
}

我更喜歡故障轉移條件的 2 個實例。如果 server1 關閉,則 server2 會將通知發送到連接的客戶端,但在我的情況下,server2 不知道與 server1 連接的客戶端。

如果 2 個客戶端與 server1 連接,並且如果我在 server2 上執行 server.getAllClients() 它返回空列表而不是具有 2 個計數的列表。

這是預期的。 Server2 可能有一些有關與 server1 連接的客戶端的信息(因為它們將 redis 與 pub/sub 一起使用),例如 sessionId(查看類BaseStoreFactory )等,但 server2 未與這些客戶端連接,server2 和客戶端之間不存在 Channel服務器 1。 想一想,在底層,當沒有 tcp 套接字連接存在時,server2 怎么可以與客戶端通信。

我更喜歡故障轉移條件的 2 個實例。如果 server1 關閉,則 server2 會將通知發送到連接的客戶端,但在我的情況下,server2 不知道與 server1 連接的客戶端。

使用 Nginx(帶有iphash )或集群頂部的任何代理,一旦一台服務器出現故障,客戶端將嘗試重新連接,nginx 會將其重定向到另一台服務器。 從客戶的角度來看,不會有太多延遲。

我遇到了類似的問題,並用我的“自協議”解決了這個問題。

服務器 A客戶端 X連接,服務器 B客戶端 Y連接。 我需要從服務器 A客戶端 Y發送私人消息 該解決方案是通過在每個服務器中映射所有服務器主機的列表來實現的,並且我們為每個服務器主機創建一個“內部客戶端”。

每個內部客戶端負責通知其各自的服務器,然后服務器可以檢查 client-target 是否存在於其自身的客戶端列表中。

給定服務器 A ,如果您想列出集群的所有客戶端,您可以要求每個內部客戶端為其連接服務器發送一個數據包,例如“ REQUEST ”,然后為“ RESPONSE ”消息創建一個偵聽器並將結果添加到全球名單。

構建.gradle

implementation group: 'io.socket', name: 'socket.io-client', version: '1.0.0'

服務器

Configuration config = new Configuration();
config.setHostname(LOCALHOST);
config.setPort(PORT);
config.setTransports(Transport.WEBSOCKET); // DONT FORGET THIS LINE !!!

Config redissonConfig = new Config();
redissonConfig.useSingleServer().setAddress("redis://192.168.0.24:6379")
            .setPassword("myPass");
Redisson redisson = (Redisson) Redisson.create(redissonConfig);
RedissonStoreFactory redisStoreFactory = new RedissonStoreFactory(redisson);
config.setStoreFactory(redisStoreFactory);

SocketIOServer server = new SocketIOServer(config);

server.addEventListener("REQUEST", Object.class, (client, data, ackSender) -> {
    server.getBroadcastOperations().sendEvent("RESPONSE", server.getAllClients());
});

內部客戶

List<SocketIOClient> allClients = new ArrayList<>();
List<Socket> internalClients = new ArrayList<>();
String[] hostnames = { "http://localhost:8081", "http://localhost:8082" };

for (String hostname : hostnames) {
    IO.Options opts = new IO.Options();
    opts.transports = new String[] { WebSocket.NAME };  // DONT FORGET THIS LINE !!!
    Socket socket = IO.socket(hostname, opts);

    socket.on("RESPONSE", args -> {
        List<SocketIOClient> currentList = (List<SocketIOClient>) args[0];
        allClients.addAll(currentList);
    });

    socket.connect();
    internalClients.add(socket);
}

for (Socket socket : internalClients) {
    socket.emit("REQUEST", "foo"); // THIS LINE WILL FILL CLIENTS LIST, VIA CALLBACK, FOR EACH SERVER
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM