Installation pour connecter Spark avec H2O dans R

Author : Sébastien Rochette
Categories : modèles
Tags : H2O, Spark
Date :

Dans la Task Force ThinkR, nous adorons jouer avec H2O dans R. Leurs algorithmes pour le machine learning et l’intelligence artificielle sont vraiment puissants. Combiné avec Apache Spark via Sparkling Water, H2O permet d’avoir des procédures de traitement de données encore plus puissantes, que vous pouvez exécuter sur votre propre ordinateur portable.

Installer Spark et H2O pour qu’ils travaillent ensemble dans R

La documentation de H2O est très bien faite, mais vous pouvez rencontrer des problèmes de compatibilités de versions. Chez ThinkR, nous avons l’expertise pour l’installation de serveurs R. Dans cet article de blog, nous présentons comment initier une association entre Spark et H2O dans R. C’est une procédure pas-à-pas, montrant où le processus peut s’arrêter en cas d’erreurs. Ne soyez donc pas surpris si une partie du code ci-dessous mène à des erreurs ! De plus, certaines étapes sont répétées parce que vous devrez redémarrer votre session.

Problème rencontré

Il y a de nombreuses raisons pour lesquelles vous pourriez obtenir le message d’erreur suivant en utilisant {sparklyr} :

#> Error : org.apache.spark.SparkException: Job 1 cancelled because SparkContext was shut down...
...[cut](voir ci-dessous pour le message complet]

Une raison commune est un problème d’allocation de mémoire lors de l’utilisation de grands jeux de données. Cependant, vous pouvez également obtenir ce problème dès le début, sans aucun jeu de données chargé. Dans ce cas, il s’agit très probablement d’un problème de compatibilité des versions.
Vous trouverez sur github le tableau des compatibilités de versions : https://github.com/h2oai/rsparkling/blob/master/README.md. Nous allons voir ça plus en détail.

Installer les packages R

Allons-y ! Suivons le processus d’installation. D’abord, une installation toute simple avec les packages à jour sur le CRAN. La première fois ça installe aussi h2o en même temps que les packages.

install.packages(c("rsparkling", "sparklyr", "h2o"))

Ensuite, chargeons les packages.

# Libraries
library(rsparkling)
library(sparklyr)
library(h2o)
library(here)
library(glue)

Paramétrer l’allocation de mémoire

Comme je l’ai dit, c’est l’une des raisons pour lesquelles vous pouvz obtenir le fameux message d’erreur. Ce paramétrage de l’allocation de mémoire peut donc sauvegarder vos analyses. Selon la taille de vos données et des analyses que vous souhaitez effectuer, il se peut que vous ayez besoin d’allouer une quantité importante de mémoire à vos processus. Définissez ce qui suit en fonction de votre machine. Ici, j’exécute des modèles sur mon ordinateur portable avec (16G) de RAM.
Je définis également un dossier (« spark_dir ») dans lequel tous les modèles ajustés et les logs seront stockés, de façon à les retrouver facilement et à suivre ce qu’il se passe.

# Just in case you are already connected
spark_disconnect_all() # Be sure it is what you want
# Define a directory where to save model outputs and logs
spark_dir <- here("tmp/spark_dir/")
# Set driver and executor memory allocations **depending on your machine**
config <- spark_config()
config$`sparklyr.shell.driver-memory` <- "8G"
config$`sparklyr.shell.executor-memory` <- "8G"
config$spark.executor.memoryOverhead <- "4g"
config$`sparklyr.shell.driver-java-options` <-
  glue("-Djava.io.tmpdir={spark_dir}")

Première connexion à Spark

Pour installer et vous connecter à Apache Spark, vous allez utiliser spark_connect avec la configuration précédente.

# This may install one version of Spark the first time
sc <- spark_connect(master = "local", config = config)

Vous verrez probablement ce message :

