少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

          2017年12月24日 #

               摘要: 前陣子從支付寶轉(zhuǎn)賬1萬塊錢到余額寶,這是日常生活的一件普通小事,但作為互聯(lián)網(wǎng)研發(fā)人員的職業(yè)病,我就思考支付寶扣除1萬之后,如果系統(tǒng)掛掉怎么辦,這時余額寶賬戶并沒有增加1萬,數(shù)據(jù)就會出現(xiàn)不一致狀況了。上述場景在各個類型的系統(tǒng)中都能找到相似影子,比如在電商系統(tǒng)中,當(dāng)有用戶下單后,除了在訂單表插入一條記錄外,對應(yīng)商品表的這個商品數(shù)量必須減1吧,怎么保證?!在搜索廣告系統(tǒng)中,當(dāng)用戶點擊某廣告后,除了在點擊...  閱讀全文
          posted @ 2018-01-04 00:01 abin 閱讀(724) | 評論 (0)編輯 收藏

          微服務(wù)架構(gòu)采用Scale Cube方法設(shè)計應(yīng)用架構(gòu),將應(yīng)用服務(wù)按功能拆分成一組相互協(xié)作的服務(wù)。每個服務(wù)負(fù)責(zé)一組特定、相關(guān)的功能。每個服務(wù)可以有自己獨立的數(shù)據(jù)庫,從而保證與其他服務(wù)解耦。
          微服務(wù)優(yōu)點
          1、通過分解巨大單體式應(yīng)用為多個服務(wù)方法解決了復(fù)雜性問題,每個微服務(wù)相對較小
          2、每個單體應(yīng)用不局限于固定的技術(shù)棧,開發(fā)者可以自由選擇開發(fā)技術(shù),提供API服務(wù)。
          3、每個微服務(wù)獨立的開發(fā),部署
          4、單一職責(zé)功能,每個服務(wù)都很簡單,只關(guān)注于一個業(yè)務(wù)功能
          5、易于規(guī)模化開發(fā),多個開發(fā)團(tuán)隊可以并行開發(fā),每個團(tuán)隊負(fù)責(zé)一項服務(wù)
          6、改善故障隔離。一個服務(wù)宕機(jī)不會影響其他的服務(wù)
          微服務(wù)缺點:
          1.開發(fā)者需要應(yīng)對創(chuàng)建分布式系統(tǒng)所產(chǎn)生的額外的復(fù)雜因素
          l  目前的IDE主要面對的是單體工程程序,無法顯示支持分布式應(yīng)用的開發(fā)
          l  測試工作更加困難
          l  需要采用服務(wù)間的通訊機(jī)制
          l  很難在不采用分布式事務(wù)的情況下跨服務(wù)實現(xiàn)功能
          l  跨服務(wù)實現(xiàn)要求功能要求團(tuán)隊之間的緊密協(xié)作
          2.部署復(fù)雜
          3.內(nèi)存占用量更高
          posted @ 2017-12-31 16:41 abin 閱讀(426) | 評論 (0)編輯 收藏

          JDK 的 HashMap 中使用了一個 hash 方法來做 bit shifting,在注釋中說明是為了防止一些實現(xiàn)比較差的hashCode() 方法,請問原理是什么?JDK 的源碼參見:GrepCode: java.util.HashMap (.java)
          /**
           * Applies a supplemental hash function to a given hashCode, which
           * defends against poor quality hash functions.  This is critical
           * because HashMap uses power-of-two length hash tables, that
           * otherwise encounter collisions for hashCodes that do not differ
           * in lower bits. Note: Null keys always map to hash 0, thus index 0.
           */
          static int hash(int h) {
              // This function ensures that hashCodes that differ only by
              // constant multiples at each bit position have a bounded
              // number of collisions (approximately 8 at default load factor).
              h ^= (h >>> 20) ^ (h >>> 12);
              return h ^ (h >>> 7) ^ (h >>> 4);
          }
          PS:網(wǎng)上看見有人說作者本人說原理需要參見圣經(jīng)《計算機(jī)程序設(shè)計藝術(shù)》的 Vol.3 里頭的介紹,不過木有看過神書,求達(dá)人介紹





          這段代碼叫“擾動函數(shù)”。
          題主貼的是Java 7的HashMap的源碼,Java 8中這步已經(jīng)簡化了,只做一次16位右位移異或混合,而不是四次,但原理是不變的。下面以Java 8的源碼為例解釋,

          //Java 8中的散列值優(yōu)化函數(shù)staticfinalinthash(Objectkey){inth;return(key==null)?0:(h=key.hashCode())^(h>>>16);//key.hashCode()為哈希算法,返回初始哈希值}
          大家都知道上面代碼里的key.hashCode()函數(shù)調(diào)用的是key鍵值類型自帶的哈希函數(shù),返回int型散列值。理論上散列值是一個int型,如果直接拿散列值作為下標(biāo)訪問HashMap主數(shù)組的話,考慮到2進(jìn)制32位帶符號的int表值范圍從-2147483648到2147483648。前后加起來大概40億的映射空間。只要哈希函數(shù)映射得比較均勻松散,一般應(yīng)用是很難出現(xiàn)碰撞的。但問題是一個40億長度的數(shù)組,內(nèi)存是放不下的。你想,HashMap擴(kuò)容之前的數(shù)組初始大小才16。所以這個散列值是不能直接拿來用的。用之前還要先做對數(shù)組的長度取模運算,得到的余數(shù)才能用來訪問數(shù)組下標(biāo)。源碼中模運算是在這個indexFor( )函數(shù)里完成的。

          bucketIndex = indexFor(hash, table.length);indexFor的代碼也很簡單,就是把散列值和數(shù)組長度做一個"與"操作,

          static int indexFor(int h, int length) {        return h & (length-1);}順便說一下,這也正好解釋了為什么HashMap的數(shù)組長度要取2的整次冪。因為這樣(數(shù)組長度-1)正好相當(dāng)于一個“低位掩碼”。“與”操作的結(jié)果就是散列值的高位全部歸零,只保留低位值,用來做數(shù)組下標(biāo)訪問。以初始長度16為例,16-1=15。2進(jìn)制表示是00000000 00000000 00001111。和某散列值做“與”操作如下,結(jié)果就是截取了最低的四位值。
          10100101 11000100 00100101& 00000000 00000000 00001111---------------------------------- 00000000 00000000 00000101    //高位全部歸零,只保留末四位
          但這時候問題就來了,這樣就算我的散列值分布再松散,要是只取最后幾位的話,碰撞也會很嚴(yán)重。更要命的是如果散列本身做得不好,分布上成等差數(shù)列的漏洞,恰好使最后幾個低位呈現(xiàn)規(guī)律性重復(fù),就無比蛋疼。這時候“擾動函數(shù)”的價值就體現(xiàn)出來了,說到這里大家應(yīng)該猜出來了。看下面這個圖,


          右位移16位,正好是32bit的一半,自己的高半?yún)^(qū)和低半?yún)^(qū)做異或,就是為了混合原始哈希碼的高位和低位,以此來加大低位的隨機(jī)性。而且混合后的低位摻雜了高位的部分特征,這樣高位的信息也被變相保留下來。最后我們來看一下PeterLawley的一篇專欄文章《An introduction to optimising a hashing strategy》里的的一個實驗:他隨機(jī)選取了352個字符串,在他們散列值完全沒有沖突的前提下,對它們做低位掩碼,取數(shù)組下標(biāo)。


          結(jié)果顯示,當(dāng)HashMap數(shù)組長度為512的時候,也就是用掩碼取低9位的時候,在沒有擾動函數(shù)的情況下,發(fā)生了103次碰撞,接近30%。而在使用了擾動函數(shù)之后只有92次碰撞。碰撞減少了將近10%。看來擾動函數(shù)確實還是有功效的。但明顯Java 8覺得擾動做一次就夠了,做4次的話,多了可能邊際效用也不大,所謂為了效率考慮就改成一次了。
          ------------------------------------------------------








          https://www.zhihu.com/question/20733617



          posted @ 2017-12-24 22:38 abin 閱讀(455) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 集贤县| 洛南县| 屏山县| 中宁县| 巧家县| 连山| 公主岭市| 泾川县| 珲春市| 江山市| 漳州市| 襄汾县| 大安市| 新民市| 大港区| 基隆市| 美姑县| 达州市| 桐城市| 宁夏| 蓬莱市| 汤原县| 南溪县| 双鸭山市| 河东区| 长顺县| 阜新市| 贵港市| 定襄县| 仙桃市| 霍林郭勒市| 九龙县| 孝义市| 乾安县| 蒙城县| 灵璧县| 临海市| 广德县| 朝阳市| 镇沅| 安宁市|