Dovrebbe compilare Java come stringa in runtime o usare un linguaggio interpretato?

1

Diciamo che abbiamo un sistema di offerta (scritto in Java 8), che secondo alcuni algoritmi (strategia di offerta) e determinate condizioni, aumenteremmo o diminuiremo l'importo dell'offerta in un determinato momento. Abbiamo diversi algoritmi definiti, ma ora vorremmo che i nostri utenti definissero il proprio algoritmo.

L'utente può scegliere tra i nostri algoritmi quale desidera per la sua strategia di offerta.

L'idea è di lasciarli scrivere codice e quindi salvare questo algoritmo come una nuova opzione (tra tutti i nostri algoritmi) da utilizzare nella loro strategia di offerta.

Quindi, ho pensato in queste due opzioni:

  1. Permetti all'utente di scrivere il codice java, salvarlo nel DB e quando l'algoritmo deve essere eseguito, compila quel "String" (in fase di esecuzione) ed eseguilo.

  2. Permetti ai nostri utenti di scrivere in un linguaggio interpretato, salvarlo in DB e quando l'algoritmo richiede di essere eseguito, interpreta semplicemente ogni riga e pubblica il risultato in una coda che il nostro "motore" ascolta .

L'opzione 2 potrebbe non essere una buona idea, poiché potrebbero essere milioni di offerte per utente, quindi potrebbe esserci troppa latenza in questo approccio. Ma mi piacerebbe sapere se 1 e 2 sono un buon approccio o c'è un modo migliore per gestire questo requisito?

    
posta Josemy 26.04.2018 - 14:31
fonte

2 risposte

7

Questo è un problema difficile: come può essere eseguito in modo sicuro tale codice fornito dall'utente e come è possibile garantire una buona esperienza utente?

Se esegui il codice per conto di qualcun altro, non ti puoi fidare di quel codice . Il codice può tentare di manipolare le risorse di elaborazione (quindi incorrere in costi per te e negare risorse di calcolo ad altri offerenti), può tentare di hackerare il tuo sistema o il codice di altri offerenti o semplicemente utilizzare le risorse di calcolo fornite come parte di una botnet ... le possibilità di abuso sono infinite. Quindi è necessario sandbox questo codice molto strettamente. Il modello di sicurezza Java è un buon inizio e consente di negare la riflessione e altre API al codice non attendibile. Tuttavia, potresti comunque trovare difficoltà a limitare in modo affidabile le risorse di calcolo disponibili.

Il prossimo problema è l'esperienza dell'utente. Come possono gli utenti scrivere, eseguire il debug e testare il loro codice? Fornirai una sorta di IDE? Quali API offri a quel codice? Come è documentato? Esiste un ambiente di test in cui è possibile provare le strategie di offerta? Come raccoglierai e visualizzerai i messaggi di errore?

Se compili il codice Java , sei limitato dal modello di sicurezza Java. Questo può essere effettivamente sufficiente, supponendo che tu sia competente con quel modello di sicurezza (non lo sono) e puoi configurarlo in modo appropriato. Puoi facilmente memorizzare nella cache il codice compilato , in modo che non debba essere ricompilato per ogni esecuzione. Ci sono strumenti maturi su Java, quindi sarebbe semplice offrire un tipo di IDE.

Se utilizzi qualsiasi altra lingua basata su JVM come Groovy, valgono le stesse considerazioni. Alla fine, tutto andrà come bytecode JVM e sarà quindi ragionevolmente veloce.

Se integri un linguaggio di scripting non JVM (una lingua esistente come JavaScript o una DSL di tua progettazione), allora hai più controllo sul confine di sicurezza tra il tuo codice e il non sicuro codice utente Tuttavia, questo potrebbe essere un po 'più lento. In particolare, l'implementazione della propria DSL è solitamente piuttosto soggetta a errori e spesso lenta.

Se una sandbox in-process non è sufficiente per le proprie esigenze, considerare sandbox a livello di processo o di sistema operativo: containerizzazione e virtualizzazione. esegui il codice utente in un processo separato e comunichi tramite un socket. Questo non solo migliora la sicurezza, ma consente anche una maggiore scalabilità. Tuttavia, qualsiasi input / output deve essere serializzato, il che può limitare le prestazioni.

Invece di creare un DSL testuale, puoi anche progettare un motore di regole . Fondamentalmente, si forniscono blocchi configurabili che gli utenti possono combinare in una GUI. Questo è più accessibile ai non programmatori. Offrendo o non offrendo determinati blocchi (come loop, dichiarazioni di funzioni, ...) è possibile influenzare il costo dei programmi risultanti, pur offrendo una maggiore flessibilità rispetto a una serie di strategie preconfigurate. Mentre controlli tutti i blocchi disponibili, puoi anche creare un chiaro limite di sicurezza senza dover utilizzare complicate funzionalità di isolamento.

A meno che le tue offerte non siano state risolte in pochi secondi, esiste un'altra opzione: offrire un'API REST . In questo modo, non devi eseguire alcun codice non affidabile. Esistono strumenti molto maturi per la creazione di API. C'è un confine di sicurezza molto chiaro. Puoi facilmente limitare gli utenti in eccesso. Con un'API, gli utenti possono iscriversi a un feed di eventi e reagire inviando le loro azioni ai tuoi endpoint API. Sono quindi totalmente liberi nel modo in cui scrivono le loro strategie. Tuttavia, dovranno fornire le proprie risorse di calcolo. Se questa è un'alternativa valida dipende in gran parte dal tuo mercato: il tuo prodotto è destinato ai consumatori, oppure è B2B o per sviluppatori?

Tuttavia, qualunque sia la tua scelta, altre considerazioni come l'offerta di un ambiente di test utilizzabile possono essere molto più complicate rispetto alla semplice integrazione di un linguaggio di scripting o all'offerta di un'API.

Suggerirei di porsi e / o chiarire con le parti interessate:

  1. Che tipo di flessibilità è necessaria e quali sono le possibilità di abuso con quella flessibilità?
  2. È sufficiente un motore di regole per fornire la flessibilità necessaria?
  3. In caso contrario, un'API sarebbe appropriata?
  4. In caso contrario, quale linguaggio di programmazione / scripting sarebbe la migliore esperienza utente? Per esempio. Java, Groovy, JavaScript o un DSL personalizzato? Molti problemi di prestazioni possono essere risolti buttando soldi sul problema (usando più server), quindi le prestazioni non dovrebbero essere la tua prima considerazione qui.
risposta data 26.04.2018 - 15:21
fonte
0

Entrambe le opzioni sono perfettamente ragionevoli ma l'opzione 1 sarebbe complessivamente più efficiente per il tuo scenario.

La compilazione richiede un notevole overhead una tantum (dell'ordine di 0,1 sec), ma porta a un'esecuzione significativamente più veloce. Se stai eseguendo una strategia milioni di volte, la compilazione ti ripagherà a lungo termine. Assicurati solo di non compilare milioni di volte!

Potresti non voler compilare dopo aver estratto la stringa dal DB. È possibile compilare in anticipo e salvare invece il file .class nel DB. Ciò ti consentirà di iniziare a eseguire più rapidamente le prime offerte.

    
risposta data 26.04.2018 - 14:51
fonte

Leggi altre domande sui tag