基於redis實現分佈式鎖_貨運

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

目錄

  • 原理剖析
  • 實現
    • 編寫註解
    • 攔截器攔截
    • 上述提及工具
      • RedisLock
      • StockKeyGenerator
    • 問題分析
      • 業務處理時間>上鎖過期時間

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

系統的不斷擴大,分佈式鎖是最基本的保障。與單機的多線程不一樣的是,分佈式跨多個機器。線程的共享變量無法跨機器。

為了保證一個在高併發存場景下只能被同一個線程操作,java併發處理提供ReentrantLock或Synchronized進行互斥控制。但是這僅僅對單機環境有效。我們實現分佈式鎖大概通過三種方式。

  • redis實現分佈式鎖
  • 數據庫實現分佈式鎖
  • zk實現分佈式鎖
    今天我們介紹通過redis實現分佈式鎖。實際上這三種和java對比看屬於一類。都是屬於程序外部鎖。

原理剖析

  • 上述三種分佈式鎖都是通過各自為依據對各個請求進行上鎖,解鎖從而控制放行還是拒絕。redis鎖是基於其提供的setnx命令。
  • setnx當且僅當key不存在。若給定key已經存在,則setnx不做任何動作。setnx是一個原子性操作。
  • 和數據庫分佈式相比,因為redis內存輕量。所以redis分佈式鎖性能更好

實現

  • 原理很簡單。結合springboot項目我們實現一套通過註解形式對接口進行庫存上鎖案例進行理解

編寫註解

  • 我們編寫註解。方便我們在接口上添加註解提供攔截信息

/**
 * @author 張新華
 * @version V1.0
 * @Package com.ay.framework.order.redis.product
 * @date 2020年03月26日, 0026 10:29
 * @Copyright © 2020 安元科技有限公司
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface StockLock {

    /**
     * @author zxhtom
     * @Description 鎖key的前綴
     * @Date 15:25 2020年03月25日, 0025
     * @Param []
     * @return java.lang.String
     */
    String prefix() default "";
    /**
     * @author zxhtom
     * @Description key的分隔符
     * @Date 15:27 2020年03月25日, 0025
     * @Param []
     * @return java.lang.String
     */
    String delimiter() default ":";
}


/**
 * @author 張新華
 * @version V1.0
 * @Package com.ay.framework.order.redis.product
 * @date 2020年03月26日, 0026 11:09
 * @Copyright © 2020 安元科技有限公司
 */