#> * Using Spark: 2.2.1
#> Spark version 2.2 detected. Will call latest Sparkling Water version 2.2.12
#> Detected H2O version 3.16.0.2. Please install H2O version 3.18.0.2, which is compliant with the latest Sparkling Water version for Spark 2.2.* -> Sparkling Water version 2.2.12
#> To update your h2o R package, copy/paste the following commands and then restart your R session:
#>    detach("package:rsparkling", unload = TRUE)
#>    if ("package:h2o" %in% search()) { detach("package:h2o", unload = TRUE) }
#>    if (isNamespaceLoaded("h2o")){ unloadNamespace("h2o") }
#>    remove.packages("h2o")
#>    install.packages("h2o", type = "source", repos = "https://h2o-release.s3.amazonaws.com/h2o/rel-wolpert/2/R")

 

En fait, la version de H2O installée par défaut dans la bibliothèque R par {h2o} n’est pas totalement en accord avec la version requise par Sparkling Water. Du coup, vous devez faire ce qui est recommandé dans le message pour installer la bonne version de H2O.

Ici, vous devrez redémarrer votre session R (sans sauvegarder l’espace de travail bien sûr…. Ne jamais le faire….)

Erreur avec la version de Java

Si vous rencontrez le message d’erreur suivant:

Error in validate_java_version_line(master, version) : 
  Java 9 is currently unsupported in Spark distributions unless you manually install Hadoop 2.8 and manually configure Spark. Please consider uninstalling Java 9 and reinstalling Java 8. To override this failure set 'options(sparklyr.java9 = TRUE)'.

Vous devez installer ou ré-installer Java 8. Si comme moi, vous avez déjà plusieurs version de Java installée, vous pouvez définir le chemin de la version Java que vous souhaitez utiliser avec Sys.setenv(JAVA_HOME = "/path/to/java") :

# Pour Java8 sur Ubuntu 64bit
Sys.setenv(JAVA_HOME = "/usr/lib/jvm/java-8-openjdk-amd64")

Démarrer le cluster H2O

Vous avez redémarré votre session R. Chargeons de nouveau les packages et la configuration. Et démarrons Spark.

# Libraries
library(rsparkling)
library(sparklyr)
library(h2o)
library(here)
library(glue)
# Just in case you are already connected
spark_disconnect_all()
# Define a directory where to save model outputs and logs
spark_dir <- here("tmp/spark_dir/")
# Set driver and executor memory allocations **depending on your machine**
config <- spark_config()
config$`sparklyr.shell.driver-memory` <- "8G"
config$`sparklyr.shell.executor-memory` <- "8G"
config$spark.yarn.executor.memoryOverhead <- "4g"
config$`sparklyr.shell.driver-java-options` <-
  glue("-Djava.io.tmpdir={spark_dir}")
# Connect to Spark
sc <- spark_connect(master = "local", config = config)

Pas de message d’erreur !

#> * Using Spark: 2.2.1
#> Spark version 2.2 detected. Will call latest Sparkling Water version 2.2.12

If you work within Rstudio, you probably remarked that your “Connection Pane” shows your Spark connection. With no tables if you are not connected to an existing Spark session.
Now that we started connection to Spark, you may want to initiation H2O cluster. Let’s test for H2O and Spark connection.

Si vous travaillez dans Rstudio, vous avez probablement remarqué que votre « Panneau de connexion » (Connection pane) montre votre connexion Spark. Il n’y a pas de tables si vous n’êtes pas connecté à une session Spark existante.
Maintenant que nous avons démarré la connexion à Spark, vous allez vouloir initier le cluster H2O. Testons donc la connexion H2O et Spark.

# Create h2o cluster
h2o_context(sc)

Et là… Un nouveau message d’erreur…

#> Version mismatch! H2O is running version 3.18.0.7 but h2o-R package is version 3.18.0.2.
#> Install the matching h2o-R version from – http://h2o-release.s3.amazonaws.com/h2o/rel-wolpert/7/index.html

Qu’est-ce qu’on fait de celui-ci ? Si nous installons la version H2O recommandée, ce n’est pas la même que celle recommandée lorsque nous avons utilisé spark_connect. Alors laquelle choisir ?
Dans ce cas et à partir de maintenant, je vous recommande d’utiliser le paramètre strict_version_check = FALSE, parce qu’au final, on ne va pas trop s’inquiéter si  H2O n’est pas totalement la version utilisée pour compiler le paquet R {h2o}. Cela devrait de toutes façons fonctionner.
Créons le « contexte » h2o….

