2017-02-25 172 views
3

我有一個關於proguard與scala aws lambda函數一起使用的問題。我創建了一個非常簡單的AWS lambda表達式是這樣的:使用Proguard for Scala AWS Lambda

package example 

import scala.collection.JavaConverters._ 
import com.amazonaws.services.lambda.runtime.events.S3Event 
import com.amazonaws.services.lambda.runtime.Context 

object Main extends App { 

def kinesisEventHandler(event: S3Event, context: Context): Unit = { 
val result = event.getRecords.asScala.map(m => m.getS3.getObject.getKey) 
println(result) 
} 

} 

我已經導入以下軟件包:

"com.amazonaws" % "aws-lambda-java-core" % "1.1.0" 
"com.amazonaws" % "aws-lambda-java-events" % "1.3.0" 

當我創建一個胖罐子它的大小13 MB和工程就像預期的那樣AWS Lambda函數(僅用於測試輸出)。

13 MB是非常大的,所以我嘗試proguard縮小罐子,但它不工作,我總是遇到問題,兩天後,我沒有更多的想法如何解決這個問題。

這裏是我的ProGuard配置:

-injars "/Users/x/x/x/AWS_Lambda/target/scala-2.12/lambda-demo-assembly-1.0.jar" 
-libraryjars "/Users/x/x/x/AWS_Lambda/lib_managed/jars/org.scala-lang/scala-library/scala-library-2.12.1.jar" 
-libraryjars "/Users/x/x/x/AWS_Lambda/lib_managed/jars/com.amazonaws/aws-lambda-java-core/aws-lambda-java-core-1.1.0.jar" 
-libraryjars "/Library/Java/JavaVirtualMachines/jdk1.8.0_102.jdk/Contents/Home/jre/lib/rt.jar" 
-libraryjars "/Users/x/x/x/AWS_Lambda/lib_managed/jars/com.amazonaws/aws-java-sdk-s3/aws-java-sdk-s3-1.11.0.jar" 
-libraryjars "/Users/x/x/x/AWS_Lambda/lib_managed/jars/com.amazonaws/aws-lambda-java-events/aws-lambda-java-events-1.3.0.jar" 
-outjars "/Users/x/x/x/AWS_Lambda/target/scala-2.12/proguard/lambda-demo_2.12-1.0.jar" 
-dontoptimize 
-dontobfuscate 
-dontnote 
-dontwarn 

-keepattributes SourceFile,LineNumberTable 

# Preserve all annotations. 

-keepattributes *Annotation* 

# Preserve all public applications. 

-keepclasseswithmembers public class * { 
    public static void main(java.lang.String[]); 
} 

# Preserve some classes and class members that are accessed by means of 
# introspection. 

-keep class * implements org.xml.sax.EntityResolver 

-keepclassmembers class * { 
    ** MODULE$; 
} 

-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool { 
    long eventCount; 
    int workerCounts; 
    int runControl; 
    scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack; 
    scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack; 
} 

-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinWorkerThread { 
    int base; 
    int sp; 
    int runState; 
} 

-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinTask { 
    int status; 
} 

-keepclassmembernames class scala.concurrent.forkjoin.LinkedTransferQueue { 
    scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference head; 
    scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference tail; 
    scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference cleanMe; 
} 

# Preserve some classes and class members that are accessed by means of 
# introspection in the Scala compiler library, if it is processed as well. 

#-keep class * implements jline.Completor 
#-keep class * implements jline.Terminal 

#-keep class scala.tools.nsc.Global 

#-keepclasseswithmembers class * { 
# <init>(scala.tools.nsc.Global); 
#} 

#-keepclassmembers class * { 
# *** scala_repl_value(); 
# *** scala_repl_result(); 
#} 

# Preserve all native method names and the names of their classes. 

-keepclasseswithmembernames,includedescriptorclasses class * { 
    native <methods>; 
} 

# Preserve the special static methods that are required in all  enumeration 
# classes. 

-keepclassmembers,allowoptimization enum * { 
    public static **[] values(); 
    public static ** valueOf(java.lang.String); 
} 

# Explicitly preserve all serialization members. The Serializable interface 
# is only a marker interface, so it wouldn't save them. 
# You can comment this out if your application doesn't use serialization. 
# If your code contains serializable classes that have to be backward 
# compatible, please refer to the manual. 

-keepclassmembers class * implements java.io.Serializable { 
    static final long serialVersionUID; 
    static final java.io.ObjectStreamField[] serialPersistentFields; 
    private void writeObject(java.io.ObjectOutputStream); 
    private void readObject(java.io.ObjectInputStream); 
    java.lang.Object writeReplace(); 
    java.lang.Object readResolve(); 
} 

# Your application may contain more items that need to be preserved; 
# typically classes that are dynamically created using Class.forName: 

# -keep public class mypackage.MyClass 
# -keep public interface mypackage.MyInterface 
# -keep public class * implements mypackage.MyInterface 

-keep,includedescriptorclasses class example.** { *; } 

-keepclassmembers class * { 
    <init>(...); 
} 

當我運行此我的罐子很小(大約5 MB),但是當我啓動拉姆達我收到以下錯誤

"errorMessage": "java.lang.NoSuchMethodException: com.amazonaws.services.s3.event.S3EventNotification.parseJson(java.lang.String)", 
"errorType": "lambdainternal.util.ReflectUtil$ReflectException" 

我看了一下類和proguard刪除了這個函數。當我改變配置來保存這個文件時,我在另一個文件中遇到了另一個問題。

有人已經用scala AWS lambda函數使用了proguard,並且有一個很好的設置或知道這個問題嗎?有沒有其他很好的解決方案來縮小罐子尺寸?

最佳, Lothium

回答

0

老實說,13MB並不大。但是,儘管我確信這將被視爲對Scala開發人員的異端,但我在Java中創建了一個等效的方法,它有點超過7MB。我沒有嘗試使用Proguard - 它可能會進一步縮小。

這就是您正在使用的S3Event軟件包。如果你看看因爲這個軟件包而被包含在內的東西,它會帶來很多額外的東西 - SQS,SNS,Dynamo等等。最終這是最大的部分。我做了一些測試,試圖消除除aws-lambda-java-core之外的所有庫,而改爲使用JsonPath。這讓我的jar文件到458 K

我的代碼如下。我知道這不是斯卡拉,但也許你可以從中得到一些想法。關鍵是儘可能多地消除AWS庫。當然,如果您想要在Lambda中執行除打印鍵以外的任何操作,則需要引入更多的AWS庫,這些庫的大小仍爲7MB左右。

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.util.List; 

import com.amazonaws.services.lambda.runtime.Context; 
import com.amazonaws.services.lambda.runtime.RequestStreamHandler; 
import com.jayway.jsonpath.JsonPath; 


public class S3EventLambdaHandler implements RequestStreamHandler { 
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) { 

     try { 
      List<String> keys = JsonPath.read(inputStream, "$.Records[*].s3.object.key"); 

      for(String nextKey: keys) 
       System.out.println(nextKey); 
     } 
     catch(IOException ioe) { 
      context.getLogger().log("caught IOException reading input stream"); 
     } 
    } 
} 
+0

嘿,謝謝你的迴應! 5MB開銷可以用scala庫解釋。我已經從aws的事件包中排除了一些不需要的庫,並將大小降至7MB,這是朝正確方向邁出的第一步。謝謝你的幫助! – Lothium