@Target({ElementType.PARAMETER , ElementType.METHOD , ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface StockParam {
    /**
    * @author zxhtom
    * @Description 組成key
    * @Date 11:11 2020年03月26日, 0026
    * @Param []
    * @return java.lang.String[]
    */
    String[] names() default {""};
}

攔截器攔截

  • redis分佈式鎖實現的關鍵就是攔截器的編寫。上面的註解只是為了實現攔截的一個輔助。

@Around("execution(public * *(..)) && @annotation(com.ay.framework.order.redis.product.StockLock)")

  • 通過springboot的Around進行針對StockLock註解的攔截。通過攔截我們可以獲取到攔截的方法、參數、及需要的鎖的參數。
  • 我們獲取到需要鎖的名稱這裏叫做【a】之後通過redis的原子性操作對該key進行遞減操作。
  • 為了方便我們在削減庫存的時候可以對庫存進行更新操作。我們在遞減庫存前還需要藉助於另一把鎖。 這一把鎖我們叫做【a_key】
  • 換句話說我們接口想訪問就必須獲取【a】鎖,拿到【a】鎖需要減少庫存。減少庫存之前需要獲取【a_key】鎖。
  • 拿到鎖之後處理完邏輯之後我們需要釋放對應鎖。

RedisAtomicLong entityIdCounter = new RedisAtomicLong(lockKey, redisTemplate.getConnectionFactory());
    if (redisTemplate.hasKey(CoreConstants.UPDATEPRODUCTREDISLOCKKEY + lockKey)) {
        //表示lockKey的庫存信息有變動。此時無法進行交易
        throw new BusinessException("庫存變動。暫無法交易");
    }
    Long increment = entityIdCounter.decrementAndGet();
    if (increment >= 0) {
        try {
            Object proceed = pjp.proceed();
        } catch (Throwable throwable) {
            //所佔資源需要釋放回資源池
            while (!redisLock.tryGetLock(CoreConstants.UPDATEPRODUCTREDISLOCKKEY + lockKey, "")) {

            }
            //表示lockKey的庫存信息有變動。此時無法進行交易
            long l = entityIdCounter.incrementAndGet();
            if (l < 1) {
                redisTemplate.opsForValue().set(lockKey,1);
            }
            redisLock.unLock(CoreConstants.UPDATEPRODUCTREDISLOCKKEY + lockKey);
            throwable.printStackTrace();
        }
    } else {
        redisTemplate.opsForValue().set(lockKey,0);
        throw new BusinessException("庫存不足!無法操作");
    }

  • 因為我們上鎖就需要釋放鎖。但是程序在中途處理業務是發生異常導致沒有走到釋放鎖的步驟。這個時候就導致我們的分佈式鎖一直被鎖。俗稱【死鎖】。為了避免這種場景的發生。我們常常在上鎖的時候給一個有效期。有效期已過自動釋放鎖。這個特性恰好和redis的過期策略不摩爾和。

上述提及工具

RedisLock


public Boolean tryGetLock(String key , String value) {
    return tryGetLock(key, value, -1, TimeUnit.DAYS);
}
public Boolean tryGetLock(String key , String value, Integer expire) {
    return tryGetLock(key, value, expire, TimeUnit.SECONDS);
}
public Boolean tryGetLock(String key , String value, Integer expire , TimeUnit timeUnit) {
    ValueOperations operations = redisTemplate.opsForValue();
    if (operations.setIfAbsent(key, value)) {
        //說明 redis沒有該key , 換言之 加鎖成功  設置過期時間防止死鎖
        if (expire > 0) {
            redisTemplate.expire(key, expire, timeUnit);
        }
        return true;
    }
    return false;
}

public Boolean unLock(String key) {
    return redisTemplate.delete(key);
}

StockKeyGenerator


@Component()
@Primary
public class StockKeyGenerator implements CacheKeyGenerator {
    @Override
    public String getLockKey(ProceedingJoinPoint pjp) {
        //獲取方法簽名
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        //獲取方法cacheLock註解
        StockLock stockLock = method.getAnnotation(StockLock.class);
        //獲取方法參數
        Object[] args = pjp.getArgs();
        Parameter[] parameters = method.getParameters();
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < parameters.length; i++) {
            StockParam stockParam = parameters[i].getAnnotation(StockParam.class);
            Object arg = args[i];
            if (arg instanceof Map) {
                Map<String, Object> temArgMap = (Map<String, Object>) arg;
                String[] names = stockParam.names();
                for (String name : names) {
                    if (builder.length() > 0) {
                        builder.append(stockLock.delimiter());
                    }
                    builder.append(temArgMap.get(name));
                }
            }

        }
        return builder.toString();
    }
}

問題分析

  • 上面分析了一個死鎖的場景,理論上出了死鎖我們redis分佈鎖很好的解決了分佈式問題。但是還是會出現問題。下面列舉寫小編遇到的問題。

業務處理時間>上鎖過期時間

  • a線程獲取到鎖,開始進行業務處理需要8S,
  • 在8S內,鎖的有效期是5S,在鎖過期后也就是第6S , b線程進入開始獲取鎖這個時候b是可以獲取到新鎖的。這個時候就是有問題的。
  • 假設b線程業務處理只需要3S , 但是因為a線程釋放了鎖,所以在第8S的時候雖然b線程沒有釋放鎖,b的鎖也沒有過期但是這時候也沒有了鎖。從而導致C線程也可以進入

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

何苦咬牙買豪華品牌?教你如何用20萬買出豪華檔次的車型!_貨運

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

0T的車型的畢竟6AT比1。5T的7速雙離合要成熟不少,開起來起碼平順性是很好的。實際上該車的操控、靜音等各方面都進步不少,底盤也是十分紮實,震動的動作不大,感覺新君越的整體駕乘體驗不比豪華車差。長安福特-金牛座指導價:23。

可能有些人覺得開台BBA出去會比較有面子,畢竟豪華車是身份的象徵,當然,那些是有錢之後考慮的事情了。那如果手裡的閑錢不到三十萬,要不要咬咬牙,擠多一點錢出來直接拿下一台BBA?認為這完全沒必要,按照這個預算,其實也有豪華感十足,但是購車和用車成本比BBA低很多的車子,這不,今天就給大家挑了幾輛這樣的車。(pS:這幾輛車就不介紹乘坐空間了,因為這是完全不用擔心的問題。)

一汽大眾-邁騰

指導價:18.99-31.69萬

今年七月上市的換代新邁騰(B8)可謂千呼萬喚始出來,事實上,一汽大眾這輛基於MQB平台的B級車也並沒有讓失望。

外觀上,新邁騰總體來說就是變得更寬更扁了,中網-大燈一體化的設計讓前臉看起來更加開揚,LED光源的大燈點亮後效果十分搶眼。貫穿兩個把手的腰線十分硬朗,告別了舊款略帶木訥的觀感。車尾線條幹凈利落,最有特色的要數那LED豎狀剎車燈,點亮后辨識度極高。

內飾的設計雖然低調,但商務氣息特別濃,中控台採用大面積的軟質搪塑材料,質感十分好,最喜歡的莫過於內飾中加入了實木飾板,提升了整個車廂的格調,帶來越級的體驗。儀錶盤為液晶的,功能強大,8英寸大屏搭載了MIB多媒體系統,操作簡單。內飾雖說不上奢華,但能夠給一種很接地氣的豪華感。

動力方面,新邁騰仍然有1.4T、1.8T和2.0T三個版本,搭載最新的第三代EA211和EA888發動機,最大馬力分別是150、179和220pS,變速箱為大眾比較成熟的7速雙離合。大眾的雙離合已經十分成熟,換擋動作快而穩,發動機的發力點靠後,起步平順,後勁十足,雖然不能給你激烈的駕駛感受,但配合紮實有韌性的底盤,認為這種平順穩重的行駛品質,是該級別的車應有的表現。

上汽通用別克-君越

指導價:22.58-33.98萬

君越的出現可以說是刷新了對B級車的看法,

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

第一次見到B級車也能夠這麼長,這麼有豪華感,而20多30萬的價格,又讓該車十分的接地氣。

新君越的造型明顯變得更加年輕化的低矮扁平了,擺脫了舊款車型臃腫的“大叔車”造型,飛翼式的格柵辨識度很高,亮黑的底色配上鍍鉻兩條,質感很高檔。整體來說,認為這一代君越流暢、扁平的造型會讓他的受眾範圍更廣,兼顧了商務大氣和年輕時尚,很好。

簡潔明了的內飾採用懷抱式的設計,幹練之餘線條十分流暢。進入新君越的車廂時第一感覺就是豪華,大量的真皮搭配仿木紋飾板,十分顯高檔。多媒體系統也支持安吉星、Carplay和Carlife功能,十分豐富。

燃油版的新君越有兩種動力配置,按排量分分別是1.5T和2.0T,提供最大170pS和261pS的馬力,還是建議買2.0T的車型的畢竟6AT比1.5T的7速雙離合要成熟不少,開起來起碼平順性是很好的。實際上該車的操控、靜音等各方面都進步不少,底盤也是十分紮實,震動的動作不大,感覺新君越的整體駕乘體驗不比豪華車差。

長安福特-金牛座

指導價:23.38-34.88萬

要說金牛座,剛上市的時候還是比較沸沸揚揚的,當然也是有各種事件的影響,看中大型車銷量的話,金牛座其實並不差,前面除了BBA就是皇冠了,二十萬出頭能有這個級別的商務機座駕,夫復何求啊。

外觀上,認為金牛座的外觀是穩重當中又帶點粗獷氣息的,這也很符合美系車的風格。前臉最明顯的就是家族式的碩大中網,但隱約覺得與金牛座穩重的風格有點格格不入。覺得金牛座的外觀還是相當大氣的,畢竟車身尺寸擺在那。

再看內飾,皮質的面料、寬大的扶手箱、木紋飾板的加入、四副式的方向盤,營造出一種沉穩的商務氣息。細節上,看到金牛座的做工其實很不錯,接縫均勻、包裹嚴實,做工上絕對對得起它的定位。最出彩的是後排有豐富的功能,多媒體、空調控制等等一應俱全。

動力上,指導價不出30萬就能夠買到2.7T雙渦輪增壓V6引擎的配置,最大馬力329pS,搭配6AT變速箱,動力輸出平順而有力,油門雖然沉穩,但是V6引擎的低扭十分強,絲毫不用擔心起步拖沓。底盤的質感偏軟,但能保證一定的支撐性,整體的行駛質感還是十分優秀的。

一汽豐田-皇本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

一圖讀懂十九屆五中全會公報中的美麗中國_貨運

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

2020-11-01

2020-11-01
分享到:
[打印]
字號:[大] [中] [小]

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

小米有品野小獸健腹輪 J20 眾籌推出:智慧數字顯示、遠距回彈,眾籌價約 860 元_貨運

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

除了疫情影響,最近寒流來襲也讓民眾降低出門運動的意願,不過如果想在家自主培養運動習慣,選購一款體積小、收納不佔用空間的健身器材就相當重要,像是健腹輪就是款能幫助用戶在家鍛煉腹肌、燃燒脂肪的運動器材就是不錯的選擇。最近小米有品最新一期眾籌的「野小獸健腹輪 J20」,不僅能顯示數字資訊、還能自動回彈讓新手也能輕鬆駕馭。

小米有品野小獸健腹輪 J20 眾籌推出:智慧數字顯示、遠距回彈,眾籌價約 860 元

最近在小米有品推出的野小獸健腹輪 J20 採用人體工學設計,能搭配智慧訓練模式和完整的訓練計劃達成訓練目標。

野小獸健腹輪 J20 具備自動超強回彈機制,回彈力道足以抵銷運動時身體向前的衝力,降低受傷風險、即便新手也能駕馭。

當運動到最遠處時,彈簧可提供等效的回彈力道來支撐身體, 1.8 公尺的安全回彈距離,能有效保障運動安全。

野小獸健腹輪 J20 配備智慧 LED 顯示螢幕,能即時顯示藍芽狀態、剩餘電量、運動次數等運動數據。

在野小獸健腹輪 J20 採用一體成型設計,在機身內部採用全包覆式多重防護結構,能有效防止拉伸、變形、捲縮、分裂,達到安全防護作用。

另外,採用多重消音裝置讓運動更靜音,通過內建鋼片發條自動回彈發力,確保滾動更順暢。相較於傳統發條受力更均衡、壽命也更長。

滾輪內裡採用多層加厚複合材質,具備韌性強、耐磨行滑的特性,在滾動來回之間不傷地板、無噪音。

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

用戶也能野小獸 App 觀看教學課程,在 App 端也能即時顯示運動數據:

售價方面,野小獸健腹輪 J20 目前在小米有品展開眾籌,眾籌價為人民幣 199 元(約合新台幣 860 元),建議售價則為人民幣 299 元(約合新台幣 1,287 元)。

圖片/消息來源:小米有品

延伸閱讀:
Redmi K40 Pro 最新渲染圖曝光:可能是最便宜的 S888 旗艦 5G 手機之一

小米11 Lite 通過 FCC 認證,相關規格提前曝光!

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

六一兒童節,程序員寫給女兒的一封信_貨運

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

今天是六一兒童節,不想寫技術了,就寫點別的吧——給四歲的女兒寫封信。我的讀者群體里大部分都是大學生或者初入職場的新人,一時半會是體會不到做父母的辛酸和樂趣。

但我希望我的故事能給讀者朋友們枯燥的生活增添一丟丟樂趣,這就足夠了,對吧?這也是我一直以來的心愿。

親愛的女兒,你好呀。

我是你的爸爸馬偉青(有些讀者叫我二哥、有些叫王老師、有些叫馬老師、有些叫青哥,我統統接受,一個也不挑),等你能看懂這封信的時候,你已經可以自由地閱讀了。大量的閱讀,對人的一生至關重要,所以咱們家最多的就是書本了——這也是我一直引以為傲的。

媽媽也喜歡給你買書,我覺得她給你買的書都質量蠻高的,比如說甜心英語、長頸鹿卡密爾、馬努和米娜、巧虎、窗邊的小豆豆等等,這些書都是成套的,爸爸讀起來都覺得挺有意思,我想你也一定非常喜歡。

因為你讀書的樣子真的非常專註,非常可愛。

記得你剛從媽媽肚子里剖出來的時候,外婆抱着你,對爸爸說了一句夠驕傲一輩子的話:“長得真像你啊。”不是爸爸要和你媽媽爭寵,而是你的確是爸爸媽媽愛情的結晶,你的到來,豐富了我們的生活和情感,更重要的是,賦予了爸爸媽媽神聖的職責。

如果沒有你,爸爸在業餘時間里,可能還沉浸在 Dota、火炬之光、三國群英傳 7 的遊戲中。想想都覺得無比的可怕,打遊戲沒有錯,但爸爸應該去做一些更积極向上、更富有意義的事情,比如說讀書和寫作。

我比你姑姑大 11 歲,所以她小的時候,爸爸帶的非常多。就連上了小學,爸爸去哪裡她都要跟到哪裡,包括和你媽媽約會的時候。

也許是這樣一份特殊的經歷,爸爸在帶你的過程中顯然比你媽媽更專業一些,就連拍飽嗝(防止你奶吃多了吐)這種高級別的手法爸爸都會。由於媽媽工作上的限制,爸爸總體上帶你的時間確實要比媽媽多一些,陪你去上金寶貝早教課、上兔加熊體能課、上樂高積木、上愛貝英語,包括在小區裏面和小朋友玩,以及日常護理,洗澡洗頭髮,爸爸都能得心應手。

一開始,爸爸也是放不開的,畢竟帶孩子這件事,女性的佔比要比男性的佔比多得多,站在女人堆里,有時候真的是舉足無措啊。

但爸爸硬是挺了過來。關鍵是,還兼顧了家務、工作和寫作,想想都覺得自己挺牛逼的,我想你也這麼覺得吧?

爸爸和媽媽畢竟有一些不同,有的時候會嚴厲一些,所以你從來不鬧爸爸,你的這份克制多多少少會讓爸爸覺得內疚,但我想,對你的性格,對你以後的為人處事會有一些幫助,畢竟社會有美好的一面,也有殘忍的一面。

你長這麼大,只有一件事,讓爸爸至今懷恨在心,就是在你滿月之前,剪手指甲的時候把你手指頭上的肉剪掉了一小塊。鮮紅的血液流出來了你才後知后覺地哭了起來,可把爸爸嚇壞了。從此以後,再沒敢替你剪過指甲。

好了,過往就先煽情到這裏。接下來,爸爸寫一下對你的期許,或許不叫期許,更應該叫做祝福。無論你成為怎樣的你,爸爸永遠都是你背後最強有力的支柱。

第一,爸爸媽媽會努力給你力所能及最好的教育條件。但是,爸爸不希望學校過早的壓榨你的潛力,如果作業真的多到沒有時間去玩,爸爸寧願你不寫,家長會挨批的話,爸爸不嫌丟臉。

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

在爸爸看來,學習固然重要,但如果是通過寫不完的作業來達成的話,我認為是有問題的。爸爸來自於農村,所以讀書上學是唯一改變命運的出路,但你不同,你可以放心大膽地去做更多你喜歡做的事情,不用去承擔後果,以及背負巨大的壓力。

第二,在上學的年紀,一定要多多讀書,你喜歡讀什麼樣的書,爸爸都會給你買,沒有任何限制。

爸爸在上初中的時候,讀書的興趣是最濃烈,最純粹的,但那時候學校不允許讀任何課外書,真的是抹殺了爸爸求知的天性。

人最怕的除了窮,就是無知了。“窮”這個難題,爸爸媽媽會努力幫你解決,但“無知”這個難題,就需要你自己去完成了。而書,是解決這個難題最強有力的武器。

第三,英語非常非常重要,了解我們自己的文化固然重要,吸取別人的長處同樣重要。如果你精通英語的話,周遊世界,探索你感興趣的領域就會容易得多,這是不爭的事實。

爸爸就時常後悔沒有把英語學到極致,否則爸爸會在編程領域更上一層樓的。但爸爸沒有放棄,仍然在盡最大的努力改善中。你現在已經認識四五十個單詞了,這在爸爸看來,太棒了。

第四,女孩子一定要學會撒嬌和賣萌,這也是爸爸從小一直教你的,遇到一些問題時,哭鬧不是最好的解決辦法,變通才是最好的。

你可以像爸爸一樣,做一個情緒化的人,該哭的時候哭,該笑的時候笑,不要做女強人,學會與朋友分享你的痛苦和快樂。

第五,女孩子一定要學會化妝和打扮,把自己收拾的美美的,衣着得體,糟糕的情緒也會逃之夭夭。

體能鍛煉也是必不可少的,一方面是為了保持身體健康,塑造完美體形,另一方面,能夠幫助你養成良好的生活習慣,以及堅強的意志力。

第六,做你自己,做好你自己。不要太計較別人的眼光,把自己活得快活一點,樂觀一點、瀟洒一點。

如果以後爸爸媽媽的觀點和你不一致,不要聽我們的,聽從你自己內心最真實的那個聲音。你雖然是我們的女兒,但生命是你自己的,由你負責。但不管怎樣,爸爸和媽媽,都會做你最堅強的後盾,永遠支持你和愛護你。

就寫這麼多吧。Peace。

如果覺得文章對你有點幫助,請微信搜索「 沉默王二 」第一時間閱讀。

本文已收錄 GitHub,傳送門~ ,裏面更有大廠面試完整考點,歡迎 Star。

我是沉默王二,一枚有顏值卻靠才華苟且的程序員。關注即可提升學習效率,別忘了三連啊,點贊、收藏、留言,我不挑,嘻嘻

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

空污驟降 歐少死1萬人_貨運

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

摘錄自2020年4月30日聯合報報導

30日發佈的最新報告顯示,由於化石燃料污染驟降,發布禁足令的歐洲國家在4月死亡人數與去年同期相較,少了1萬1000人。

法新社報導,歐洲國家為防止新冠病毒擴散採取的措施減緩經濟發展,燃煤火力發電下降37%、石油消耗也減少三分之一。全球石油使用量下降幅度大致相同,煤炭消耗量降幅則因地而異。

工廠關閉和空蕩道路帶來意想不到的好處:乾淨的空氣。研究發現,二氧化氮和微小污染粒子pm2.5的含量分別下降37%和10%,這兩種有毒物質皆為燃燒煤炭、石油和天然氣的產物。

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

 

 

公害污染
空氣污染
污染治理
國際新聞
歐洲
化石燃料
武漢肺炎
疫情
動物與大環境變遷

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

ROG 新一代 Claymore II 機械鍵盤與 Gladius III 電競滑鼠推出,全方面大進化_貨運

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

除了筆電等系統類產品外,Asus 也更新了旗下 ROG 的周邊配備,其中包含從前一代就定位明確、頗有亮點的可分離式 Claymore II 機械鍵盤以及更輕量、可更換微動的 Gladius III 電競滑鼠,兩款產品有感升級,不只系統要更新,有如左臂右膀的配件產品更是不能錯漏。

ROG 新一代 Claymore II 機械鍵盤與 Gladius III 電競滑鼠推出,全方面大進化

Claymore II 機械鍵盤
這一代的 Claymore II 與前一代同樣採用可分離式設計,在數字鍵上方配置有 4 個可自行定義功能的按鍵,讓用戶依照使用需求自由組合形式與設定,繼續保持高自由度的好傳統。

在外觀上延續過去窄框、金屬上蓋與裸軸等元素,但軸心部分則從過去的 MX 軸改為 ROG 自家的 RX Blue 光軸,具備段落明確的手感以及較重的 65gf 觸發力道。這款鍵盤內建 4000mAh 電池,最長續航可達 100 小時並支援快充,可支援有線與 2.4GHz、藍牙無線等模式。

ROG Gladius III
這款最新的電競滑鼠與上面的鍵盤一樣支援有線與 2.4GHz、藍牙無線三種模式。

這款滑鼠在外型上設計改良,讓其握感更合手,加上側邊手感提升的止滑墊以及僅有 89g 的輕量化,讓你一鼠在手所向披靡。在光學感應器部分提升至 19000 DPI,還將微動更換插槽升級為 Push-Fit Switch Socket II,支援之前的 3 Pin 微動與 5 Pin 歐姆龍光學微動,讓玩家依照個人喜好自行選擇替換。

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

這兩款最新周邊產品目前尚未公布其售價與上市時間,不過對很多玩家來說應該已經開始期待,包括筆者也對其躍躍欲試,日後有機會親手把玩再來與大家分享吧!

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

[源碼解析]為什麼mapPartition比map更高效_貨運

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

[源碼解析]為什麼mapPartition比map更高效

目錄

  • [源碼解析]為什麼mapPartition比map更高效
    • 0x00 摘要
    • 0x01 map vs mapPartition
      • 1.1 map
      • 1.2 mapPartition
      • 1.3 異同
    • 0x02 代碼
    • 0x03 Flink的傳輸機制
      • 3.1 傳輸機制概述
      • 3.2 遠程通信
      • 3.3 TaskManager進程內傳輸
      • 3.4 源碼分析
    • 0x04 runtime
      • 4.1 Driver
      • 4.2 MapDriver
      • 4.3 MapPartitionDriver
      • 4.4 效率區別
    • 0x05 優化和ChainedMapDriver
    • 0x06 總結
    • 0x07 參考

0x00 摘要

自從函數式編程和響應式編程逐漸進入到程序員的生活之後,map函數作為其中一個重要算子也為大家所熟知,無論是前端web開發,手機開發還是後端服務器開發,都很難逃過它的手心。而在大數據領域中又往往可以見到另外一個算子mapPartition的身影。在性能調優中,經常會被建議盡量用 mappartition 操作去替代 map 操作。本文將從Flink源碼和示例入手,為大家解析為什麼mapPartition比map更高效。

0x01 map vs mapPartition

1.1 map

Map的作用是將數據流上每個元素轉換為另外的元素,比如data.map { x => x.toInt }。它把數組流中的每一個值,使用所提供的函數執行一遍,一一對應。得到與元素個數相同的數組流。然後返回這個新數據流。

1.2 mapPartition

MapPartition的作用是單個函數調用并行分區,比如data.mapPartition { in => in map { (_, 1) } }。該函數將分區作為“迭代器”,可以產生任意數量的結果。每個分區中的元素數量取決於并行度和以前的operations。

1.3 異同

其實,兩者完成的業務操作是一樣的,本質上都是將數據流上每個元素轉換為另外的元素。

區別主要在兩點。

從邏輯實現來講

  • map邏輯實現簡單,就是在函數中簡單一一轉換,map函數的輸入和輸入都是單個元素。
  • mapPartition相對複雜,函數的輸入有兩個,一般格式為 void mapPartition(Iterable<T> values, Collector<O> out) 。其中values是需要映射轉換的所有記錄,out是用來發送結果的collector。具體返回什麼,如何操作out來返回結果,則完全依賴於業務邏輯。

從調用次數來說

  • 數據有多少個元素,map就會被調用多少次。
  • 數據有多少分區,mapPartition就會被調用多少次。

為什麼MapPartition有這麼高效呢,下面我們將具體論證。

0x02 代碼

首先我們給出示例代碼,從下文中我們可以看出,map就是簡單的轉換,而mapPartition則不但要做轉換,程序員還需要手動操作如何返回結果:

public class IteratePi {

    public static void main(String[] args) throws Exception {
        final ExecutionEnvironment env=ExecutionEnvironment.getExecutionEnvironment();
        //迭代次數
        int iterativeNum=10;
        DataSet<Integer> wordList = env.fromElements(1, 2, 3);
      
        IterativeDataSet<Integer> iterativeDataSet=wordList.iterate(iterativeNum);
        DataSet<Integer> mapResult=iterativeDataSet
          			.map(new MapFunction<Integer, Integer>() {
            @Override
            public Integer map(Integer value) throws Exception {
                value += 1;
                return value;
            }
        });
        //迭代結束的條件
        DataSet<Integer> result=iterativeDataSet.closeWith(mapResult);
        result.print();

        MapPartitionOperator<Integer, Integer> mapPartitionResult = iterativeDataSet
                .mapPartition(new MapPartitionFunction<Integer, Integer>() {
            @Override
            public void mapPartition(Iterable<Integer> values, Collector<Integer> out) {
                for (Integer value : values) {
                    // 這裏需要程序員自行決定如何返回,即調用collect操作。
                    out.collect(value + 2);
                }
            }                                                                                                                           					}
        );
        //迭代結束的條件
        DataSet<Integer> partitionResult=iterativeDataSet.closeWith(mapPartitionResult);
        partitionResult.print();
    }
}

0x03 Flink的傳輸機制

世界上很少有沒有來由的愛,也少見免費的午餐。mapPartition之所以高效,其所依賴的基礎就是Flink的傳輸機制。所以我們下面就講解下為什麼。

大家都知道,Spark是用微批處理來模擬流處理,就是說,spark還是一批一批的傳輸和處理數據,所以我們就能理解mapPartition的機制就是基於這一批數據做統一處理。這樣確實可以高效。

但是Flink號稱是純流,即Flink是每來一個輸入record,就進行一次業務處理,然後返回給下游算子。

有的兄弟就會產生疑問:每次都只是處理單個記錄,怎麼能夠讓mapPartition做到批次處理呢。其實這就是Flink的微妙之處:即Flink確實是每次都處理一個輸入record,但是在上下游傳輸時候,Flink還是把records累積起來做批量傳輸的。也可以這麼理解:從傳輸的角度講,Flink是微批處理的

3.1 傳輸機制概述

Flink 的網絡棧是組成 flink-runtime 模塊的核心組件之一,也是 Flink 作業的核心部分。所有來自 TaskManager 的工作單元(子任務)都通過它來互相連接。流式傳輸數據流都要經過網絡棧,所以它對 Flink 作業的性能表現(包括吞吐量和延遲指標)至關重要。與通過 Akka 使用 RPC 的 TaskManager 和 JobManager 之間的協調通道相比,TaskManager 之間的網絡棧依賴的是更底層的,基於 Netty 的 API。

3.2 遠程通信

一個運行的application的tasks在持續交換數據。TaskManager負責做數據傳輸。不同任務之間的每個(遠程)網絡連接將在 Flink 的網絡棧中獲得自己的 TCP 通道。但是如果同一任務的不同子任務被安排到了同一個 TaskManager,則它們與同一個 TaskManager 的網絡連接將被多路復用,並共享一個 TCP 信道以減少資源佔用。

每個TaskManager有一組網絡緩衝池(默認每個buffer是32KB),用於發送與接受數據。如發送端和接收端位於不同的TaskManager進程中,則它們需要通過操作系統的網絡棧進行交流。流應用需要以管道的模式進行數據交換,也就是說,每對TaskManager會維持一個永久的TCP連接用於做數據交換。在shuffle連接模式下(多個sender與多個receiver),每個sender task需要向每個receiver task發送數據,此時TaskManager需要為每個receiver task都分配一個緩衝區。

一個記錄被創建並傳遞之後(例如通過 Collector.collect()),它會被遞交到RecordWriter,其將來自 Java 對象的記錄序列化為一個字節序列,後者最終成為網絡緩存。RecordWriter 首先使用SpanningRecordSerializer將記錄序列化為一個靈活的堆上字節數組。然後它嘗試將這些字節寫入目標網絡通道的關聯網絡緩存。

因為如果逐個發送會降低每個記錄的開銷並帶來更高的吞吐量,所以為了取得高吞吐量,TaskManager的網絡組件首先從緩衝buffer中收集records,然後再發送。也就是說,records並不是一個接一個的發送,而是先放入緩衝,然後再以batch的形式發送。這個技術可以高效使用網絡資源,並達到高吞吐。類似於網絡或磁盤 I/O 協議中使用的緩衝技術。

接收方網絡棧(netty)將接收到的緩存寫入適當的輸入通道。最後(流式)任務的線程從這些隊列中讀取並嘗試在RecordReader的幫助下,通過Deserializer將積累的數據反序列化為 Java 對象。

3.3 TaskManager進程內傳輸

若sender與receiver任務都運行在同一個TaskManager進程,則sender任務會將發送的條目做序列化,並存入一個字節緩衝。然後將緩衝放入一個隊列,直到隊列被填滿。

Receiver任務從隊列中獲取緩衝,並反序列化輸入的條目。所以,在同一個TaskManager內,任務之間的數據傳輸並不經過網絡交互。

在同一個TaskManager進程內,也是批量傳輸

3.4 源碼分析

我們基於Flink優化的結果進行分析驗證,看看Flink是不是把記錄寫入到buffer中,這種情況下運行的是CountingCollector和ChainedMapDriver。

copyFromSerializerToTargetChannel:153, RecordWriter (org.apache.flink.runtime.io.network.api.writer)
emit:116, RecordWriter (org.apache.flink.runtime.io.network.api.writer)
emit:60, ChannelSelectorRecordWriter (org.apache.flink.runtime.io.network.api.writer)
collect:65, OutputCollector (org.apache.flink.runtime.operators.shipping)
collect:35, CountingCollector (org.apache.flink.runtime.operators.util.metrics)
collect:79, ChainedMapDriver (org.apache.flink.runtime.operators.chaining)
collect:35, CountingCollector (org.apache.flink.runtime.operators.util.metrics)
invoke:196, DataSourceTask (org.apache.flink.runtime.operators)
doRun:707, Task (org.apache.flink.runtime.taskmanager)
run:532, Task (org.apache.flink.runtime.taskmanager)
run:748, Thread (java.lang)

當執行完用戶定義的map函數之後,系統運行在 ChainedMapDriver.collect 函數。

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

public void collect(IT record) {
    this.outputCollector.collect(this.mapper.map(record));// mapper就是用戶代碼
}

然後調用到了CountingCollector.collect

public void collect(OUT record) {
		this.collector.collect(record);// record就是用戶轉換后的記錄
}

OutputCollector.collect函數會把記錄發送給所有的writers。

this.delegate.setInstance(record);// 先把record設置到SerializationDelegate中
for (RecordWriter<SerializationDelegate<T>> writer : writers) {  // 所有的writer
   writer.emit(this.delegate); // 發送record
}

RecordWriter負責把數據序列化,然後寫入到緩存中。它有兩個實現類:

  • BroadcastRecordWriter: 維護了多個下游channel,發送數據到下游所有的channel中。
  • ChannelSelectorRecordWriter: 通過channelSelector對象判斷數據需要發往下游的哪個channel。我們用的正是這個RecordWriter

這裏我們分析下ChannelSelectorRecordWriteremit方法:

public void emit(T record) throws IOException, InterruptedException {
   emit(record, channelSelector.selectChannel(record));
}

這裏使用了channelSelector.selectChannel方法。該方法為record尋找到對應下游channel id。

public class OutputEmitter<T> implements ChannelSelector<SerializationDelegate<T>> {
	public final int selectChannel(SerializationDelegate<T> record) {
		switch (strategy) {
		case FORWARD:
			return forward(); // 我們代碼用到了這種情況。這裏 return 0;
    ......
		}
	}
}

接下來我們又回到了父類RecordWriter.emit

protected void emit(T record, int targetChannel) throws IOException, InterruptedException {
   serializer.serializeRecord(record);
   // Make sure we don't hold onto the large intermediate serialization buffer for too long
   if (copyFromSerializerToTargetChannel(targetChannel)) {
      serializer.prune();
   }
}

關鍵的邏輯在於copyFromSerializerToTargetChannel此方法從序列化器中複製數據到目標channel,我們可以看出來,每條記錄都是寫入到buffer中

protected boolean copyFromSerializerToTargetChannel(int targetChannel) throws IOException, InterruptedException {
   // We should reset the initial position of the intermediate serialization buffer before
   // copying, so the serialization results can be copied to multiple target buffers.
   // 此處Serializer為SpanningRecordSerializer
   // reset方法將serializer內部的databuffer position重置為0
   serializer.reset();

   boolean pruneTriggered = false;
    // 獲取目標channel的bufferBuilder
    // bufferBuilder內維護了MemorySegment,即內存片段
    // Flink的內存管理依賴MemorySegment,可實現堆內堆外內存的管理
    // RecordWriter內有一個bufferBuilder數組,長度和下游channel數目相同
    // 該數組以channel ID為下標,存儲和channel對應的bufferBuilder
    // 如果對應channel的bufferBuilder尚未創建,調用requestNewBufferBuilder申請一個新的bufferBuilder  
   BufferBuilder bufferBuilder = getBufferBuilder(targetChannel);
    // 複製serializer的數據到bufferBuilder中
   SerializationResult result = serializer.copyToBufferBuilder(bufferBuilder);
    // 循環直到result完全被寫入到buffer
    // 一條數據可能會被寫入到多個緩存中
    // 如果緩存不夠用,會申請新的緩存
    // 數據完全寫入完畢之時,當前正在操作的緩存是沒有寫滿的
    // 因此返回true,表明需要壓縮該buffer的空間  
   while (result.isFullBuffer()) {
      finishBufferBuilder(bufferBuilder);

      // If this was a full record, we are done. Not breaking out of the loop at this point
      // will lead to another buffer request before breaking out (that would not be a
      // problem per se, but it can lead to stalls in the pipeline).
      if (result.isFullRecord()) {
         pruneTriggered = true;
         emptyCurrentBufferBuilder(targetChannel);
         break;
      }

      bufferBuilder = requestNewBufferBuilder(targetChannel);
      result = serializer.copyToBufferBuilder(bufferBuilder);
   }
   checkState(!serializer.hasSerializedData(), "All data should be written at once");

   // 如果buffer超時時間為0,需要flush目標channel的數據
   if (flushAlways) {
      flushTargetPartition(targetChannel);
   }
   return pruneTriggered;
}

0x04 runtime

4.1 Driver

Driver是Flink runtime的一個重要概念,是在一個task中運行的用戶業務邏輯組件,具體實現了批量操作代碼。其內部API包括初始化,清除,運行,取消等邏輯。

public interface Driver<S extends Function, OT> {
   ......
   void setup(TaskContext<S, OT> context);
   void run() throws Exception;
   void cleanup() throws Exception;
   void cancel() throws Exception;
}

具體在 org.apache.flink.runtime.operators 目錄下,我們能夠看到各種Driver的實現,基本的算子都有自己的Driver。

......
CoGroupDriver.java
FlatMapDriver.java
FullOuterJoinDriver.java
GroupReduceCombineDriver.java
GroupReduceDriver.java
JoinDriver.java
LeftOuterJoinDriver.java
MapDriver.java
MapPartitionDriver.java
......

4.2 MapDriver

map算子對應的就是MapDriver。

結合上節我們知道,上游數據是通過batch方式批量傳入的。所以,在run函數會遍歷輸入,每次取出一個record,然後調用用戶自定義函數function.map對這個record做map操作。

public class MapDriver<IT, OT> implements Driver<MapFunction<IT, OT>, OT> {

   @Override
   public void run() throws Exception {
      final MutableObjectIterator<IT> input = this.taskContext.getInput(0);
      .....
      else {
         IT record = null;
        
         // runtime主動進行循環,這樣導致大量函數調用
         while (this.running && ((record = input.next()) != null)) {
            numRecordsIn.inc();
            output.collect(function.map(record)); // function是用戶函數
         }
      }
   }
}

4.3 MapPartitionDriver

MapPartitionDriver是mapPartition的具體組件。系統會把得到的批量數據inIter一次性的都傳給用戶自定義函數,由用戶代碼來進行遍歷操作

public class MapPartitionDriver<IT, OT> implements Driver<MapPartitionFunction<IT, OT>, OT> {
   @Override
   public void run() throws Exception {
     
		final MutableObjectIterator<IT> input = new CountingMutableObjectIterator<>(this.taskContext.<IT>getInput(0), numRecordsIn);     
      ......
      } else {
         final NonReusingMutableToRegularIteratorWrapper<IT> inIter = new NonReusingMutableToRegularIteratorWrapper<IT>(input, this.taskContext.<IT>getInputSerializer(0).getSerializer());

         // runtime不參与循環,這樣可以減少函數調用
         function.mapPartition(inIter, output);
      }
   }
}

