Redis: indicizzazione delle sessioni
Ultimo post a tema #Redis: oggi vediamo come lavorare con Spring per indicizzare le sessioni sfruttando Redis OM!
Un’integrazione Redis ancora + mejo
L’integrazione con Redis offre un’annotazione chiamata @EnableRedisIndexedHttpSession
che, come suggerisce il nome, introduce la capacità di indicizzazione per le sessioni, che forse è proprio quello che stavamo cercando.
Quindi, questa annotazione dovrebbe essere aggiunta alla SessionConfig
precedentemente implementata, come mostrato di seguito:
@Configuration
@EnableRedisIndexedHttpSession
public class SessionConfig implements BeanClassLoaderAware {
private ClassLoader loader;
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new Jackson2JsonRedisSerializer(objectMapper(), Object.class);
}
private ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModules(SecurityJackson2Modules.getModules(this.loader));
return mapper;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.loader = classLoader;
}
}
Ancora una volta, pulisci lo store delle sessioni di Redis, avvia l’applicazione e procedi con il solito processo di login. I dati in Redis saranno visualizzati come segue:
Nel Redis session store sono stati aggiunti tre nuovi chiavi per migliorare la gestione delle sessioni e il monitoraggio delle scadenze:
spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:user
include il nome utente nella struttura della chiave, associandolo direttamente all’ID della sessione. Questo facilita l’identificazione delle sessioni degli utenti, rendendo semplice determinare a quali utenti appartengono le sessioni.spring:session:sessions:expires:92f8c84b-a7d5-48de-b269-42a2989b65d4
permette di monitorare quando le sessioni scadranno. Tracciando il momento di scadenza di ciascuna sessione, il sistema garantisce una gestione tempestiva delle sessioni e la pulizia delle risorse.spring:session:expirations:1708768500000
fornisce un timestamp che dettaglia il momento esatto in cui una sessione è destinata a scadere. Questo timing preciso consente una gestione efficiente delle scadenze delle sessioni, assicurando che le sessioni siano attive solo per il loro periodo di vita previsto.
Questi miglioramenti potenziano il sistema di gestione delle sessioni, offrendo un controllo più preciso sulla durata delle sessioni e lo stato di autenticazione degli utenti in un contesto distribuito. Facilitano l’identificazione degli utenti autenticati e delle sessioni a cui sono connessi, adattandosi a scenari in cui un utente potrebbe accedere al sistema da più dispositivi contemporaneamente.
Spesso, le applicazioni Stateful utilizzano le sessioni come contenitore per vari elementi di dati, come carrelli della spesa nelle piattaforme di e-commerce. Questa pratica non è ottimale perché sovraccarica i sistemi di gestione delle sessioni, che dovrebbero principalmente occuparsi di autenticazione e autorizzazione per migliorare le prestazioni. Inoltre, le sessioni hanno tempi di scadenza, e potrebbe essere necessario conservare alcuni dati, come il contenuto del carrello della spesa, in modo indipendente.
Sebbene i database tradizionali possano segregare e memorizzare tali dati, Redis offre un’alternativa efficiente date le sue elevate performance come soluzione di archiviazione persistente.
Considera il vantaggio di rilevare carrelli con un totale superiore a 1.000 dollari per offrire immediatamente uno sconto di 100 dollari o un coupon, a patto che il pagamento avvenga entro i prossimi 10 minuti.
Questa strategia può essere arricchita con analisi dettagliate, associando i carrelli alle sessioni degli utenti tramite l’uso di chiavi uniche e sfruttando i tipi di dati Redis come Hashes o JSON, per una gestione dati più efficiente e incisiva.
Queste strutture dati consentono l’indicizzazione, permettendo agli amministratori di esaminare efficacemente le sessioni, le attività degli utenti e il contenuto dei carrelli della spesa attraverso operazioni di filtraggio, ricerca e aggregazione.
All’interno dell’ecosistema Redis, emerge un framework noto come Redis OM, specificatamente progettato per permettere la modellazione degli oggetti di business, offrendo un approccio diretto per ottimizzare le operazioni con Redis.
Redis OM, acronimo di Redis Object Mapping, consiste in un insieme di librerie sviluppate per facilitare l’interazione con Redis attraverso il paradigma della programmazione orientata agli oggetti. La suite di Redis OM semplifica l’utilizzo di Redis attraverso l’astrazione dei comandi diretti in operazioni ad alto livello. È concepita per offrire un metodo di lavoro con Redis più intuitivo e accessibile, trasformando tasks complessi in procedure gestibili e dirette.
Consideriamo il seguente carrello della spesa modellato usando le direttive Redis OM:
@Document
public class Cart {
@Id
private String id;
@Indexed
@Searchable
private String userId;
@Indexed
private String sessionId;
@Indexed
private List<Product> products;
@Indexed
private double total;
private double discount;
@Indexed
private long totalProducts;
@Indexed
private long totalQuantity;
//Constructors, getters, setters...
}
L’annotazione @Document
segnala che si tratta di un oggetto JSON memorizzato in Redis. Usando @Indexed
, si specificano gli attributi da indicizzare;
Redis OM poi assegna automaticamente il tipo di indice appropriato, basandosi sul tipo dell’attributo.
Questo approccio è applicato anche all’oggetto annidato Product
, definito nel seguente modo:
public class Product {
@Id
private String id;
@Searchable
private String title;
@TextIndexed
private String description;
private String thumbnailUrl;
@Indexed
private double price;
@Indexed
private long quantity;
@Indexed
private double total;
//Constructors, getters, setters...
}
L’oggetto Product adotta automaticamente la struttura di Redis JSON, eliminando la necessità di definirla esplicitamente.
Utilizzando l’annotazione @TextIndexed
, si indica che l’attributo description
è di tipo testo, permettendo così una ricerca Full-Text.
Questo processo di modellazione dei dati porta alla generazione automatica del seguente indice in Redis:
FT.CREATE com.foogaro.dto.CartIdx
ON JSON
PREFIX 1 "com.foogaro.dto.Cart:"
LANGUAGE "english"
SCORE "1.0"
SCHEMA
"$.userId" AS userId TAG SEPARATOR "|" SORTABLE
"$.sessionId" AS sessionId TAG SEPARATOR "|" SORTABLE
"$.products[0:].title" AS products_title TEXT WEIGHT 1
"$.total" AS total NUMERIC
"$.totalProducts" AS totalProducts NUMERIC
"$.totalQuantity" AS totalQuantity NUMERIC
"$.id" AS id TAG SEPARATOR "|" SORTABLE
A questo punto, è necessario configurare le query da eseguire tramite interfaccia, come, per esempio, l’elenco di tutti i carrelli della spesa con un totale che supera un determinato valore.
Grazie a Redis OM, questo compito è estremamente semplice e richiede solo poche righe di codice:
public Iterable<Cart> findAllCartTotalGreaterThan(final double total) {
return entityStream
.of(Cart.class)
.filter(Cart$.TOTAL.ge(total))
.sorted(Cart$.TOTAL, SortedField.SortOrder.ASC)
.collect(Collectors.toList());
}
Questo metodo individua tutte le chiavi associate all’oggetto Cart il cui totale è maggiore o uguale (indicato come “ge”) al valore specificato, come illustrato di seguito;
Successivamente, nell’interfaccia utente, è possibile applicare facilmente lo sconto necessario per incentivare il cliente a procedere con il checkout del carrello e completare l’ordine.
Lato Redis è possibile verificare gli aggiornamenti utilizzando RedisInsight, come illustrato nella seguente schermata:
Questa strategia potenzia l’engagement degli utenti e le opportunità di vendita.
Questo è real-time analytics.
Questo è real-time online sales!
Per approfondire l’argomento, Luigi Fùgaro ha pubblicato insieme a Mirko Ortensi un manuale su Redis, chiamato “Redis Stack for Application Modernization: Build real-time multi-model applications at any scale with Redis”: scoprilo qui!