<input id="ohw05"></input>
  • <table id="ohw05"><menu id="ohw05"></menu></table>
  • <var id="ohw05"></var>
  • <code id="ohw05"><cite id="ohw05"></cite></code>
    <label id="ohw05"></label>
    <var id="ohw05"></var>
  • 項目完成 - 基于Django3.x版本 - 開發部署小結

    前言

    最近因為政企部門的工作失誤,導致我們的項目差點掛掉,客戶意見很大,然后我們只能被動進入007加班狀態,忙得嗷嗷叫,直到今天才勉強把項目改完交付,是時候寫一個小結。

    技術

    因為前期需求不明確,數據量不大,人手也不多,所以我直接用Django做了后端,Django自帶的admin可以作為管理后臺使用,可以很快完成這個需求。

    我們的前端有兩個,一個數據展示大屏,一個可視化地圖。前者使用Vue+ElementUI+DataV實現,后者使用jQuery+百度MapV。

    大概的效果如下所示,涉及到數據的部分只能打碼,感謝理解~

    這個是Django的admin界面,主頁是我重新寫的

    image

    數據展示大屏

    image

    可視化地圖

    image

    技術含量其實不高,但項目在具體實施和落地的過程中,有一些問題和細節,還是有必要記錄一下

    切換MySQL數據庫

    開發的時候默認用的SQLite數據庫,到了正式環境,需要切換到CS架構的服務器,比如MySQL

    我的配置是這樣

    # 數據庫配置
    database_config = {
        'sqlite3': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        },
        'mysql': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'name',
            'USER': 'root',
            'PASSWORD': 'password',
            'HOST': 'mysql' if DOCKER else 'localhost',
            'PORT': '3306',
        }
    }
    DATABASES = {'default': database_config['sqlite3']}
    

    這樣方便切換不同的數據庫,其實還可以把數據庫切換用環境變量來控制,docker中使用MySQL,本地開發環境使用sqlite。

    MySQL的HOST配置是:'mysql' if DOCKER else 'localhost' 也是為了適配本地環境和docker環境的切換,后續我再封裝一下 DjangoStarter 的數據庫配置部分,實現前面說的環境變量切換配置。

    大量數據導入問題

    本項目遇到的第一個麻煩的問題是大量的數據導入

    客戶提供的數據是Excel格式,大概幾百萬條吧,我首先使用Python對數據進行預處理,做了一些去重、數據清洗之類的操作,然后導出成JSON文件。

    然后在導入Django數據庫的時候就遇到了問題,DjangoORM的速度太慢了!

    讓他跑數據跑了一個晚上,才導入了80w條數據左右,這肯定不行啊,因為被業務部門捅了婁子,項目還有幾天的時間就要上線了,要趕!總共數據有幾百萬呢……

    沒辦法,只能直接上SQL了,掏出Navicat,連上服務器的MySQL數據庫,然后把數據直接導入臨時表,再用SQL一番折騰,導入到Django生成的表里,這樣數據的問題就搞定了。

    (當然后續還有一系列的數據問題,前期的數據清洗還是不夠的,后面發現的一些數據缺失啥的問題,在趕進度的過程中邊處理,做了一些補救措施,最后也還好勉強可以用)

    下次數據清洗還是得試一下Pandas這種專業的工具,單靠Python本身不夠。

    接口緩存

    由于數據量太大,有幾個需要計算操作的接口是比較慢的,該優化的暫時都優化了(下面或許會寫一下DjangoORM的優化),所以只能上緩存了

    項目用了我的「DjangoStarter」項目模板,本身集成了Redis支持,所以緩存直接用Redis的就好了。

    緩存有兩種使用方式,用Django默認的cache_page裝飾器,或者第三方庫rest_framework_extensions

    前者作用于 function view 上,當然 class view 也能用,但是得加 method_decorator,然后得自己封裝一個緩存過期配置。

    后者可以使用 rest_framework 的緩存配置,相對來說更方便,只是需要安裝一個庫。(另外提一點,rest_framework_extensions這個庫還有其他的一些功能,有空再介紹,感興趣的同學可以探索一下)

    最終我選擇了第二個,哈哈~

    不過我都介紹一下吧,很簡單

    cache_page 的使用

    from django.views.decorators.cache import cache_page
    from rest_framework.decorators import api_view
    
    @cache_page(CACHE_TIMEOUT)
    @api_view()
    def overview(request: Request):
    	...
    

    其中 CACHE_TIMEOUT 的單位是秒,也可以設置成 None,這樣緩存就永不過期了。

    rest_framework_extensions

    rest_framework 的緩存配置

    REST_FRAMEWORK = {
        # 緩存過期時間
        'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 * 60,
    }
    

    安裝

    pip install drf-extensions
    

    使用

    常用的兩種方式,裝飾器和Mixin

    裝飾器用法

    from rest_framework_extensions.cache.decorators import cache_response
    
    class ViewSet(viewsets.ModelViewSet):
        ...
    
        @cache_response()
        def list(self, request, *args, **kwargs):
            ...
    

    Mixin用法,注意 CacheResponseMixin 要放在 ModelViewSet 的前面

    from rest_framework_extensions.cache.mixins import CacheResponseMixin
    
    class ViewSet(CacheResponseMixin, viewsets.ModelViewSet):
        ...
    

    參考資料

    響應數據量太大問題

    前面那個可視化地圖的頁面,需要獲取幾萬條人員信息,這個接口一開始沒做優化,返回的數據大小有50MB,就很離譜,單純網絡傳輸就用了40秒,卡的一批。

    前端小伙伴反映這個問題后,我查看一下服務器的日志,發現響應時間就達到了5秒,這忍不了啊。一開始是加了緩存,效果顯著,響應時間直接壓縮到了0.1秒!不過沒用,傳輸時間還是很長。

    繼續分析,因為是用DjangoStarter的自動代碼生成功能實現的接口,所以請求之后會默認返回人員信息的所有字段,但很明顯,地圖上只需要三個字段:ID、經緯度。

    所以我重新寫了個 serializer

    class BasicPersonSerializer(serializers.ModelSerializer):
        class Meta:
            model = BasicPerson
            fields = ['id', 'address_lng', 'address_lat']
    

    然后在 viewsets 里也重寫了 list 方法,用上新定義的這個 serializer

    class BasicPersonViewSet(viewsets.ModelViewSet):
        ...
    
        @cache_response()
        def list(self, request, *args, **kwargs):
            queryset = self.filter_queryset(self.get_queryset())
    
            page = self.paginate_queryset(queryset)
            if page is not None:
                serializer = BasicPersonSerializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = BasicPersonSerializer(queryset, many=True)
            return Response(serializer.data)
    

    然后再來測試一下,響應時間69毫秒,數據量變成4MB+,效果很顯著!

    整個傳輸時間只需要1.2秒左右~

    妙啊,但是我還不滿足,既然還有優化空間,那就繼續優化。

    給接口加個gzip壓縮吧~

    為圖省事,直接上全站壓縮

    MIDDLEWARE = [
        'django.middleware.gzip.GZipMiddleware',
    ]
    

    搞定

    再次請求看看

    數據大小被壓縮到480kb,傳輸時間只需要356毫秒!妙啊

    這個問題就搞定了。

    參考資料:Django使用gzip實現壓縮請求 - https://www.pythonf.cn/read/116970

    聚合查詢

    既然用Django了,有了這么方便好用的ORM,就別老想著用什么SQL語句了。

    我在這個項目里比較常用的是這幾個

    • aggregate
    • annotate
    • values (雖然這個可能不算,但用的很多)
    • Count
    • Sum

    每個函數的具體用法我就不復制粘貼了,看下面的參考資料吧~

    參考資料:

    性能優化

    Django性能確實有點一言難盡,性能優化也老生常談了,不過就實際運用而已,我們這也還是在探索之中,因為大部分場景是夠用的,沒有多高的并發。

    不過有個比較慢的地方是展示大屏的數據接口,因為要匯集好幾個表的數據進行統計,幾十萬上百萬的數據,有點慢,一開始響應時間需要40秒,這也太離譜了。

    肯定是得優化的,優化思路從減少數據庫訪問次數、合并運算、增加緩存入手,優化完成之后冷啟動速度5秒,命中緩存60毫秒內,效果還是可以的。

    關于性能優化這塊以后還是得繼續看看,Django有太多可以優化的地方了……

    (或者不行的話直接用.Net Core這種高性能的平臺重寫?)

    部署

    部署方面依然是 uwsgi / docker / docker-compose 這套組合,之前用了好多次了,比較穩定,配置文件都是現成的,直接把代碼上傳服務器 up一下就啟動了,非常方便。

    對了還需要配置一下nginx,uwsgi是專有協議,需要做個轉發,才能使用http訪問到。

    部署之后關閉debug模式,還需要進入docker容器里,在bash里執行 collectstatics 收集靜態文件。

    之后要更新的話,只需要在pycharm里配置 commit 的時候順便deploy,把修改的代碼文件提交到服務器,然后修改一下 readme.md 文件(我配置了監聽這個文件)即可重啟服務。

    項目監控

    對了,還有一個關鍵的,項目上線之后,需要監控項目的運行狀態

    對于Django項目,我用的是sentry來做監控,很好用,集成也很方便,這個sentry我準備后面寫篇文章來介紹。

    PS:對于.Net Core項目,我用的是.Net專用的ExceptionLess,這個界面很簡潔直觀,但文檔沒有sentry詳細,不過docker搭建還是很方便的。

    可以看我之前的這篇文章:[Vue2.x項目整合ExceptionLess監控](

    小結

    OK,大概就是這樣了,項目也不是到這里就結束了,只是暫告一個段落,接下來看看客戶那邊有什么新的需求再來繼續開發。

    Django框架陸陸續續也用了兩三年的時間了,雖然應用場景都比較簡單,但屬于是基本摸清了開發流程和定制的上限,像django-admin這種內置的管理后臺,盡管有大量的自定義配置功能,還有simpleUI這種優秀的第三方界面,但他的上限還是擺在那,遇到稍微需要定制化的管理后臺需求,還是得自己搞一套,好在用RestFramework寫接口實在是方便,接口導出來,套個vue+elementUI的前端,一套后臺就搞定了。

    如果還需要數據大屏這類可視化功能,我們現在也積累了一些這方面的技術和經驗,可以比較快的出產品。

    接下來很多新的項目還是優先使用.Net Core技術,從穩定性和性能的方面考慮,我還是更信賴.Net Core。

    Django的優勢主要還是在于開發效率和背靠Python社區的強大生態,不過性能和部署方便就要稍遜一點點。

    總之,都好用,看場景使用~

    posted @ 2022-04-24 22:31  程序設計實驗室  閱讀(293)  評論(0編輯  收藏  舉報
    国产美女a做受大片观看