4.4 效率區別

我們能夠看到map和mapPartition的input都是MutableObjectIterator input類型, 說明兩者的輸入一致。只不過map是在Driver代碼中進行循環,mapPartition在用戶代碼中進行循環。具體mapPartition的 效率提高體現在如下方面 :

  1. 假設一共有60個數據需要轉換,map會在runtime中調用用戶函數60次。
  2. runtime把數據分成6個partition操作,則mapPartition在runtime中會調用用戶函數6次,在每個用戶函數中分別循環10次。對於runtime來說,map操作會多出54次用戶函數調用。
  3. 如果用戶業務中需要頻繁創建額外的對象或者外部資源操作,mapPartition的優勢更可以體現。 例如將數據寫入Mysql, 那麼map需要為每個元素創建一個數據庫連接,而mapPartition為每個partition創建一個鏈接。

假設有上億個數據需要map,這資源佔用和運行速度效率差別會相當大。

0x05 優化和ChainedMapDriver

之前提到了優化,這裏我們再詳細深入下如何優化map算子。

Flink有一個關鍵的優化技術稱為任務鏈,用於(在某些情況下)減少本地通信的過載。為了滿足任務鏈的條件,至少兩個以上的operator必須配置為同一併行度,並且使用本地向前的(local forwad)方式連接。任務鏈可以被認為是一種管道。

