排查calibre-web服務阻塞問題


問題

k8s集群中使用linuxServer的linuxserver/docker-calibre-web鏡像部署了janeczku/calibre-web,在211011升級了最新的鏡像后,發現網頁頻繁出現無響應的狀況:瀏覽器標簽頁持續保持轉圈的狀態,直到很久以后才會報超時,且從此之后所有請求都無法正常完成。

經過多次嘗試,發現在前端復現該問題的操作方法是:編輯書籍,獲取元數據,點擊保存。

排查

  1. 首先直接用kubectl port-forward calibre-6c5c84fd4f-z2mgb 8083:12345代理方式訪問集群內calibre的pod,繞過集群中pod以外的其他網絡組件,比如traefik,排除集群本身問題。發現問題依舊,初步排除集群網絡問題。

  2. 此時需要看calibre-web日志:經過一番搜索研究,發現該項目的日志不會輸出到stdout,而是位於項目目錄里的calibre-web.log文件。相應的,在容器內的位置是/app/calibre-web/calibre-web.log

  3. 日志文件中看到很多重復的日志塊如下。初步懷疑是由於編輯書的元數據時請求了google scholar,但是由於返回了status code 403,而相關代碼在處理請求重試時邏輯有誤導致了無限重試,進一步導致阻塞了web server主線程。

    INFO {scholarly:116} Got an access denied error (403). [2021-10-13 10:10:29,801] INFO {scholarly:118} No other connections possible. [2021-10-13 10:10:29,801] INFO {scholarly:124} Will retry after 80.11549845444705 seconds (with another session). [2021-10-13 10:11:54,220] INFO {scholarly:105} Session proxy config is {} 
  4. 此時需要查看janeczku/calibre-web的代碼邏輯,相關代碼如下:如果pip安裝了scholarly庫,則會去請求google scholor,否則會跳過。而項目把一些額外的pip依賴放到了單獨的requirements文件optional-requirements.txt中。

    # Improve this to check if scholarly is available in a global way, like other pythonic libraries try: from scholarly import scholarly have_scholar = True except ImportError: have_scholar = False @editbook.route("/scholarsearch/<query>",methods=['GET']) @login_required_if_no_ano @edit_required def scholar_search(query): if have_scholar: scholar_gen = scholarly.search_pubs(' '.join(query.split('+'))) i=0 result = [] for publication in scholar_gen: del publication['source'] result.append(publication) i+=1 if(i>=10): break return Response(json.dumps(result),mimetype='application/json') else: return "[]" 
  5. 查看linuxserver/docker-calibre-web中的Dockerfile可以看到確實默認安裝optional-requirements.txt

本地復現

  1. 第一次在本地啟動calibre-web,僅安裝requirements.txt里的依賴,此時可以正常編輯書籍的元數據。

  2. pip install optional-requirements.txt后,再編輯書籍元數據,問題被復現。

  3. 本文問題的出現,和calibre web server側的代理情況密切相關,總結如下:

    1. 首先,顯然,不安裝scholarly,無論對google scholar的可達性如何都不會有問題
    2. 安裝啟用了scholarly后,如果訪問google scholar正常,也不會有問題
    3. 安裝啟用了scholarly后,如果訪問gogole scholar返回403,則會出現本文描述的問題。
    4. 安裝啟用了scholarly后,如果server在國內,且未有任何proxy的情況下,經過測試,scholarly在重試超過最大次數后會拋出MaxTriesExceededException異常,在異常拋出之前server也會被阻塞,但拋出異常后恢復正常。

溯源

安裝scholarly,該庫提供訪問google scholar的api。pip install scholarly

❯ pip show scholarly Name: scholarly Version: 1.2.2 

截取有問題的代碼片段如下,可以看到訪問google 得到403 status code時會導致循環無法跳出。

# scholarly/_navigator.py if resp.status_code == 200 and not has_captcha: return resp.text elif has_captcha: self.logger.info("Got a captcha request.") self._session = self.pm._handle_captcha2(pagerequest) continue # Retry request within same session elif resp.status_code == 403: self.logger.info(f"Got an access denied error (403).") if not self.pm.has_proxy(): self.logger.info("No other connections possible.") if not self.got_403: self.logger.info("Retrying immediately with another session.") else: if not self.pm._use_luminati: w = random.uniform(60, 2*60) self.logger.info("Will retry after {} seconds (with another session).".format(w)) time.sleep(w) self._new_session() self.got_403 = True continue # Retry request within same session else: self.logger.info("We can use another connection... let's try that.") else: self.logger.info(f"""Response code {resp.status_code}. Retrying...""") 

臨時解決

 

docker pull lwabish/calibre-web:china

較快速的解決方法是:fork linuxserver/docker-calibre-web,在其中的dockerfile中加入pip uninstall scholarly -y,取消google scholar支持。

新構建的鏡像已上傳至docker hub:lwabish/calibre-web - Docker Image | Docker Hub


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM