Docker筆記二:Lumen + Redis

  Lumen 基於 Laravel 打造,專爲構建微服務和 APIs 而生。Lumen與Redis服務端通訊可經過Predis(PHP庫)或者PhpRedis(PHP的C擴展)來實現,建議使用PhpRedis,其性能更高。Lumen下使用Predis和PhpRedis都需引入illuminate/redis(PHP庫),illuminate/redis(PHP庫)都對Predis和PhpRedis(Laravel 5.3以上)進行了很好的封裝,但illuminate/redis(PHP庫)又依賴predis/predis(PHP庫),故安裝 illuminate/redis時會自動引入predis/predis(PHP庫)。php

  Redis 與 Memcached 均爲經常使用的 key-value 分佈式內存對象緩存系統,可提供數據緩存和數據共享能力,Redis 支持持久化,而 memcached 不支持持久化,發生重啓後數據不會自動恢復。mysql

  關於Memcached:laravel

  • memcached採用Slab Allocation機制基於hashmap來實現對內存對象的建立與管理,容量(哈希表中桶的數量)和加載因子(容量自動增長以前能夠達到多滿的一種尺度)影響其性能。當哈希表中的條目數超出了加載因子與當前容量的乘積時,則要對該哈希表進行 rehash (重建內部數據結構),從而哈希表將具備大約兩倍的桶數。在Java編程語言中,加載因子默認值爲0.75,默認哈希表元爲101。
  • memcached若是運行在默認狀態下,應放置在防火牆後端;
  • 在內置空間被佔滿以後,memcached採用惰性失效(Lazy Expiration)機制和Least Recently Used(LRU)機制來作淘汰管理;
  • 基於libevent的事件處理,運行多線程處理多客戶端併發鏈接請求,雖然說也支持分佈式,但服務端並無分佈式功能,彼此不能互相通訊,徹底依賴於客戶端實現,故障轉移也不提供冗餘節點,一旦某節點發生故障將致使相應的數據不可用;
  • 客戶端libmemcached可採用多種哈希算法(MD五、CRC等)計算key,對非標量類型數據如數組、對象(非資源類型才能被序列化)等將先進行序列化而後再發送給服務端,支持Multi操做;
  • CAS(Check And Set)是Memcached中比較方便的一種防止競爭修改資源的方法
    A 64bit "CAS" value, which is kept unique.
  • 支持文本協議和二進制協議兩種主要的協議。此外,還支持子協議SASL Authentication、Range operations。相關信息參考 https://github.com/memcached/memcached/wiki

    下邊這段是關於文本協議「noreply」的描述,同時建議使用二進制協議:git

    Most ASCII commands allow a "noreply" version. One should not normally use this with the ASCII protocol, as it is impossible to align errors with requests. The intent is to avoid having to wait for a return packet after executing a mutation command (such as a set or add).
    
    The binary protocol properly implements noreply (quiet) statements. If you have a client which supports or uses the binary protocol, odds are good you may take advantage of this.

    下邊這段是關於「A Well Designed Binary Protocol Client」的描述:github

    With the binary protocol, it(A Well Designed Binary Protocol Client may take many application threads and use a single TCP connection back to memcached) is possible to pack requests from different client instances into the same TCP socket, then dole back results to the right owners.

  關於Redis(REmote DIctionary Server, 遠程字典服務器)SSDB支持LevelDB,是Redis的替代品,且與其兼容。web

  • 運行單線程(多核CPU沒法充分利用)處理多客戶端併發鏈接請求,採用了異步非阻塞 IO 模型(epoll)。多線程天然是能夠比單線程有更高的性能上限,但在今天的計算環境中,即便是單機多線程的上限也不能知足實際需求了,所以單機單線程集羣化部署是有效解決方案;
  • 不依賴libevent這個追求通用而致使代碼龐大的庫,用libevent中的兩個文件修改實現了本身的epoll event loop,小巧並去依賴,編譯Redis以前並不須要執行./configure;
  • Redis 2.0增長了虛擬內存(Virtual Memory,Redis本身實現的比OS Page更細的換入出粒度)特性,實現了冷熱數據分離,讓數據容量突破了物理內存的限制;
  •  支持多種類型的數據結構,如strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs and geospatial indexes with radius queries;
  • 支持Cache-Only、Persistence兩種存儲模式,Persistence可分AOF(Append-Only File)、RDB(Redis Database)兩種機制(但官方建議兩種模式同時開啓,參考Redis Persistence),可用於crash後從磁盤恢復,可是都存在可能丟失數據(數據可靠性)問題。從讀緩存這個角度講,一般咱們的應用能夠接受這種數據丟失帶來的影響,若是應用要求更高的數據可靠性,那就不該該對該類數據使用緩存服務;
    RDB:在save、shutdown、slave時觸發寫二進制文件,粒度大,若是這些操做未完成以前crash可能致使丟失一部分數據。
    經過fork一個進程,copy-on-write把整個db保存下來,而主進程不會進行任何IO操做,保證了redis的高性能。

    AOF:持續把寫操做命令格式化後追加到日誌文件的尾部,粒度較小,crash以後數據丟失小。AOF支持不一樣的fsync策略,
    包括無fsync、每秒fsync、請求時fsync,默認爲每秒fsync策略。fsync是由後臺線程完成的,主線程繼續努
    力地執行寫請求。AOF是文本文件,一般也比RDB文件大,恢復速度慢。
  • Redis支持Cluster、Master-Slave replication,因爲Redis的高性能,replication基本沒有延遲,這樣達到了防止單點故障及實現了高可用;
  • Redis支持事務:watch/multi/exec(discard、unwatch);
  • list可用來實現隊列;
  • Redis pipeline技術能夠在服務端未響應時,客戶端能夠繼續向服務端發送請求,並最終一次性讀取全部服務端的響應。

 