當管道以任務鏈的方式執行時候,Operators的函數被融合成單個任務,並由一個單獨的線程執行。一個function產生的records,通過使用一個簡單的方法調用,被遞交給下一個function。所以這裡在方法之間的records傳遞中,基本沒有序列化以及通信消耗

針對優化后的Operator Chain,runtime對應的Driver則是ChainedMapDriver。這是通過 MAP(MapDriver.class, ChainedMapDriver.class, PIPELINED, 0), 映射得到的。

我們可以看到,因為是任務鏈,所以每個record是直接在管道中流淌 ,ChainedMapDriver連循環都省略了,直接map轉換后丟給下游去也

public class ChainedMapDriver<IT, OT> extends ChainedDriver<IT, OT> {

   private MapFunction<IT, OT> mapper; // 用戶函數

   @Override
   public void collect(IT record) {
      try {
         this.numRecordsIn.inc();
         this.outputCollector.collect(this.mapper.map(record));
      } catch (Exception ex) {
         throw new ExceptionInChainedStubException(this.taskName, ex);
      }
   }
}

// 這時的調用棧如下
map:23, UserFunc$1 (com.alibaba.alink)
collect:79, ChainedMapDriver (org.apache.flink.runtime.operators.chaining)
collect:35, CountingCollector (org.apache.flink.runtime.operators.util.metrics)
invoke:196, DataSourceTask (org.apache.flink.runtime.operators)
doRun:707, Task (org.apache.flink.runtime.taskmanager)
run:532, Task (org.apache.flink.runtime.taskmanager)
run:748, Thread (java.lang)

