Transcript

#GlobalAzure #ViseoSpirit

NodeJS & SocketIO scalablesStéphane Escandell@sescandellgithub/sescandell

Microsoft Azure #GlobalAzure #ViseoSpirit

GAB 2015 LYON ORAGANIZER

LOCAL SPONSORS

THANK YOU ALL !!

WORLDWIDE SPONSORS

#GlobalAzure #ViseoSpirit

Microsoft Azure #GlobalAzure #ViseoSpirit

• Node• Open source

– Créé en 2009– Basé sur le moteur V8

• Application C– Utilisée en tant que « gestionnaire de requêtes

HTTPs » dans l’exemple d’aujourd’hui– « Event-driven »– IO non bloquants

NodeJS

Microsoft Azure #GlobalAzure #ViseoSpirit

Socket.IO

JAVASCRIPTREALTIME

WEB

APP

BI-

DIR

EC

TIO

NN

AL

WEBSOCKETS

UNIFIED API

NO

DEJS

FALLBACK

EVENT DRIVEN

ASYNCHRONOUS

OPEN SOURCEBROADCASTING

CLIE

NT

SER

VER

WR

APPER

DATA

AJA

X

CROSS PLATFORM

MULTI-CLIENT

Bi-directionnal communicationEmit message

Broadcasting

Microsoft Azure #GlobalAzure #ViseoSpirit

Application de chat• Isolation par « room »• Notifications• Gravatar• Fallback pulling

Fil rouge

Microsoft Azure #GlobalAzure #ViseoSpirit 6

Fonctionnement de l’application

connect()

connect

load

peopleInChat

login

imgparticipantJoined

msgreceive

Login process

Notify users

Chat

loop

Notify users

Microsoft Azure #GlobalAzure #ViseoSpirit

démoEXÉCUTION LOCALE

Microsoft Azure #GlobalAzure #ViseoSpirit

• DevOps friendly– Interface intuitive– x-CLI

• Ouvert– .Net– PHP– Java– NodeJS– …

• Déploiement simplifié : git push azure• CI : hooks Git

Web App

Microsoft Azure #GlobalAzure #ViseoSpirit

• Windows Server• Serveur web IIS• Scalabilité automatique

• Pas de root• Pas d’accès RDP aux machines

Architecture Web App

9

Microsoft Azure #GlobalAzure #ViseoSpirit

• Pas de changement de l’application• Préparation de l’environnement

– Importation d’un profil de sécurisation– Exécuté une seule fois

• Selon votre préférence :– Portail en ligne– x-CLI– API Rest

Déploiement

10

Microsoft Azure #GlobalAzure #ViseoSpirit

azure site create gab2015demo --location "West Europe » --git --gitusername "sescandell"

git push azure local:master

11

Microsoft Azure #GlobalAzure #ViseoSpirit

Activation des websockets

azure site set –w gab2015demo

12

Microsoft Azure #GlobalAzure #ViseoSpirit

démoEXÉCUTION DEPUIS WEB APP

Microsoft Azure #GlobalAzure #ViseoSpirit

Quels problèmes pour la scalabilité ?

1 1

2 2 2

Les messages ne sont pas envoyés (broadcastés) aux différentes « instances socket.io »

Le stockage des participant est « local » (non partagé)

1

2

Microsoft Azure #GlobalAzure #ViseoSpirit

Architecture ciblée

15

Stockage des participants basé sur Azure Table Storage (un stockage clé-valeur)

Azure Service Bus service utilisé comme connecteur inter-scokets (compatible protocole AMQP)

Point d’entrée de l’application Web AppAgit comme un Load Balancer

Une instance

Microsoft Azure #GlobalAzure #ViseoSpirit

1ère étape : Adapter SocketIO - Service Busrequire(‘azure’);

module.exports = adapter;

