2017-08-20 4 views
2

Modifier: Le problème semble être avec l'acccpeting SSL et une fuite de mémoire.Erlang SSL TCP serveur et Garbage Collection

J'ai remarqué si vous avez longtemps vécu processus (son serveur), et les clients d'envoyer des données au serveur (RECV), la collecte des ordures Erlang ne sera jamais appelé (ou rarement)

serveurs ont besoin de données (à actions de préforme), et les données peuvent être de longueur variable (en raison d'un message comme "Bonjour" ou "Comment allez-vous"). Pour cette raison, il semble que le processus Erlang va accumuler des ordures.

Comment pouvez-vous gérer correctement cela, le processus Erlang doit toucher les données de recv, est-ce inévitable? Ou devez-vous proposer des conceptions qui touchent les données de longueur variable le moins de fois possible (par exemple, en les transmettant immédiatement à un pilote de port)?

Faire apparaître un travailleur pour traiter les données est une mauvaise solution (des millions de connexions ...), et l'utilisation des travailleurs serait fondamentalement la même chose, n'est-ce pas? Cela me laisse donc très peu d'options.

Merci ...

+1

Vous avez besoin de plus de détails sur Erlang GC, je vous recommande de lire https://hamidreza-s.github.io/erlang%20garbage%20collection%20memory%20layout%20soft%20realtime/2015/08/24/ erlang-garbage-collection-détails-et-pourquoi-ça-questions.html – Pouriya

Répondre

0

Juste au cas où quelqu'un se retrouve dans le même bateau. Cela est connu/se passe lorsque vous martelez le serveur avec de nombreuses connexions à la fois. Je pense. Sans ssl, mes sessions sont à peu près ~ 8KB, et les ressources sont déclenchées comme prévu pour GC. Avec SSL, c'est une augmentation de ~ 150 Ko, et la mémoire ne cesse de croître et de croître.

http://erlang.org/pipermail/erlang-questions/2017-August/093037.html

+0

Vous pourriez essayer de forcer le GC en appelant erlang: garbage_collect/0/1/2; voir http://erlang.org/doc/man/erlang.html#garbage_collect-0. Si GC: ing après chaque requête fonctionne, essayez de le réduire à chaque nième requête et de trouver une bonne valeur pour n. – RichardC

+0

Je ne sais pas si cela résout le problème ou non, mais même avec tous ces correctifs utilisant SSL augmente le processus utilisateur de 142 + Ko (et c'est sans logique, juste un ssl: recv). C'est inacceptable. La solution de mon côté consistera simplement à fournir des identifiants de connexion SRP et à activer un certain type de chiffrement (peut-être AES) pour les données. – Mike5050

3

Si le serveur détient sur le message reçu plus que nécessaire, il y a un bogue dans l'implémentation du serveur. Normalement, le serveur devrait oublier toutes ou la plupart des références aux données dans une requête lorsque cette requête a fini de traiter, et les données deviendront alors corrompues et seront finalement collectées. Mais si vous collez les données de chaque requête dans une liste dans l'état du processus, ou dans une table ets ou similaire, vous obtiendrez une fuite de mémoire. Il y a un peu d'exception avec les binaires supérieurs à 64 octets, car ils sont gérés par le comptage des références, et pour l'allocateur de mémoire, il peut sembler qu'il n'y ait pas encore besoin d'effectuer une collecte, bien que le nombre d'octets utilisés Off-tas par de tels binaires peut être assez grand.

0

Vous pourriez avoir un problème avec de grandes tables de session SSL/TLS. Nous (équipe OTP) avons historiquement eu quelques problèmes avec ces tables car elles peuvent devenir très importantes si vous n'avez pas de mécanismes limitatifs. Hélas, dans la dernière version SSL, l'un des mécanismes de limitation a été brisé, mais il est facilement réparé par ce patch. Comme une solution de contournement, vous pouvez également sacrifier une certaine efficacité et désactiver la réutilisation de session.

diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl 
index ca9aaf4..ef7c3de 100644 
--- a/lib/ssl/src/ssl_manager.erl 
+++ b/lib/ssl/src/ssl_manager.erl 
@@ -563,7 +563,7 @@ server_register_session(Port, Session, #state{session_cache_server_max = Max, 

do_register_session(Key, Session, Max, Pid, Cache, CacheCb) -> 
    try CacheCb:size(Cache) of 
- Max -> 
+ Size when Size >= Max -> 
    invalidate_session_cache(Pid, CacheCb, Cache); 
_ ->  
    CacheCb:update(Cache, Key, Session),