0x06 總結

map和mapPartition實現的基礎是Flink的數據傳輸機制 :Flink確實是每次都處理一個輸入record,但是在上下游之間傳輸時候,Flink還是把records累積起來做批量傳輸。即可以認為從數據傳輸模型角度講,Flink是微批次的。

對於數據流轉換,因為是批量傳輸,所以對於積累的records,map是在runtime Driver代碼中進行循環,mapPartition在用戶代碼中進行循環。

map的函數調用次數要遠高於mapPartition。如果在用戶函數中涉及到頻繁創建額外的對象或者外部資源操作,則mapPartition性能遠遠高出。

如果沒有connection之類的操作,則通常性能差別並不大,通常不會成為瓶頸,也沒有想象的那麼嚴重。

0x07 參考

深入了解 Flink 網絡棧 ——A Deep-Dive into Flink’s Network Stack

Flink架構(二)- Flink中的數據傳輸

Flink 源碼之節點間通信

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

面試官問我會不會Elasticsearch,我語塞了…_網頁設計公司

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

少點代碼,多點頭髮

本文已經收錄至我的GitHub,歡迎大家踴躍star 和 issues。

https://github.com/midou-tech/articles

從今天開始準備給大家帶來全新的一系列文章,Elasticsearch系列

新系列肯定會有很多疑惑,先為大家答疑解惑,下面是今天要講的問題