# Create context with Sparkling Water
h2o_context(sc, strict_version_check = FALSE)

… and finally start H2O clusters ! Choose the number of cores you allow it to use ((4) for me) as well as the maximum memory allocation. Yes, memory again, but this is H2O here, not spark. I have (16G) available, let me allow for “(14G)”.

…. et lançons enfin les clusters H2O ! Choisissez le nombre de cœurs que vous lui permettez d’utiliser ((4) pour moi) ainsi que l’allocation maximale de mémoire. Oui, encore de la mémoire, mais c’est H2O ici, pas spark. J’ai (16G) disponible, je vais fixer « (14G) » pour pouvoir faire encore quelques trucs à côté de R, si besoin.

# Start H2O clusters
h2o.init(ip = "localhost", nthreads = 4, max_mem_size = "14G",
         strict_version_check = FALSE)
#> Connection successful!

Youhou ! Ça marche ! Enfin… Ça devrait marcher. En effet, selon la version Spark que vous définissez, ce n’est pas toujours le cas. Et à ce stade, vous pouvez rencontrer le fameux message d’erreur :

#> Error : org.apache.spark.SparkException: Job 1 cancelled because SparkContext was shut down...

Définir la version Sparkling Water

Sur ma machine, ça fonctionnait avec les paramètres par défaut. Dans mon cas, Spark 2.2.1 est installé et fonctionne avec Sparkling Water 2.2.2.12.
Si vous avez installé tout ça il y a quelques mois, ou si vous travaillez avec différentes versions d’Apache Spark comme Spark 2.1, vous obtiendrez probablement le message d’erreur. Pour s’en débarrasser, il suffit de spécifier la version de Sparkling Water à utiliser. Et pour savoir ce qui fonctionne avec quoi, jetons un coup d’oeil au tableau de cette page : https://github.com/h2oai/rsparkling/blob/master/README.md
Vous pouvez voir les compatibilités entre les versions de Spark, Sparkling Water et H2O. Donc, pour être correct, voici ce que vous pouvez définir :

  • Trouver la version de Spark que vous voulez : spark_available_versions()
  • Installer la version Spark que vous voulez: spark_install(version = "2.2.1")
  • Fixez la version correcte de sparkling water : options(rsparkling.sparklingwater.version = "2.2.11")
  • Installer la version adéquate de H2O
# Install adequate h2o
detach("package:rsparkling", unload = TRUE)
if ("package:h2o" %in% search()) {
  detach("package:h2o", unload = TRUE)
}
if (isNamespaceLoaded("h2o")) {
  unloadNamespace("h2o")
}
remove.packages("h2o", lib = .libPaths()[1])
install.packages("h2o",
  type = "source",
  repos = "https://h2o-release.s3.amazonaws.com/h2o/rel-wolpert/5/R"
)
# **Restart your session**

Résumé : configurations complètes

Ci-dessous, vous trouverez le code complet que vous pouvez utiliser sur chaque projet de script R pour Spark + H2O = Sparkling Water que vous démarrez.
Mettez à jour les versions en fonction de cette page : https://github.com/h2oai/rsparkling/blob/master/README.md et adaptez les paramètres d’allocation de mémoire en fonction de votre machine.

Spark 2.3

Redémarrer votre session R avant tout.

[Mise à jour: 27-10-2018]

# Define Sparkling Water version for Spark 2.3
options(rsparkling.sparklingwater.version = "2.3.16")
# Load libraries
library(rsparkling)
library(sparklyr)
library(h2o)
library(here)
library(glue)
# Install spark (eventually with specific hadoop version)
spark_available_versions(show_hadoop = TRUE)
spark_install(version = "2.3.2", hadoop_version = "2.7")
# Set driver and executor memory allocations
spark_dir <- here("tmp/spark/")
config <- spark_config()
# config$spark.driver.memory <- "6G"
#config$spark.executor.memory <- "6G"
config$`sparklyr.shell.driver-memory` <- "6G"
config$`sparklyr.shell.executor-memory` <- "6G"
config$spark.yarn.executor.memoryOverhead <- "2g"
  glue("-Djava.io.tmpdir={spark_dir}")
