Upload
stephane-escandell
View
292
Download
0
Embed Size (px)
#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…