為什麼寫Elasticsearch系列文章?

之前在文章中也陸陸續續的提到過,龍叔是做搜索引擎的。搜索引擎技術屬於商業技術,大家耳熟能詳的百度搜索,Google搜索,這可都是因為把握核心搜索技術,從而誕生了商業帝國。

每個互聯網大廠都想去分一杯搜索的羹,360搜索、神馬、頭條、搜狗搜索等等,由此可見搜索技術的商業作用和機密性了。

搜索把握用戶的入口

蘑菇街的搜索引擎是一款使用C++開發、完全自研、沒有開源的搜索引擎,沒有開源就是不能隨便寫出來的。

但是現在不一樣了

第一、我離職了,離開了意味着不在持有那些商業機密了,就算不講出來我也沒啥心理負擔(但還是不能講的,離職協議寫的很清楚,不能泄露公司商業機密)。

第二、去新的公司還是在搜索領域,他們用Es Elasticsearch是一個開源搜索,開源的東西可以隨便說,但還是不能說公司的商業數據

自己一直在搜索領域做,輸出搜索相關的文章,第一個可以讓自己更好的學習和總結,第二個可以讓粉絲們了解到搜索這個神秘的技術,增加大家自身的核心競爭力。

後面會說到,Elasticsearch是搜索引擎,但不簡單隻能使用在搜索領域,他可以作用的場景非常多。