function adapter(opts) { ... var azureServiceBusSender = azure.createServiceBusService(); var azureServiceBusReceiver = azure.createServiceBusService(); function AzureServiceBus(namespace) { azureServiceBusReceiver.createTopicIfNotExists("default", function(err) { azureServiceBusReceiver.createSubscription("default",getId(), function(err) { azureServiceBusReceiver.receiveSubscriptionMessage("default",getId(),this.onmessage.bind(this)); } }) } AzureServiceBus.prototype.__proto__ = Adapter.prototype;

AzureServiceBus.prototype.onmessage = function(err, receivedMessage) {azureServiceBusReceiver.receiveSubscriptionMessage(opts.topic, this.subscriptionId,

this.onmessage.bind(this));args.push(true);this.broadcast.apply(this, args);

};

16

Microsoft Azure #GlobalAzure #ViseoSpirit

AzureServiceBus.prototype.broadcast = function(packet, opt, remote) { Adapter.prototype.broadcast.call(this, packet, opt);

if (!remote) { var message = { body: msgpack.encode([packet, opt]) };

azureServiceBusSender.sendTopicMessage("default", message);}

}; return AzureServiceBus;}

17

Microsoft Azure #GlobalAzure #ViseoSpirit

démoEXÉCUTION DEPUIS WEB APP AVEC SOCKET.IO

Microsoft Azure #GlobalAzure #ViseoSpirit

Service Bus & NodeJS… Place à Redis

PubSub

Microsoft Azure #GlobalAzure #ViseoSpirit

Nouvelle architecture ciblée

20

Stockage des participants basé sur Azure Table Storage (un stockage clé-valeur)

Azure Redis Cache (via ses capacités pub/sub) service utilisé comme connecteur pour socket.IO

Point d’entrée de l’application Web AppAgit comme un Load Balancer

Une instance

Microsoft Azure #GlobalAzure #ViseoSpirit

1ère étape : Adapter SocketIO - Redisvar redis = require(‘redis’).createClient;var redisAdapter = require('socket.io-redis');

module.exports = function (app, io) { ... // Publisher var redisClientPub = redis( process.env.REDIS_PORT, process.env.REDIS_HOST, {auth_pass: process.env.REDIS_AUTH_PASS} ); // Subscriber var redisClientSub = redis( process.env.REDIS_PORT, process.env.REDIS_HOST, {auth_pass: process.env.REDIS_AUTH_PASS, detect_buffers: true} );

io.adapter(redisAdapter({ pubClient: redisClientPub, subClient: redisClientSub }));

21

Microsoft Azure #GlobalAzure #ViseoSpirit

2ème étape : Stockage – Azure Table Storagevar azureStorage = require('azure-storage');

module.exports = function () { // Service Repository var ParticipantTableStorage = function () { var azureTableService = azureStorage.createTableService(); var entGen = azureStorage.TableUtilities.entityGenerator; var tableName = 'participants'; var partitionKey = "default"; var prefix = process.env.WEBSITE_INSTANCE_ID || 'default';

// If this is the first time the application is launched, let's create the table azureTableService.createTableIfNotExists(tableName); return {

22

Microsoft Azure #GlobalAzure #ViseoSpirit

// Retrieve participants count from Store // We retrieve all participants to show you how to get a users' list getCount: function(room, callback) { var query = new azureStorage.TableQuery() .where('PartitionKey eq ?', partitionKey + room); azureTableService.queryEntities(tableName, query, null, function(err, result, response){ callback(undefined, result.entries.length); }.bind(this)) }, // Add a new participant to the store add: function(participant) { var entity = { PartitionKey: entGen.String(partitionKey + participant.room), RowKey: entGen.String(prefix + participant.id), username: entGen.String(participant.username), avatar: entGen.String(participant.avatar), room: entGen.String(participant.room) };

azureTableService.insertEntity(tableName, entity) },

23

Microsoft Azure #GlobalAzure #ViseoSpirit

// Remove a participant from the store remove: function(participant) { var entity = { PartitionKey: entGen.String(partitionKey + participant.room), RowKey: entGen.String(prefix + participant.id) };

azureTableService.deleteEntity(tableName, entity); } };

return ParticipantTableStorage;};

24

Microsoft Azure #GlobalAzure #ViseoSpirit

démoWEB APP / LOCAL / SOCKET IO / REDIS

Microsoft Azure #GlobalAzure #ViseoSpirit

26

Pour faire de la potion magique,

mieux vaut avoir la bonne

recette

Microsoft Azure #GlobalAzure #ViseoSpirit 27

• Devrait être une règle de base

• Créez des interfaces communes– Règles d’équipes– TypeScript

• Injection de dépendances– Stockage de données– Système de fichiers– Gestionnaire d’événement– … toutes les I/Os

I/O abstraction

Microsoft Azure #GlobalAzure #ViseoSpirit

GAB 2015 LYON ORAGANIZER

LOCAL SPONSORS

THANK YOU ALL !!

WORLDWIDE SPONSORS

#GlobalAzure #ViseoSpirit

Microsoft Azure #GlobalAzure #ViseoSpirit

… je peux essayer d’y répondre…

Vous avez des questions…


Top Related