needed <- FALSE
if (needed) {
    # Install adequate h2o
  detach("package:rsparkling", unload = TRUE)
  if ("package:h2o" %in% search()) {
    detach("package:h2o", unload = TRUE)
  }
  if (isNamespaceLoaded("h2o")) {
    unloadNamespace("h2o")
  }
  remove.packages("h2o", lib = .libPaths()[1])
  install.packages("h2o",
    type = "source",
    repos = "https://h2o-release.s3.amazonaws.com/h2o/rel-wright/10/R"
  )
  # **Restart your R session**
}
# Connect to spark version 2.3.2
sc <- spark_connect(
  master = "local", config = config, version = "2.3.2")
# Create Sparkling Water context
h2o_context(sc, strict_version_check = FALSE)
# Stop earlier h2o cluster if exists
h2o.shutdown() # Be sure it is what you want
# Create h2o cluster
h2o.init(ip = "localhost", nthreads = 4, max_mem_size = "12G",
         strict_version_check = FALSE)
# clean slate - just in case the cluster was already running
h2o.removeAll() # Be sure it is what you want

Spark 2.2

Redémarrer votre session R avant tout.

# Define Sparkling Water version for Spark 2.2
options(rsparkling.sparklingwater.version = "2.2.11")
# Load libraries
library(rsparkling)
library(sparklyr)
library(h2o)
library(here)
library(glue)
# Install spark (eventually with specific hadoop version)
spark_available_versions(show_hadoop = TRUE)
spark_install(version = "2.2.1", hadoop_version = "2.7")
# Set driver and executor memory allocations
spark_dir <- here("tmp/spark/")
config <- spark_config()
# config$spark.driver.memory <- "6G"
#config$spark.executor.memory <- "6G"
config$`sparklyr.shell.driver-memory` <- "6G"
config$`sparklyr.shell.executor-memory` <- "6G"
config$spark.yarn.executor.memoryOverhead <- "2g"
  glue("-Djava.io.tmpdir={spark_dir}")
needed <- FALSE
if (needed) {
    # Install adequate h2o
  detach("package:rsparkling", unload = TRUE)
  if ("package:h2o" %in% search()) {
    detach("package:h2o", unload = TRUE)
  }
  if (isNamespaceLoaded("h2o")) {
    unloadNamespace("h2o")
  }
  remove.packages("h2o", lib = .libPaths()[1])
  install.packages("h2o",
    type = "source",
    repos = "https://h2o-release.s3.amazonaws.com/h2o/rel-wolpert/5/R"
  )
  # **Restart your R session**
}
# Connect to spark version 2.2.1
sc <- spark_connect(
  master = "local", config = config, version = "2.2.1")
# Create Sparkling Water context
h2o_context(sc, strict_version_check = FALSE)
# Stop earlier h2o cluster if exists
h2o.shutdown() # Be sure it is what you want
# Create h2o cluster
h2o.init(ip = "localhost", nthreads = 4, max_mem_size = "12G",
         strict_version_check = FALSE)
# clean slate - just in case the cluster was already running
h2o.removeAll() # Be sure it is what you want

Spark 2.1

Redémarrer votre session R avant tout.

# Define sparkling water version for Spark 2.1
options(rsparkling.sparklingwater.version = "2.1.25")
# Libraries
library(rsparkling)
library(sparklyr)
library(h2o)
library(here)
library(glue)
# Install spark (eventually with specific hadoop version)
spark_available_versions(show_hadoop = TRUE)
spark_install(version = "2.1.1", hadoop_version = "2.7")
# Set driver and executor memory allocations
spark_dir <- here("tmp/spark/")
config <- spark_config()
# config$spark.driver.memory <- "6G"
#config$spark.executor.memory <- "6G"
config$`sparklyr.shell.driver-memory` <- "6G"
config$`sparklyr.shell.executor-memory` <- "6G"
config$spark.yarn.executor.memoryOverhead <- "2g"
  glue("-Djava.io.tmpdir={spark_dir}")