Elasticsearch是什麼?

Elasticsearch 是一個分佈式的開源搜索分析引擎,適用於所有類型的數據,包括文本、数字、地理空間、結構化和非結構化數據。

Elasticsearch 在 Apache Lucene 的基礎上開發而成,Elasticsearch 以其簡單的 REST 風格 API、分佈式特性、速度和可擴展性而聞名,是 Elastic Stack 的核心組件。

Elastic Stack 是適用於數據採集、充實、存儲、分析和可視化的一組開源工具。人們通常將 Elastic Stack 稱為 ELK Stack(代指 Elasticsearch、Logstash 和 Kibana),目前 Elastic Stack 包括一系列豐富的輕量型數據採集代理,這些代理統稱為 Beats,可用來向 Elasticsearch 發送數據。

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

Elasticsearch 的實現原理主要分為以下幾個步驟,首先用戶將數據提交到Elasticsearch 數據中心,再通過分詞控制器去將對應的數據分詞,將其權重和分詞結果一併存入數據,當用戶搜索數據時候,再根據權重將結果排名,打分,再將返回結果呈現給用戶。

是什麼差不多搞清楚了,再說說ES都哪些成熟的應用以及在哪些領域使用。

Elasticsearch在哪些領域使用?

  • 應用程序搜索
  • 網站搜索
  • 企業搜索
  • 日誌處理和分析
  • 基礎設施指標和容器監測
  • 應用程序性能監測
  • 地理空間數據分析和可視化
  • 安全分析
  • 業務分析

Elasticsearch有哪些特點?

Elasticsearch 很快。 由於 Elasticsearch 是在 Lucene 基礎上構建而成的,所以在全文本搜索方面表現十分出色。Elasticsearch 同時還是一個近實時的搜索平台,這意味着從文檔索引操作到文檔變為可搜索狀態之間的延時很短,一般只有一秒。因此,Elasticsearch 非常適用於對時間有嚴苛要求的用例,例如安全分析和基礎設施監測。

Elasticsearch 具有分佈式的本質特徵。 Elasticsearch 中存儲的文檔分佈在不同的容器中,這些容器稱為分片,可以進行複製以提供數據冗餘副本,以防發生硬件故障。Elasticsearch 的分佈式特性使得它可以擴展至數百台(甚至數千台)服務器,並處理 PB 量級的數據。

Elasticsearch 包含一系列廣泛的功能。 除了速度、可擴展性和彈性等優勢以外,Elasticsearch 還有大量強大的內置功能(例如數據匯總和索引生命周期管理),可以方便用戶更加高效地存儲和搜索數據。

