Skip to content
Snippets Groups Projects
Verified Commit b7c9aaaa authored by Julien Wittouck's avatar Julien Wittouck
Browse files

:sparkles: : add ha courses

parent 1eb110ae
No related branches found
No related tags found
No related merge requests found
Pipeline #52970 passed
Showing
with 483 additions and 1 deletion
...@@ -353,7 +353,7 @@ ...@@ -353,7 +353,7 @@
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text" class="index-last-update">Last updated Wed. 06 Nov</div> <div id="footer-text" class="index-last-update">Last updated Fri. 08 Nov</div>
</div> </div>
<script <script
......
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>ALOM - Asynchronism</title>
<meta name="description" content="ALOM - Asynchronism">
<meta name="author" content="Julien WITTOUCK <julien@codeka.io>">
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="../reveal/dist/reveal.css">
<link rel="stylesheet" href="../reveal/dist/theme/white.css" id="theme">
<link rel="stylesheet" href="../css/miage-lille.css"/>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css"
integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h1>ALOM</h1>
<h2>⏰ Asynchronism</h2>
</section>
<section>
<h2>Problématiques : </h2>
<p>Exécuter des traitements longs sans bloquer l'utilisateur ⏱</p>
<p>Exécuter des traitements parallèlement plutôt que séquentiellement</p>
<ul>
<li>Envois de mails ✉️</li>
<li>Impression de documents 🖨</li>
</ul>
<p>Ne pas bloquer l'utilisateur si l'imprimante n'a plus de papier !</p>
</section>
<section>
<h2>The cost of I/O : </h2>
<img src="images/cost_of_io.png"/>
</section>
<section>
<h2>The cost of I/O : </h2>
<table>
<thead>
<th>Action</th>
<th>Latency</th>
<th># of cycles</th>
<th>Human Time</th>
</thead>
<tbody>
<tr>
<td>1 Cycle CPU (3GHz Clock)</td>
<td>0.3 ns</td>
<td>1</td>
<td>1 s</td>
</tr>
<tr>
<td>Level 1 cache access</td>
<td>0.9 ns</td>
<td>3</td>
<td>3 s</td>
</tr>
<tr>
<td>Level 2 cache access</td>
<td>2.8 ns</td>
<td>9</td>
<td>9 s</td>
</tr>
<tr>
<td>Level 3 cache access</td>
<td>12.9 ns</td>
<td>43</td>
<td>43 s</td>
</tr>
</tbody>
</table>
</section>
<section>
<h2>The cost of I/O : </h2>
<table>
<thead>
<th>Action</th>
<th>Latency</th>
<th># of cycles</th>
<th>Human Time</th>
</thead>
<tbody>
<tr>
<td>RAM access</td>
<td>70 - 100 ns</td>
<td>233 - 333</td>
<td>3.5 - 5.5 m</td>
</tr>
<tr>
<td>NVMe SSD</td>
<td>7 - 150 µs</td>
<td>23k - 500k</td>
<td>6.5 h - 5.5 d</td>
</tr>
<tr>
<td>Rotational disk</td>
<td>1 - 10 ms</td>
<td>3 - 30 M</td>
<td>1 - 10 months</td>
</tr>
<tr>
<td>Internet: SF to NYC</td>
<td>40 ms</td>
<td>130 M</td>
<td>4.2 years</td>
</tr>
</tbody>
</table>
</section>
<section>
<h2>Concurrence</h2>
<img src="images/fry.png"/>
<p>Comment exécuter plusieurs choses en même temps ?</p>
</section>
<section>
<h2>Le CPU <i class="fas fa-microchip"></i></h2>
<p>Un CPU exécute un seul process à la fois</p>
<p>Le système d'exploitation switche entre les process pour leur donner le CPU</p>
</section>
<section>
<h2>Les CPUs multi-coeurs <i class="fas fa-microchip"></i><i class="fas fa-microchip"></i><i
class="fas fa-microchip"></i><i class="fas fa-microchip"></i></h2>
<p>Exécution de plusieurs process en parallèle</p>
<p>Comment exécuter des choses en parallèle dans un même process ?</p>
</section>
<section>
<h2>Multithreading</h2>
<p>Permet l'exécution de plusieurs tâches (threads) dans un même programme</p>
<p>Les threads se partagent la mémoire du process<i class="fas fa-microchip"></i></p>
</section>
<section>
<h2>En Java ☕</h2>
<p>Un des premiers langages à rendre le multithreading "facile" pour les développeurs</p>
<p>La gestion du multithreading se fait à l'aide des classes <code>java.util.concurrent.*</code></p>
</section>
<section>
<h2>Tomcat 😺 (rappel)</h2>
<ul>
<li>instancie un <code>Thread</code> java par connexion HTTP</li>
<li>voyez par vous-même dans votre code:
<code>System.out.println(Thread.currentThread().getName());</code></li>
<li>les <code>Threads</code> sont maintenus en vie dans un <code>pool</code></li>
<li>le nombre de thread est paramétrable pour booster 🚀 Tomcat (200 par défaut)</li>
<li>si pas de thread dispo, les requêtes sont 'mises en attente'</li>
</ul>
</section>
<section>
<h2><img src="images/spring-by-pivotal.png" style="height: 1.5em; vertical-align: middle;"/></h2>
<ul>
<li>Les beans Spring sont des singletons par défaut!</li>
<li>La mémoire entre les threads est partagée!</li>
<li>Ne pas utiliser d'attributs de classe dans un bean spring : les valeurs seraient partagées entre
tous les threads/requêtes HTTP !
</li>
</ul>
</section>
<section>
<h3>Instancier des threads</h3>
<p>implémenter l'interface Runnable...</p>
<img src="carbon/runnable.png"/>
</section>
<section>
<h3>Instancier des threads</h3>
<p>... en java 8 avec une lambda</p>
<img src="carbon/new-thread.png"/>
<p>⚠️ à bien utiliser la méthode <code>start</code></p>
<p>la méthode <code>run</code> exécuterait le code donné dans le thread "courant"</p>
</section>
<section>
<img src="images/fry.png"/>
<p>Comment récupérer un résultat ?</p>
</section>
<section>
<h3><a href="https://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Future.html">Future</a>,
<a href="https://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Callable.html">Callable</a>
et <a href="https://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorService.html">ExecutorService</a>
</h3>
<p>depuis Java ☕ 5 ! (si, si !)</p>
<ul>
<li><code>Future&lt;T&gt;</code> représente un résultat asynchrone</li>
<li><code>Callable&lt;T&gt;</code> représente une tâche retournant un résultat</li>
<li><code>ExecutorService</code> gère l'exécution de tâches asynchones <code>Runnable</code> ou <code>Callable&lt;T&gt;</code>
</li>
</ul>
</section>
<section>
<h3>ExecutorService</h3>
<p>Exécution d'un <code>Callable</code></p>
<img src="carbon/executor-service.png"/>
</section>
<section>
<h3>ExecutorService</h3>
<p>Exécution de plusieurs <code>Callable</code></p>
<img src="carbon/multi-callables.png"/>
</section>
<section>
<h3><a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html">CompletableFuture</a>
</h3>
<p>depuis Java ☕ 8</p>
<ul>
<li><code>CompletableFuture&lt;T&gt;</code> est une Future</li>
<li>Propose des méthodes de chaînage (proche des Promesses en ECMAScript)</li>
<li>Propose des méthodes <code>static</code> pour exécuter des
<code>Runnable</code>/<code>Callable</code> sans <code>ExecutorService</code></li>
</ul>
</section>
<section>
<h3>CompletableFuture</h3>
<img src="carbon/completable-future.png"/>
</section>
<section>
<h3>CompletableFuture & Streams</h3>
<p>Gérer le chargement asynchrone d'une liste</p>
</section>
<section>
<h3>CompletableFuture</h3>
<p>Taille du pool de threads par défaut : Nb CPU - 1</p>
<p>Permet de laisser un CPU disponible au Thread principal et à l'OS</p>
<p>Si un seul CPU dispo, pas de pool de Thread, un Thread sera créé pour chaque tâche</p>
<p>Attention au contexte d'exécution (docker) et à ce pool partagé</p>
</section>
<section>
<h3>Avec les streams Java 8</h3>
<p>Possibilité d'exécuter des streams Java en parallèle - Proche de l'asynchronisme</p>
<p>En séquentiel :</p>
<img src="carbon/stream-simple.png"/>
</section>
<section>
<h3>Avec les streams Java 8</h3>
<p>En synchrone, chaque opération se fait dans le thread principal</p>
<img src="carbon/stream-simple-logs.png"/>
</section>
<section>
<h3>Avec les streams Java 8</h3>
<p>En parallèle</p>
<img src="carbon/stream-parallel.png"/>
</section>
<section>
<h3>Avec les streams Java 8</h3>
<p>En parallèle, chaque opération se fait dans le pool de thread. Le thread principal assure lui aussi sa
part du travail</p>
<img src="carbon/stream-parallel-logs.png"/>
</section>
<section>
<h3>Quel intéret pour nous?</h3>
<img src="images/fry.png"/>
<p>Je n'ai pas besoin de Threads, Tomcat 😺 est déjà multithreadé</p>
</section>
<section>
<h3>Quel intéret pour nous?</h3>
<p>Tomcat alloue un thread pour chaque requête entrante. Nous avons besoin de threads supplémentaires pour
:</p>
<ul>
<li>Composition d'appels d'API</li>
<li>Exécution de tâches longues</li>
<li>Parallélisme au lieu de séquencement</li>
</ul>
</section>
<section>
<img src="images/api-calls-seq.png"/>
</section>
<section>
<img src="images/api-calls-async.png"/>
</section>
<section>
<h2>Gain de temps de traitement global !</h2>
<img src="images/gatsby.png"/>
</section>
<section data-markdown>
<textarea data-template>
# Spring Async
Exécution de tâches asynchrones avec l'annotation `@Async`
```java
@Configuration
@EnableAsync
public class AsyncConfig {
}
```
```java
@Async
void doSomething() {
// this will be run asynchronously
}
@Async
Future<PokemonType> doSomethingThatReturns(int i) {
// this will be run asynchronously
}
```
---
# Spring Async
Configuration du pool de threads
```properties
spring.task.execution.pool.max-size=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s
---
# Scheduling
Déclencher des tâches en fonction d'expressions crontab, ou d'un délai.
```java
@Configuration
@EnableScheduling
public class SchedulingConfig {
}
```
```java
@Scheduled(cron="*/5 * * * * MON-FRI")
void doSomethingOnWeekDays() {
// something that should run on weekdays only
}
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS)
public void doSomethingEveryFiveSeconds() {
// something that should run periodically
}
```
</textarea>
</section>
<section style="text-align:left;">
<h1>Fin du cours</h1>
<p>Cours suivant : <br/>
<a href="../w08-high-availability/08-high-availability.html">High-Availability & micro-services
patterns</a>
</p>
</section>
</div>
</div>
<script src="../reveal/dist/reveal.js"></script>
<script src="../reveal/plugin/markdown/markdown.js"></script>
<link rel="stylesheet" href="../reveal/plugin/highlight/zenburn.css">
<script src="../reveal/plugin/highlight/highlight.js"></script>
<script>
// More info about initialization & config:
// - https://revealjs.com/initialization/
// - https://revealjs.com/config/
Reveal.initialize({
hash: true,
// Learn about plugins: https://revealjs.com/plugins/
plugins: [RevealMarkdown, RevealHighlight],
markdown: {
smartypants: true
}
});
</script>
<aside class="miage_aside_logo"></aside>
</body>
</html>
File added
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
new Thread(() -> {
System.out.println("Hello from thread " + Thread.currentThread().getName());
}).start();
// création d'un executorService
ExecutorService executorService = Executors.newFixedThreadPool(2);
// exécution d'une tâche dans un thread dédié avec récupération future d'un résultat
Future<String> futureResult = executorService.submit(() -> {return "test";});
// attente de la fin de la tâche (attente blocante dans le thread "main")
String result = futureResult.get();
System.out.println(result);
ExecutorService executorService = Executors.newFixedThreadPool(2);
// création de callables
Callable<String> a = () -> "a";
Callable<String> b = () -> "b";
Callable<String> c = () -> "c";
// exécution (cet appel est bloquant jusqu'a la fin des 3 callable!)
List<Future<String>> futures = executorService.invokeAll(Arrays.asList(a, b, c));
for(Future<String> future : futures){
System.out.println(future.get());
}
// avec un runnable
CompletableFuture.runAsync(() -> System.out.println("Hello from Thread" + Thread.currentThread().getName()));
// pour récupérer un résultat (avec un Supplier)
CompletableFuture<String> futureString = CompletableFuture.supplyAsync(() -> "Hello from Thread" + Thread.currentThread().getName());
System.out.println(futureString.get());
// pour lister la taille du pool par défaut
System.out.println(ForkJoinPool.getCommonPoolParallelism());
\ No newline at end of file
w08-asynchronism/carbon/completable-future.png

78.5 KiB

w08-asynchronism/carbon/executor-service.png

63.4 KiB

w08-asynchronism/carbon/multi-callables.png

77.2 KiB

w08-asynchronism/carbon/new-thread.png

30.1 KiB

w08-asynchronism/carbon/runnable.png

25.6 KiB

w08-asynchronism/carbon/stream-parallel-logs.png

174 KiB

2019-03-01 08:45:56 --- [commonPool-worker-3] RestTemplate : HTTP GET http://localhost:8080/pokemon-types/3
2019-03-01 08:45:56 --- [ main] RestTemplate : HTTP GET http://localhost:8080/pokemon-types/2
2019-03-01 08:45:56 --- [commonPool-worker-5] RestTemplate : HTTP GET http://localhost:8080/pokemon-types/1
2019-03-01 08:45:56 --- [ main] RestTemplate : Accept=[application/json, application/*+json]
2019-03-01 08:45:56 --- [commonPool-worker-5] RestTemplate : Accept=[application/json, application/*+json]
2019-03-01 08:45:56 --- [commonPool-worker-3] RestTemplate : Accept=[application/json, application/*+json]
2019-03-01 08:45:56 --- [commonPool-worker-5] RestTemplate : Response 200 OK
2019-03-01 08:45:56 --- [ main] RestTemplate : Response 200 OK
2019-03-01 08:45:56 --- [commonPool-worker-3] RestTemplate : Response 200 OK
2019-03-01 08:45:56 --- [commonPool-worker-5] RestTemplate : Reading to [PokemonType]
2019-03-01 08:45:56 --- [ main] RestTemplate : Reading to [PokemonType]
2019-03-01 08:45:56 --- [commonPool-worker-3] RestTemplate : Reading to [PokemonType]
w08-asynchronism/carbon/stream-parallel.png

36.4 KiB

w08-asynchronism/carbon/stream-simple-logs.png

162 KiB

2019-03-01 08:43:31 --- [main] RestTemplate : HTTP GET http://localhost:8080/pokemon-types/1
2019-03-01 08:43:31 --- [main] RestTemplate : Accept=[application/json, application/*+json]
2019-03-01 08:43:31 --- [main] RestTemplate : Response 200 OK
2019-03-01 08:43:31 --- [main] RestTemplate : Reading to [com.miage.alom.tp.pokemon_ui.pokemonTypes.bo.PokemonType]
2019-03-01 08:43:32 --- [main] RestTemplate : HTTP GET http://localhost:8080/pokemon-types/2
2019-03-01 08:43:32 --- [main] RestTemplate : Accept=[application/json, application/*+json]
2019-03-01 08:43:32 --- [main] RestTemplate : Response 200 OK
2019-03-01 08:43:32 --- [main] RestTemplate : Reading to [com.miage.alom.tp.pokemon_ui.pokemonTypes.bo.PokemonType]
2019-03-01 08:43:33 --- [main] RestTemplate : HTTP GET http://localhost:8080/pokemon-types/3
2019-03-01 08:43:33 --- [main] RestTemplate : Accept=[application/json, application/*+json]
2019-03-01 08:43:33 --- [main] RestTemplate : Response 200 OK
2019-03-01 08:43:33 --- [main] RestTemplate : Reading to [com.miage.alom.tp.pokemon_ui.pokemonTypes.bo.PokemonType]
\ No newline at end of file
w08-asynchronism/carbon/stream-simple.png

35.3 KiB

w08-asynchronism/images/Microservice-Architecture-Of-UBER.png

55.5 KiB

w08-asynchronism/images/api-calls-async.png

29.5 KiB

w08-asynchronism/images/api-calls-seq.png

29.3 KiB

w08-asynchronism/images/arbo.png

7.52 KiB

w08-asynchronism/images/archi.png

49.5 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment