只有累積,沒有奇蹟

2019年2月26日 星期二

[.NET] StackExchange.Redis.RedisServerException : 'ERR Error compiling script'

問題 
這幾天在對新專案做 POC,開始對 Redis Server 新增資料做測試,有個 Test Case 在使用 Lua script 新增多筆資料到 Redis Server 時候發生錯誤,錯誤訊息為  "StackExchange.Redis.RedisServerException: 'ERR Error compiling script (new function): user_script:1: function or expression too complex near ''insert script'' ' " ,這篇就針對此案例作簡單紀錄與分享若是有不清楚或是錯誤的地方歡迎討論予糾正

解決方法 
首先先看一下案發現場的 code 如下
private static void InsertBy_LuaScript(IEnumerable<string> input)
{
    var insertValues = String.Join(",", input.Select(o => $"'{o}'"));
    string luaScript = $"redis.call('rpush', 'Luascript', {insertValues})";

    var prepared = LuaScript.Prepare(luaScript);
    RedisConnection.GetDatabase().ScriptEvaluate(prepared);    
} 
針對 function 所傳遞進來的集合做字串相加,最後在將所有相加後的字串當作 redis.call 的參數,舉例輸入集合為 test01、test02、test03,其變數 luaScript 結果 redis.call('rpush','Luascript','test01', 'test02', 'test03') ,最後將此 script 傳入 LuaScript.Prepare API 執行;此語法在測試數量少的時候正常,但後期逐漸地把測試筆數加到 300 筆時,就會產生執行失敗跳出下列錯誤訊息
經 debug 後發現異常時其 lua script 輸出如下
redis.call('rpush', 'Luascript', '0','1','2'...'299')
該 script 當遇到新增筆數量大時,就會變成參數過度擴增的狀況,有可能是因為 redis.call 支援不了這麼多參數,且用此段語法在 lua script online 進行測試也是 compiler error,因此心中判定此種寫法失格出局,改良後的寫法如下
private static void InsertBy_LuaScript(IEnumerable<string> input)
{    
    StringBuilder sb = new StringBuilder();
    foreach (var item in input)
    {
        sb.AppendLine($"redis.call('rpush', 'Luascript', {item})");
    }

    var prepared = LuaScript.Prepare(sb.ToString());
    RedisConnection.GetDatabase().ScriptEvaluate(prepared);
} 
使用 stringBuilder 將輸入集合內容匯總為字串,每筆輸出都單獨定義其 redis.call 其設定值參數,改完後測試筆數可超越原本的限制 300 筆,測試 10000 筆資料也沒問題,宣告結案打完收工 

心得
對於 lua script 不熟悉因此踩到這基本的雷,但轉個念頭想也是因為自己因為對於基本語法不熟悉,才會造成錯誤的使用,也提醒下次遇到類似情況時可以先搞清楚觀念,或許很多雷就不會在踩到

0 意見:

張貼留言

Copyright © m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com