Elastic Stack 簡化了數據採集、可視化和報告過程。 通過與 Beats 和 Logstash 進行集成,用戶能夠在向 Elasticsearch 中索引數據之前輕鬆地處理數據。同時,Kibana 不僅可針對 Elasticsearch 數據提供實時可視化,同時還提供 UI 以便用戶快速訪問應用程序性能監測 (APM)、日誌和基礎設施指標等數據。

學習Elasticsearch能提高哪些競爭力?

看到Elasticsearch在這麼多的領域在使用,特點也這麼明顯。看到這裏估計都不用在說什麼核心競爭力,你已經意識到了。

Elastic 於 2018 年 6 月 29 日正式推出 Elastic Certified Engineer 認證考試,認證通過可以獲得官方頒發的證書和徽章,title就是 Elastic認證工程師

具體認證的細節和含金量,沒有具體研究過,但是可以很明顯的感受到官方出了這樣一個認證,表明社會需要大量這樣的人才,而這方面人才的培養和考核指標還欠缺。

有沒有必要一定要考這個認證?

個人覺得,和英語四六級一樣,通過了再說沒用。

如果你是學生,可以考慮去考一個認證,因為你很難有業務場景驅使你去做這方面的成長,認證一定是有難度的,一個一個的困難會驅使你成長,最終這個認證也會成為招聘時一個非常大的亮點。

這個認證會有哪些幫助?

  • 對於快速的構建知識體系幫助。

  • 對於全面的熟悉官方文檔幫助。

  • 對於實戰解決線上問題幫助。(遇到了相關技術問題基本上不需要再求助於社區,80%以上的問題自己基本就能解決。)

  • 對於增強信心、克服英文恐懼幫助。

Elasticsearch 支持哪些編程語言?

  • Java
  • JavaScript (Node.js)
  • Go
  • .NET (C#)
  • PHP
  • Perl
  • Python
  • Ruby

哪裡可以找到有關 Elasticsearch 的更多信息?

  • Elasticsearch GitHub 存儲庫:https://github.com/elastic
  • Elasticsearch 官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
  • Elasticsearch中文社區:https://elasticsearch.cn

我是龍叔,一個分享互聯網技術和心路歷程的star。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

國外網友結合二手健身車與任天堂健身環等設備,組出了一台可以邊運動邊玩「瑪利歐賽車」的鍛鍊神器_貨運

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

瑪利歐賽車是任天堂旗下的人氣遊戲,很多玩家喜歡它豐富的賽道設計,每場比賽中隨機刷出的道具更是給賽事增添不少勝負變數。小到香蕉皮,大到無敵星星,各種道具不但促進了瑪利歐賽車系列的大賣,也不知道撕破了多少人之間的友誼。今天不是要告訴大家瑪利歐賽車的必勝方法。而是介紹一個玩膩《健身環大冒險》,於是用一點小工具跟改裝技巧,土砲出了健身環版瑪利歐賽車專用套件的神人。用這個套件玩《瑪車》未必能讓你百戰百勝,但能讓你邊玩邊消耗熱量,甚至達到健身減重的效果:

▲(圖片翻攝自 Youtube 影片)

瑪利歐賽車系列遊戲打從超任時代就開始風靡許多大小朋友,這系列遊戲有多好玩自然不需要筆者多做介紹。歷經數年演變,畫面也從 2D、3D 到現在高畫質畫面,稱得上是任天堂的一大台柱。很多人購買 Switch 主機以後,往往也會順便來一片《瑪利歐賽車 8 Deluxe》來跟家人朋友同樂,是一款相當適合多人競技的遊戲。

有了健身環,瑪利歐賽車也可以拿來運動

在任天堂推出 Wii 主機以後,體感控制就成為許多新遊戲開創新玩法的靈感來源。從 Wii 推出的時代就有許多運動或競技相關的遊戲採用了體感操控。像是 2006 年推出的 Wii Sport、2007 年的 Wii Fit、2019 對應新主機 Switch 推出的健身環與健身環大冒險遊戲,這些遊戲都顯示運動類遊戲成為任天堂開創新玩法的重要領域。不過,這些遊戲通常都有個缺點,就是綁定的某些套件,例如健身環大冒險之於任天堂健身環。這些套件通常也無法對應到其他遊戲的玩法上。於是一位玩家就跳出來替任天堂健身環進行了一點小小的改造,搭配一台二手健身車,組合成讓人一邊運動一邊玩瑪利歐賽車的新套件「Labo Fit Adventure Kart」:

▲健身環、手把跟改裝過的二手健身車,組成了這個奇妙的健身套件(圖片翻攝自 Youtube 影片)

這套或可取名為「Labo 健身賽車冒險」的套件組合了一個健身環,一個 Switch 手把和一台二手健身車。主要的邏輯是讓健身環、健身車的操控能夠對應到 Switch 手把按鍵上,才能利用這組套件來進行有系。這位名為「Mike Choi(@mechachoi)」的國外網友就利用了自製的裝置「TAPBO」來成為溝通這些裝備的橋樑,最後讓這些裝置能成為玩家的手與腳。一邊進行著遊戲的同時,一邊還可以鍛鍊身體。既能避免沉迷遊戲,還能夠減少身上贅肉,一舉兩得:

▲TAPBO套件主要用處就是接收訊號以控制手把(圖片翻攝自 Youtube 影片)

Mike Choi 網友透過瑪利歐賽車這個遊戲做為示範,來展示自己組裝起來的「Labo Fit Adventure Kart」。簡單的說,使用者必須腳踏健身車來讓遊戲中的卡丁車加速。利用健身環做為虛擬的方向盤轉動卡丁車的前輪。至於瑪利歐賽車中重要的道具發射功能,則是透過擠壓健身環來達成。這些動作說明起來很簡單。但要一邊運動一邊在遊戲中進行排位的攻防,並不是一件簡單的事。若真能靠這個方式成為瑪利歐賽車大師,想必體脂率也大幅降低了不少:

▲作者在自己的推特上宣傳自作套件,吸引不少網友轉推(圖片翻攝自 Twitter 網頁)

▲一邊騎車讓卡丁車加速,一邊控制方向盤(健身環),一邊還得透過擠壓健身環放道具(圖片翻攝自 Youtube 影片)

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

Mike Choi 網友也在自己的套件介紹影片中說明了製造流程。就概念來說相信有點電機底子的人都不會覺得太難,只是難在要用這個方式真的在遊戲中跟親友競爭,取勝的機率相對低落的多。Mike Choi 網友甚至還試著玩了一下另一款任天堂的旗下大作「任天堂明星大亂鬥特別版」,從影片中看起來的確不是普通的累。對於有心想健身或減肥的人,藉著遊戲持之以恆的話,說不定真的能有所成效也說不定:

▲連大亂鬥也支援,不過這樣玩直的很累(圖片翻攝自 Youtube 影片)

▲可惜的是他這套純手工健身器材尚未販售,不過這個點子應該會吸引健身器材大廠或是任天堂尋求合作才是(圖片翻攝自 Youtube 影片)

消息來源

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。