needed <- FALSE
if (needed) {
    # Install adequate h2o
  detach("package:rsparkling", unload = TRUE)
  if ("package:h2o" %in% search()) {
    detach("package:h2o", unload = TRUE)
  }
  if (isNamespaceLoaded("h2o")) {
    unloadNamespace("h2o")
  }
  remove.packages("h2o", lib = .libPaths()[1])
  install.packages("h2o",
    type = "source",
    repos = "https://h2o-release.s3.amazonaws.com/h2o/rel-wolpert/5/R"
  )
  # **Restart your R session**
}
# Connect to spark version 2.1.1
sc <- spark_connect(
  master = "local", config = config, version = "2.1.1")
# Create Sparkling Water context
h2o_context(sc, strict_version_check = FALSE)
# Stop earlier h2o cluster if exists
h2o.shutdown() # Be sure it is what you want
# Create h2o cluster
h2o.init(ip = "localhost", nthreads = 4, max_mem_size = "12G",
         strict_version_check = FALSE)
# clean slate - just in case the cluster was already running
h2o.removeAll() # Be sure it is what you want

Tester si ça marche

Si vous voulez tester si votre connexion entre Spark et H2O fonctionne correctement, rien de tel qu’un bon exemple reproductible. Nous utilisons l’exemple de machine learning du dépôt github {rsparkling}.

library(dplyr)
# Copy data to Spark (See it in Connection pane in Rstudio)
mtcars_tbl <- copy_to(sc, mtcars, overwrite = TRUE)
# In case nothing happens:
# mtcars_tbl <- sparklyr:::copy_to.spark_connection(sc, mtcars, overwrite = TRUE)
# Convert to Spark data to H2O
mtcars_hf <- as_h2o_frame(sc, mtcars_tbl)
# Define variables
y <- "mpg"
x <- setdiff(names(mtcars_hf), y)
# Split the mtcars H2O Frame into train & test sets
splits <- h2o.splitFrame(mtcars_hf, ratios = 0.7, seed = 1)
# Fit a gradient boost model
fit <- h2o.gbm(x = x,
               y = y,
               training_frame = splits[[1]],
               nfolds = 3,
               min_rows = 1,
               seed = 1))
print(fit)
#> Model Details:
#> ==============
#> H2ORegressionModel: gbm
#>   number_of_trees number_of_internal_trees model_size_in_bytes min_depth max_depth
#> 1              50                       50               14804         5         5
#>   mean_depth min_leaves max_leaves mean_leaves
#> 1    5.00000         17         21    18.64000
#> H2ORegressionMetrics: gbm
#> ** Reported on training data. **
#> MSE:  0.001211724
#> RMSE:  0.03480983
#> MAE:  0.02761402
#> RMSLE:  0.001929304
#> Mean Residual Deviance :  0.001211724

Message d’erreur complet

Ceci est le message d’erreur complet que vous pouvez rencontrer si Sparkling water n’a pas été configuré correctement ou si votre allocation de mémoire était trop faible pour les modèles que vous voulez faire fonctionner.