一. Redis的Docker部署redis

  1. 建立Dockerfile-Redis(參考https://github.com/dockerfile/redis/blob/master/Dockerfile ):
    FROM ubuntu
    MAINTAINER cenze <272666745@qq.com>
    
    RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    ADD conf/sources.list /etc/apt/
    RUN apt-get update \
    && apt-get install -y gcc make vim
    
    ENV PKGS="/usr/local/pkgs"
    ADD packages/redis-3.2.8.tar.gz $PKGS/
    
    # install redis
    ENV PREFIX_REDIS="/usr/local/redis"
    WORKDIR $PKGS/redis-3.2.8
    RUN make \
    && make PREFIX=$PREFIX_REDIS install \
    && cp redis.conf $PREFIX_REDIS/ \
    && cp src/redis-trib.rb $PREFIX_REDIS/bin/ 
    
    VOLUME ["/data"]
    ENV PATH $PREFIX_REDIS/bin:$PATH
    
    EXPOSE 6379
    
    CMD ["redis-server","/usr/local/redis/redis.conf"]

    注意事項算法

    • Redis命令參考:https://redis.io/commands
    • 本人已事先下載了PhpRedis的源碼安裝包redis-3.2.8.tar.gz位於宿主機 ./packages目錄下
    • redis.conf中註銷行 bind 127.0.0.1 或明確綁定 IP地址集,其餘容器纔可訪問 
    • redis.conf中若未設置密碼,可能需設置 protected-mode 爲 no以關閉保護模式,protected-mode 默認值爲 yes
    • 安裝目錄的bin下有個redis-cli可拷到其餘容器中做爲命令行接口來鏈接管理redis服務端
    • 卷/data用於緩存數據對象的持久化存儲目錄
  2. 構建鏡像:
    sudo docker build -t cenze/redis -f Dockerfile-Redis .
  3. 運行容器:
    sudo docker run -d --name redis cenze/redis

    redis-cli或netcat(nc)或telnet測試部署:redis-cli下輸入 help <Tab> 可按組查詢命令列表sql

    root@60c9de8c01a0:/usr/local/pkgs/redis-3.2.8# redis-cli -h 127.0.0.1
    127.0.0.1:6379> set cache redis
    OK
    127.0.0.1:6379> get cache
    "redis"
    127.0.0.1:6379>  

     

 二.建立Lumen項目docker

  1. composer建立Lumen:composer沒法以 root/super 用戶來運行,因此須要切換到其餘用戶環境,好比本人會運行以下命令
    su - www-data 
    export PATH=/usr/local/php/bin:$PATH (這一條最好寫進Home下的.profile, composer依賴PHP來運行) 
    composer create-project --prefer-dist laravel/lumen lumen
  2. .env參數配置:

    APP_ENV=local
    APP_DEBUG=true
    APP_KEY=bcee22b233721b47c6043e6bf35ac4ee
    APP_TIMEZONE=Asia/Shanghai
    
    DB_CONNECTION=mysql
    DB_HOST=[myDbHost]
    DB_PORT=3306
    DB_DATABASE=[myDataBase]
    DB_USERNAME=[myUser]
    DB_PASSWORD=[myPassword]
    
    CACHE_DRIVER=redis
    QUEUE_DRIVER=sync 
    
    REDIS_HOST= 172.17.0.3
    REDIS_PORT= 6379

     

三.Lumen中啓用Predis

  1. 安裝Predis:Lumen中使用Predis須要引入 predis/predis 和 illuminate/redis兩個包
    cd /path/to/lumen
    composer require illuminate/redis (predis/predis爲illuminate/redis所依賴,故將被自動安裝上)
  2. redis客戶端配置修改lumen/vendor/laravel/lumen-framework/config/database.php
    'redis' => [
            
            'client' => 'predis',
            //'client' => 'phpredis',
            
            'cluster' => env('REDIS_CLUSTER', false),
    
            'default' => [
                'host'     => env('REDIS_HOST', 'localhost'),
                'port'     => env('REDIS_PORT', 6379),
                'database' => env('REDIS_DATABASE', 0),
                'password' => env('REDIS_PASSWORD', null),
            ],
    
        ],
  3. 註冊Illuminate\Redis\RedisServiceProvider修改lumen/bootstrap/app.php
    $app->register(Illuminate\Redis\RedisServiceProvider::class);
    
    $app->withFacades();//同時啓用Facades
    
    $app->withEloquent();//同時啓用Eloquent
  4. 測試Predis是否成功啓用:修改lumen/routes/web.php
    $app->get('/', function () use ($app) {
        //return $app->version();
        Cache::put('lumen', 'Hello, Lumen.', 5);
        return Cache::get('lumen');
    });

    頁面輸出:Hello, Lumen.

四.Lumen中啓用PhpRedis擴展

  1. 安裝PhpRedis:這是其官方參考文檔 https://github.com/phpredis/phpredis#usage,某些用法可能與Illuminate\Redis不一樣
    pecl install redis (有可能須要手動安裝 autoconf,phpize依賴該工具)
    composer require illuminate/redis

    注意事項:該C擴展安裝完後須要修改php.ini添加行extension=redis.so。若是php在cli模式下運行未發現Redis,多是由於你的php.ini文件沒有找到,該文件爲安裝配置項--with-config-file-path所指定,默認位於PREFIX/lib目錄下,因此應在啓動php時添加-c選項指定配置文件或php.ini所在目錄。

  2. redis客戶端配置:基本同於Predis,惟一不一樣之處在於lumen/vendor/laravel/lumen-framework/config/database.php中redis的client,'client' => 'phpredis'
  3. 註冊Illuminate\Redis\RedisServiceProvider:同於Predis
  4. 測試PhpRedis是否成功啓用:同於Predis
  5. 另一種無需安裝illuminate/redis包就能啓用PhpRedis的替換用方法:

    1)修改lumen/bootstrap/app.php,添加以下代碼:

    $app->singleton('redis', function(){
        $redis = new Redis;
        $redis->pconnect('172.17.0.3');
        return $redis;
    });
    unset($app->availableBindings['redis']);
    2)測試PhpRedis是否成功啓用,修改lumen/routes/web.php:
    $app->get('/', function () use ($app) {
        //return $app->version();
        app('redis')->set('lumen', 'Hello, Lumen.');
        return app('redis')->get("key");
    });
相關文章
相關標籤/搜索