#> Erreur : org.apache.spark.SparkException: Job 1 cancelled because SparkContext was shut down
#>  at org.apache.spark.scheduler.DAGScheduler$$anonfun$cleanUpAfterSchedulerStop$1.apply(DAGScheduler.scala:808)
#>  at org.apache.spark.scheduler.DAGScheduler$$anonfun$cleanUpAfterSchedulerStop$1.apply(DAGScheduler.scala:806)
#>  at scala.collection.mutable.HashSet.foreach(HashSet.scala:78)
#>  at org.apache.spark.scheduler.DAGScheduler.cleanUpAfterSchedulerStop(DAGScheduler.scala:806)
#>  at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.onStop(DAGScheduler.scala:1668)
#>  at org.apache.spark.util.EventLoop.stop(EventLoop.scala:83)
#>  at org.apache.spark.scheduler.DAGScheduler.stop(DAGScheduler.scala:1587)
#>  at org.apache.spark.SparkContext$$anonfun$stop$8.apply$mcV$sp(SparkContext.scala:1833)
#>  at org.apache.spark.util.Utils$.tryLogNonFatalError(Utils.scala:1283)
#>  at org.apache.spark.SparkContext.stop(SparkContext.scala:1832)
#>  at org.apache.spark.SparkContext$$anonfun$2.apply$mcV$sp(SparkContext.scala:581)
#>  at org.apache.spark.util.SparkShutdownHook.run(ShutdownHookManager.scala:216)
#>  at org.apache.spark.util.SparkShutdownHookManager$$anonfun$runAll$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(ShutdownHookManager.scala:188)
#>  at org.apache.spark.util.SparkShutdownHookManager$$anonfun$runAll$1$$anonfun$apply$mcV$sp$1.apply(ShutdownHookManager.scala:188)
#>  at org.apache.spark.util.SparkShutdownHookManager$$anonfun$runAll$1$$anonfun$apply$mcV$sp$1.apply(ShutdownHookManager.scala:188)
#>  at org.apache.spark.util.Utils$.logUncaughtExceptions(Utils.scala:1951)
#>  at org.apache.spark.util.SparkShutdownHookManager$$anonfun$runAll$1.apply$mcV$sp(ShutdownHookManager.scala:188)
#>  at org.apache.spark.util.SparkShutdownHookManager$$anonfun$runAll$1.apply(ShutdownHookManager.scala:188)
#>  at org.apache.spark.util.SparkShutdownHookManager$$anonfun$runAll$1.apply(ShutdownHookManager.scala:188)
#>  at scala.util.Try$.apply(Try.scala:192)
#>  at org.apache.spark.util.SparkShutdownHookManager.runAll(ShutdownHookManager.scala:188)
#>  at org.apache.spark.util.SparkShutdownHookManager$$anon$2.run(ShutdownHookManager.scala:178)
#>  at org.apache.hadoop.util.ShutdownHookManager$1.run(ShutdownHookManager.java:54)
#>  at org.apache.spark.scheduler.DAGScheduler.runJob(DAGScheduler.scala:628)
#>  at org.apache.spark.SparkContext.runJob(SparkContext.scala:1925)
#>  at org.apache.spark.SparkContext.runJob(SparkContext.scala:1938)
#>  at org.apache.spark.SparkContext.runJob(SparkContext.scala:1951)
#>  at org.apache.spark.SparkContext.runJob(SparkContext.scala:1965)
#>  at org.apache.spark.rdd.RDD$$anonfun$collect$1.apply(RDD.scala:936)
#>  at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:151)
#>  at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:112)
#>  at org.apache.spark.rdd.RDD.withScope(RDD.scala:362)
#>  at org.apache.spark.rdd.RDD.collect(RDD.scala:935)
#>  at org.apache.spark.h2o.backends.internal.InternalBackendUtils$class.startH2O(InternalBackendUtils.scala:163)
#>  at org.apache.spark.h2o.backends.internal.InternalBackendUtils$.startH2O(InternalBackendUtils.scala:262)
#>  at org.apache.spark.h2o.backends.internal.InternalH2OBackend.init(InternalH2OBackend.scala:99)
#>  at org.apache.spark.h2o.H2OContext.init(H2OContext.scala:129)
#>  at org.apache.spark.h2o.H2OContext$.getOrCreate(H2OContext.scala:381)
#>  at org.apache.spark.h2o.H2OContext$.getOrCreate(H2OContext.scala:416)
#>  at org.apache.spark.h2o.H2OContext.getOrCreate(H2OContext.scala)
#>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
#>  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
#>  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
#>  at java.lang.reflect.Method.invoke(Method.java:498)
#>  at sparklyr.Invoke$.invoke(invoke.scala:102)
#>  at sparklyr.StreamHandler$.handleMethodCall(stream.scala:97)
#>  at sparklyr.StreamHandler$.read(stream.scala:62)
#>  at sparklyr.BackendHandler.channelRead0(handler.scala:52)
#>  at sparklyr.BackendHandler.channelRead0(handler.scala:14)
#>  at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
#>  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:367)
#>  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:353)
#>  at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:346)
#>  at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
#>  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:367)
#>  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:353)
#>  at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:346)
#>  at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
#>  at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
#>  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:367)
#>  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:353)
#>  at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:346)
#>  at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)
#>  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:367)
#>  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:353)
#>  at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)
#>  at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
#>  at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:652)
#>  at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:575)
#>  at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:489)
#>  at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:451)
#>  at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)
#>  at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
#>  at java.lang.Thread.run(Thread.java:748)

Comments


Also read