精华内容
下载资源
问答
  • 如果给你一个亿,你想怎么花? 这个问题想必很多人都想过,中彩票,中一个大奖!拿一个亿就可以花天酒地潇洒无比了对吧? 网友们的回帖也是有意思得很,想大肆挥霍一把体验一下富二代生活的、想买房买车辞去工作...

    今天看到一个挺有意思的帖子:

    在这里插入图片描述

    如果给你一个亿,你想怎么花?

    这个问题想必很多人都想过,中彩票,中一个大奖!拿一个亿就可以花天酒地潇洒无比了对吧?

    网友们的回帖也是有意思得很,有想大肆挥霍一把体验一下富二代生活的、有想买房买车辞去工作从此逍遥人生的、有想买下一座无人岛和足够的生活用品隐居的、还有把自己的财富分配妥当拿出一部分理财的…

    如果是你,你炒币赚了一个亿,你会怎么样?是继续加仓享受刺激的博弈生活?还是清仓享受美好人生?

    其中,我看到了一篇这样的回帖:

    在这里插入图片描述

    我想大多数人应该对一亿和一千万来说没什么概念,但如果你真的拿到一个亿,一天花3000块钱,一个月花10万块钱,可以持续用1000个月,足足83年的时间!

    这83年的时间足够大多数的人用到去世的那一天!

    想想还真是这样,一个月10万的花销,足够支付大部分的生活开支和娱乐活动了,我们工作是为了赚钱,赚钱是为了过上更好的生活,为了给家人更舒适的生活环境,那有了一个亿之后不就可以过上想要的生活,完全不用工作了吗?

    在这里插入图片描述

    但是现实可能并没有这么美好。

    我们经常会有这样的感觉:工资没怎么涨,物价却一直在涨,钱越来越不禁花了。十年前我买一杯奶茶只需要两三块钱,现在的一杯奶茶动辄十几块,贵的甚至好几十,那这中间是什么问题在作祟?

    答案是通货膨胀。

    我们每年都会保持一定比率的通货膨胀率。经济学上,通货膨胀率为:物价平均水平的上升幅度。举个例子,如果通货膨胀率为2%,那么假设你今年100块钱可以买一杯奶茶,那么明年买同样的一杯奶茶就需要花102块钱。也就是说,你的钱的购买力在不断下降。

    根据数据,目前中国的通货膨胀率年均值就是在2%左右。

    在这里插入图片描述

    那如果按照这个数据,一个亿的钱在10年后的购买力会是多少呢?

    通货膨胀率计算公式:

    通货膨胀率(价格上涨率)=(已发行的货币量-流通中实际所需要的货币量)÷流通中实际所需要的货币量×100%

    为了方便理解,我们将这个长公式转换的通俗一点:

    C×(1+X)n=Z

    其中,C表示现有本金,X为通货膨胀率,n为年数,Z表示为本金C经过n年后与之相同的购买力需要的资金数。

    举个例子,你现在有本金C 10块钱,刚好可以买一杯奶茶,如果现在的通货膨胀率X为2%,那么1年后,你就需要花费Z 10.2块钱才能买到一杯奶茶,2年后就需要10.404块钱。

    看过我的文章《巴菲特的复利思维》的同学应该明白,出现了上角标,就意味着这个公式已经具有复利的恐怖效果了,我们来看看几年后如果你想要有现在一个亿的购买力,你需要多少钱:

    1年后,你需要102000000才能买到现在价值一个亿的东西;

    5年后,你需要110808080才能买到现在价值一个亿的东西;

    10年后,你需要121899441才能买到现在价值一个亿的东西;

    35年后,你需要200000000才能买到现在价值一个亿的东西。

    也就是说,如果你的一个亿放着不花,35年后它就只能买到现在只要花5000万就能买到的东西。

    在这里插入图片描述

    所以我是在建议你现在就把钱花掉?不要留着贬值?

    当然不是!

    这里要讲到非常有意思的穷人思维和富人思维,灵感来自于《富爸爸穷爸爸》一书,作者是罗伯特·清崎。

    其中内容我就不过多赘述,作者用穷爸爸和富爸爸处事的不同思路讲述了穷人思维与富人思维的区别:

    书中的两位爸爸是作者现实生活中的两位“父亲”,一位是高学历且有稳定工作的生父,一位是初中学历却经商多年的邻居玩伴的父亲。需要注意的是,作者区分两位父亲“穷”与“富”的区别并不是因为他们的资产,而是思维。

    当两位父亲遇到心仪却又昂贵的物品时,穷爸爸会说:“这太贵了,我买不起。”富爸爸则会说:“这东西很不错,但很贵,我要怎么才能买到它?”

    穷爸爸习惯于讲陈述句,买不起就是买不起,他习惯性的放弃了思考和努力。而富爸爸则习惯用疑问句,他会因为想得到这件商品而去想办法,他在积极主动的去寻找解决方案。

    在这里插入图片描述

    长此以往,穷爸爸在遇到金钱的问题是不断地逃避,也就越来越穷,安于现状。富爸爸则因为习惯性的想办法解决问题,所以他创造财富的能力越来越强。

    穷爸爸因为思维的局限,不给自己创造更多地可能,他的思维是贫穷的,他在遇到问题的时候习惯性的否定自己,即使收入稳定但也再无更多可能。

    富爸爸因为总是想方设法解决问题,创造出了更多地可能,于是他的企业越做越大,未来发展的可能性也越来越多。

    而导致他们金钱观相差如此之大的原因,被作者称之为区别于于智商与情商的“财商”。

    回到我们一开始的问题,如果你炒币赚了一个亿,你会怎么花?

    你是会像穷爸爸一样赶紧存起来,慢慢规划着花?还是像富爸爸一样用这笔钱创造更多地可能?

    在下方评论区留下你的想法,我们一起来探讨吧。

    好了今天的《区块链方法论》就到这了,我的内容首发平台是在“区块链倪老师”微信公众号,同时你也可以在各大平台搜索“区块链方法论”以获得最新内容。

    展开全文
  • 现在我给你一个数,你需要告诉我它是否存在其中(尽量高效)。 需求其实很清晰,只是要判断一个数据是否存在即可。但这里一个比较重要的前提:非常庞大的数据。   常规实现   先不考虑这个条件,我们脑海中...

    现在有一个非常庞大的数据,假设全是 int 类型。现在我给你一个数,你需要告诉我它是否存在其中(尽量高效)。

    需求其实很清晰,只是要判断一个数据是否存在即可。但这里有一个比较重要的前提:非常庞大的数据。

     

    常规实现

     

    先不考虑这个条件,我们脑海中出现的第一种方案是什么?我想大多数想到的都是用 HashMap 来存放数据,因为它的写入查询的效率都比较高。

     

    写入和判断元素是否存在都有对应的 API,所以实现起来也比较简单。

     

    为此我写了一个单测,利用 HashSet 来存数据(底层也是 HashMap );同时为了后面的对比将堆内存写死:

        -Xms64m -Xmx64m -XX:+PrintHeapAtGC -XX:+HeapDumpOnOutOfMemoryError 

    为了方便调试加入了 GC 日志的打印,以及内存溢出后 Dump 内存。

     @Test
    
        public void hashMapTest(){
    
            long star = System.currentTimeMillis();
    
    
            Set<Integer> hashset = new HashSet<>(100) ;
    
            for (int i = 0; i < 100; i++) {
    
                hashset.add(i) ;
    
            }
    
            Assert.assertTrue(hashset.contains(1));
    
            Assert.assertTrue(hashset.contains(2));
    
            Assert.assertTrue(hashset.contains(3));
    
    
            long end = System.currentTimeMillis();
    
            System.out.println("执行时间:" + (end - star));
    
        }

    当我只写入 100 条数据时自然是没有问题的。

     

    还是在这个基础上,写入 1000W 数据试试:

    执行后马上就内存溢出。

     

    可见在内存有限的情况下我们不能使用这种方式。

     

    实际情况也是如此;既然要判断一个数据是否存在于集合中,考虑的算法的效率以及准确性肯定是要把数据全部 load 到内存中的。

     

    Bloom Filter

     

    基于上面分析的条件,要实现这个需求最需要解决的是 如何将庞大的数据load到内存中。

     

    而我们是否可以换种思路,因为只是需要判断数据是否存在,也不是需要把数据查询出来,所以完全没有必要将真正的数据存放进去。

     

    伟大的科学家们已经帮我们想到了这样的需求。

     

    BurtonHowardBloom 在 1970 年提出了一个叫做 BloomFilter(中文翻译:布隆过滤)的算法。

     

    它主要就是用于解决判断一个元素是否在一个集合中,但它的优势是只需要占用很小的内存空间以及有着高效的查询效率。所以在这个场景下在合适不过了。

     

    Bloom Filter 原理

     

    下面来分析下它的实现原理。

    官方的说法是:它是一个保存了很长的二级制向量,同时结合 Hash 函数实现的。

     

    听起来比较绕,但是通过一个图就比较容易理解了。

     

    如图所示:

    • 首先需要初始化一个二进制的数组,长度设为 L(图中为 8),同时初始值全为 0 。

    • 当写入一个 A1=1000 的数据时,需要进行 H 次 hash 函数的运算(这里为 2 次);与 HashMap 有点类似,通过算出的 HashCode 与 L 取模后定位到 0、2 处,将该处的值设为 1。

    • A2=2000 也是同理计算后将 4、7 位置设为 1。

    • 当有一个 B1=1000 需要判断是否存在时,也是做两次 Hash 运算,定位到 0、2 处,此时他们的值都为 1 ,所以认为 B1=1000 存在于集合中。

    • 当有一个 B2=3000 时,也是同理。第一次 Hash 定位到 index=4 时,数组中的值为 1,所以再进行第二次 Hash 运算,结果定位到 index=5 的值为 0,所以认为 B2=3000 不存在于集合中。

     

    整个的写入、查询的流程就是这样,汇总起来就是:

    对写入的数据做 H 次 hash 运算定位到数组中的位置,同时将数据改为1.当有数据查询时也是同样的方式定位到数组中。 一旦其中的有一位为 0 则认为数据肯定不存在于集合,否则数据可能存在于集合中。

     

    所以布隆过滤有以下几个特点:

    1. 只要返回数据不存在,则肯定不存在。

    2. 返回数据存在,但只能是大概率存在。

    3. 同时不能清除其中的数据。

     

    第一点应该都能理解,重点解释下 2、3 点。

     

    为什么返回存在的数据却是可能存在呢,这其实也和 HashMap 类似。在有限的数组长度中存放大量的数据,即便是再完美的 Hash 算法也会有冲突,所以有可能两个完全不同的 A、B 两个数据最后定位到的位置是一模一样的。

     

    这时拿 B 进行查询时那自然就是误报了。

     

    删除数据也是同理,当我把 B 的数据删除时,其实也相当于是把 A 的数据删掉了,这样也会造成后续的误报。

     

    基于以上的 Hash 冲突的前提,所以 BloomFilter 有一定的误报率,这个误报率和 Hash算法的次数 H,以及数组长度 L 都是有关的。

     

    自己实现一个布隆过滤

     

    算法其实很简单不难理解,于是利用 Java 实现了一个简单的雏形。

        public class BloomFilters {
    
    
            /**
    
             * 数组长度
    
             */
    
            private int arraySize;
    
    
            /**
    
             * 数组
    
             */
    
            private int[] array;
    
    
            public BloomFilters(int arraySize) {
    
                this.arraySize = arraySize;
    
                array = new int[arraySize];
    
            }
    
    
            /**
    
             * 写入数据
    
             * @param key
    
             */
    
            public void add(String key) {
    
                int first = hashcode_1(key);
    
                int second = hashcode_2(key);
    
                int third = hashcode_3(key);
    
    
                array[first % arraySize] = 1;
    
                array[second % arraySize] = 1;
    
                array[third % arraySize] = 1;
    
    
            }
    
    
            /**
    
             * 判断数据是否存在
    
             * @param key
    
             * @return
    
             */
    
            public boolean check(String key) {
    
                int first = hashcode_1(key);
    
                int second = hashcode_2(key);
    
                int third = hashcode_3(key);
    
    
                int firstIndex = array[first % arraySize];
    
                if (firstIndex == 0) {
    
                    return false;
    
                }
    
    
                int secondIndex = array[second % arraySize];
    
                if (secondIndex == 0) {
    
                    return false;
    
                }
    
    
                int thirdIndex = array[third % arraySize];
    
                if (thirdIndex == 0) {
    
                    return false;
    
                }
    
    
                return true;
    
    
            }
    
    
    
            /**
    
             * hash 算法1
    
             * @param key
    
             * @return
    
             */
    
            private int hashcode_1(String key) {
    
                int hash = 0;
    
                int i;
    
                for (i = 0; i < key.length(); ++i) {
    
                    hash = 33 * hash + key.charAt(i);
    
                }
    
                return Math.abs(hash);
    
            }
    
    
            /**
    
             * hash 算法2
    
             * @param data
    
             * @return
    
             */
    
            private int hashcode_2(String data) {
    
                final int p = 16777619;
    
                int hash = (int) 2166136261L;
    
                for (int i = 0; i < data.length(); i++) {
    
                    hash = (hash ^ data.charAt(i)) * p;
    
                }
    
                hash += hash << 13;
    
                hash ^= hash >> 7;
    
                hash += hash << 3;
    
                hash ^= hash >> 17;
    
                hash += hash << 5;
    
                return Math.abs(hash);
    
            }
    
    
            /**
    
             *  hash 算法3
    
             * @param key
    
             * @return
    
             */
    
            private int hashcode_3(String key) {
    
                int hash, i;
    
                for (hash = 0, i = 0; i < key.length(); ++i) {
    
                    hash += key.charAt(i);
    
                    hash += (hash << 10);
    
                    hash ^= (hash >> 6);
    
                }
    
                hash += (hash << 3);
    
                hash ^= (hash >> 11);
    
                hash += (hash << 15);
    
                return Math.abs(hash);
    
            }
    
        }
    1. 首先初始化了一个 int 数组。

    2. 写入数据的时候进行三次 hash 运算,同时把对应的位置置为 1。

    3. 查询时同样的三次 hash 运算,取到对应的值,一旦值为 0 ,则认为数据不存在。

     

    实现逻辑其实就和上文描述的一样。

     

    下面来测试一下,同样的参数:

        -Xms64m -Xmx64m -XX:+PrintHeapAtGC
    
            @Test
    
            public void bloomFilterTest(){
    
                long star = System.currentTimeMillis();
    
                BloomFilters bloomFilters = new BloomFilters(10000000) ;
    
                for (int i = 0; i < 10000000; i++) {
    
                    bloomFilters.add(i + "") ;
    
                }
    
                Assert.assertTrue(bloomFilters.check(1+""));
    
                Assert.assertTrue(bloomFilters.check(2+""));
    
                Assert.assertTrue(bloomFilters.check(3+""));
    
                Assert.assertTrue(bloomFilters.check(999999+""));
    
                Assert.assertFalse(bloomFilters.check(400230340+""));
    
                long end = System.currentTimeMillis();
    
                System.out.println("执行时间:" + (end - star));
    
            }

    执行结果如下:

    只花了 3 秒钟就写入了 1000W 的数据同时做出来准确的判断。

     

    当让我把数组长度缩小到了 100W 时就出现了一个误报, 400230340 这个数明明没在集合里,却返回了存在。这也体现了 BloomFilter 的误报率。

     

    我们提高数组长度以及 hash 计算次数可以降低误报率,但相应的 CPU、内存的消耗就会提高;这就需要根据业务需要自行权衡。

     

    Guava 实现

    刚才的方式虽然实现了功能,也满足了大量数据。但其实观察 GC 日志非常频繁,同时老年代也使用了 90%,接近崩溃的边缘。

     

    总的来说就是内存利用率做的不好。

     

    其实 Google Guava 库中也实现了该算法,下面来看看业界权威的实现。

        -Xms64m -Xmx64m -XX:+PrintHeapAtGC 
    
            @Test
    
            public void guavaTest() {
    
                long star = System.currentTimeMillis();
    
                BloomFilter<Integer> filter = BloomFilter.create(
    
                        Funnels.integerFunnel(),
    
                        10000000,
    
                        0.01);
    
    
                for (int i = 0; i < 10000000; i++) {
    
                    filter.put(i);
    
                }
    
    
                Assert.assertTrue(filter.mightContain(1));
    
                Assert.assertTrue(filter.mightContain(2));
    
                Assert.assertTrue(filter.mightContain(3));
    
                Assert.assertFalse(filter.mightContain(10000000));
    
                long end = System.currentTimeMillis();
    
                System.out.println("执行时间:" + (end - star));
    
            }

     也是同样写入了 1000W 的数据,执行没有问题。

    观察 GC 日志会发现没有一次 fullGC,同时老年代的使用率很低。和刚才的一对比这里明显的要好上很多,也可以写入更多的数据。

     

    源码分析

     

    那就来看看 Guava 它是如何实现的。

     

    构造方法中有两个比较重要的参数,一个是预计存放多少数据,一个是可以接受的误报率。 我这里的测试 demo 分别是 1000W 以及 0.01。

    Guava 会通过你预计的数量以及误报率帮你计算出你应当会使用的数组大小 numBits 以及需要计算几次 Hash 函数 numHashFunctions 。

    这个算法计算规则可以参考维基百科。

     

    put 写入函数

     

    真正存放数据的 put 函数如下:

     

    • 根据 murmur3_128 方法的到一个 128 位长度的 byte[]。

    • 分别取高低 8 位的到两个 hash 值。

    • 再根据初始化时的到的执行 hash 的次数进行 hash 运算。

        bitsChanged |= bits.set((combinedHash & Long.MAX_VALUE) % bitSize);

     

    其实也是 hash取模拿到 index 后去赋值 1.

    重点是 bits.set() 方法。

     

    其实 set 方法是 BitArray 中的一个函数, BitArray 就是真正存放数据的底层数据结构。利用了一个 long[]data 来存放数据。

     

    所以 set() 时候也是对这个 data 做处理。

     

    • 在 set 之前先通过 get() 判断这个数据是否存在于集合中,如果已经存在则直接返回告知客户端写入失败。

    • 接下来就是通过位运算进行 位或赋值。

    • get() 方法的计算逻辑和 set 类似,只要判断为 0 就直接返回存在该值。

    mightContain 是否存在函数

    前面几步的逻辑都是类似的,只是调用了刚才的 get() 方法判断元素是否存在而已。

     

    总结

     

    布隆过滤的应用还是蛮多的,比如数据库、爬虫、防缓存击穿等。

    特别是需要精确知道某个数据不存在时做点什么事情就非常适合布隆过滤。

     

    展开全文
  • 在给定的一台4G的PC机器上实现,一个包含40亿个不重复并且没有排过序的无符号的int整数,给出一个整数,找出给定的某个数 m,是否在文件40亿个数据当中的需求。 我这边推荐两个做法。 第一种做法: 需求分析:Int...

    首先,我们先看个问题     

    在给定的一台4G的PC机器上实现,一个包含40亿个不重复并且没有排过序的无符号的int整数,给出一个整数,找出给定的某个数 m,是否在文件40亿个数据当中的需求。

    我这边推荐两个做法。

    第一种做法:

    需求分析:Int类型在Java中的存储占用4个Byte,32Bit,如果在内存中定义40亿个int类型数组来读取文件,占用大小:(40*100000000*4/1024/1024/1024)G=14.901G。这已经远远超出了机器的内存限制,这时候常规思路是,将数据存在磁盘,分批读取数据到内存中,但这样就会产生磁盘IO,对于追求速率的我们来讲,这种情况我们不考虑。

     对于数据来说,某个数据有还是没有,我们可以用0和1来表示,这正好符合二进制的0 1属性,我们知道Java中1 Int = 4 Byte = 32 Bit,这种情况下,我们需要的内存空间是,(40*100000000/8/1024/1024)M = 476.8!竟然满足了我们的要求。

    具体思路:

       1个int占4字节即4*8=32位,那么我们只需要申请一个int数组长度为 int tmp[1+N/32]即可存储完这些数据,其中N代表要进行查找的总数,tmp中的每个元素在内存在占32位可以对应表示十进制数0~31,所以可得到BitMap表:

    tmp[0]:可表示0~31

    tmp[1]:可表示32~63

    tmp[2]可表示64~95

    .......

    那么接下来就看看十进制数如何转换为对应的bit位:

    假设这40亿int数据为:6,3,8,32,36,......,那么具体的BitMap表示为:

    如何判断int数字在tmp数组的哪个下标,这个其实可以通过直接除以32取整数部分,例如:整数8除以32取整等于0,那么8就在tmp[0]上。另外,我们如何知道了8在tmp[0]中的32个位中的哪个位,这种情况直接mod上32就ok,又如整数8,在tmp[0]中的第8 mod上32等于8,那么整数8就在tmp[0]中的第八个bit位(从右边数起)

    时间复杂度为o(n)   查找时间为o(1)

     

    第二种做法:

    这个问题在《编程珠玑》里有很好的描述,大家可以参考下面的思路,探讨一下:
    又因为2^32为40亿多,所以给定一个数可能在,也可能不在其中;
    这里我们把40亿个数中的每一个用32位的二进制来表示
    假设这40亿个数开始放在一个文件中。

        然后将这40亿个数分成两类:
          1.最高位为0
          2.最高位为1
        并将这两类分别写入到两个文件中,其中一个文件中数的个数<=20亿,而另一个>=20亿(这相当于折半了);
    与要查找的数的最高位比较并接着进入相应的文件再查找

        再然后把这个文件为又分成两类:
          1.次最高位为0
          2.次最高位为1
        并将这两类分别写入到两个文件中,其中一个文件中数的个数<=10亿,而另一个>=10亿(这相当于折半了);
        与要查找的数的次最高位比较并接着进入相应的文件再查找。
        .......
        以此类推,就可以找到了,而且时间复杂度为O(logn)

     

    下面来讨论以下BitMap和布隆过滤器的优缺点

    两个的差别

    bitmap更适合用于数字比较。

    布隆过滤器适合非数字比较(有误判)

    • 当一个元素被加入集合时,通过 K 个 Hash函数将这个元素映射成一个位阵列(Bit array)中的 K 个点,把它们置为 1
    • 也就是说一个数据可能占用多个bit,hash函数越多误判越少 但是消耗内存越多

    这么来说吧,bitmap适合用于数字,如果你连串的字符串对应的hashcode()有可能相等,这样的话对应的bitmap也就相等了,但是布隆过滤器有K个散列函数,这样对应的K个值可以均匀分布到各个位置,这样就减少冲突的情况了。

    布隆过滤器的优点:不需要存储key,节省空间

    缺点:
    1. 算法判断key在集合中时,有一定的概率key其实不在集合中
    2. 无法删除

    典型的应用场景:
    某些存储系统的设计中,会存在空查询缺陷:当查询一个不存在的key时,需要访问慢设备,导致效率低下。
    比如一个前端页面的缓存系统,可能这样设计:先查询某个页面在本地是否存在,如果存在就直接返回,如果不存在,就从后端获取。但是当频繁从缓存系统查询一个页面时,缓存系统将会频繁请求后端,把压力导入后端。

    这是只要增加一个bloom算法的服务,后端插入一个key时,在这个服务中设置一次
    需要查询后端时,先判断key在后端是否存在,这样就能避免后端的压力。

    展开全文
  • 【导读】当你在浏览器上,指尖轻轻输入 www.taobao.com 以后发生了什么?本文从你按下浏览器的确定键开始分析,一直到你如何找到商品结束。适合各类读者了解你仅仅访问次淘宝的首页,所涉及到的技术和系统规模,...

    【导读】当你在浏览器上,指尖轻轻输入  www.taobao.com  以后发生了什么?本文从你按下浏览器的确定键开始分析,一直到你如何找到商品结束。适合各类读者了解你仅仅访问一次淘宝的首页,所涉及到的技术和系统规模,本文作者名叫孙放,著于他在淘宝实习期间。

    你发现快要过节了,于是想给你的男/女朋友买点儿礼物,你打开了淘宝。下面来看看,当你在浏览器轻轻www.taobao.com  以后发生了什么?

    首先你的浏览器查询了DNS服务器(注:能够使人更方便的访问互联网,而不用去记住能够被机器直接读取的IP地址,例如192.168.1.1),现在DNS服务器将www.taobao.com转换成IP地址,机器能直接读取了。

    不过浏览器发现,在不同的地区或者不同的网络(电信、联通、移动)的情况下,转换后的IP地址很可能是不一样的,这首先涉及到负载均衡(注:相当于几万人的大学,一个食堂不够用,于是学校弄了五个食堂来服务所有的同学,这就叫负载均衡)。第一步,通过DNS解析域名时将你的访问分配到不同的入口,同时尽可能保证你所访问的入口是所有入口中可能较快的一个。

    好了,现在你通过这个入口成功的访问了www.taobao.com的实际的入口IP地址。这时你产生了一个PV(注: Page View,一次页面访问),每日每个网站的总PV量是形容一个网站规模的重要指标。淘宝网全网在平日非促销期间的PV大概是16-25亿之间。同时作为一个独立的用户,你这次访问淘宝网的所有页面,均算作一个UV(注:Unique Visitor用户访问)。卖火车票的12306.cn的日PV量最高峰在10亿左右,而UV量却远小于淘宝网十余倍,这其中的原因我相信大家都会知道。(注:因为频繁刷新)

    因为同一时刻访问www.taobao.com的人数过于巨大,所以即便是淘宝首页页面的服务器,也不可能仅有一台。仅用于生成www.taobao.com首页的服务器就可能有成百上千台,那么你的一次访问时生成页面给你看的任务便会被分配给其中一台服务器完成。(注:相当于学校有5个食堂,二食堂3窗口老是爆满,因为打菜的是个萌妹子。)

    这个过程要保证公正、公平、平均(注:这成百上千台服务器每台负担的用户数要差不多,就像食堂不能颠勺),这一很复杂的过程是由几个系统配合完成,其中最关键的便是LVS(Linux Virtual Server),世界上最流行的负载均衡系统之一,正是由目前在淘宝网供职的章文嵩博士开发的。

    经过一系列复杂的逻辑运算和数据处理,用于这次给你看的淘宝网首页的内容便生成成功了。

    据消息称,在双十一当天高峰,淘宝的访问流量最巅峰达到871GB/S(注:一秒钟871GB,如果你电脑硬盘是500G的话,相当于一秒钟,你的磁盘就被塞满了)。这个数字意味着需要178万个4Mb带宽的家庭宽带才能负担的起,也完全有能力拖垮一个中小城市的全部互联网带宽。那么显然,这些访问流量不可能集中在一起。并且大家都知道,不同地区不同网络(注:电信、联通、教育网等)之间互访会非常缓慢,但是你却发现很少发现淘宝网访问缓慢。这便是CDN(Content Delivery Network),即内容分发网络的作用。淘宝在全国各地建立了数十上百个CDN节点,利用一些手段保证你访问的地方是离你最近的CDN节点,这样便保证了大流量分散在各地访问的加速节点上,指不定你们家这块就有一个。

    这便出现了一个问题,那就是假如一个卖家发布了一个新的宝贝,上传了几张新的宝贝图片,那么淘宝网如何保证全国各地的CDN节点中都会同步的存在这几张图片供用户使用呢?这里边就涉及到了大量的内容分发与同步的相关技术。淘宝开发了分布式文件系统TFS(Taobao FileSystem)来处理这类问题。

    好了,这时你终于加载完了淘宝首页,那么你习惯性的在首页搜索框中输入了 ’月饼’ 二字并敲回车,这时你又产生了一个PV,然后,淘宝网的主搜索系统便开始为你服务了。它首先对你输入的内容基于一个分词库进行分词操作。众所周知,英文是以词为单位的,词和词之间是靠空格隔开,而中文是以字为单位,句子中所有的字连起来才能描述一个意思。例如,英文句子I am a student,用中文则为:“我是一个学生”。计算机可以很简单通过空格知道student是一个单词,但是不能很容易明白“学”、“生”两个字合起来才表示一个词。把中文的汉字序列切分成有意义的词,就是中文分词,有些人也称为切词。我是一个学生,分词的结果是:我是一个学生。

    进行分词之后,还需要根据你输入的搜索词进行你的购物意图分析。用户进行搜索时常常有如下几类意图:

    (1)   浏览型:没有明确的购物对象和意图,边看边买,用户比较随意和感性。查询例如:”2013年10大香水排行”,”2013年流行雪纺衫”, “iPhone有哪个牌子好?”;

    (2)   查询型:有一定的购物意图,体现在对属性的要求上。查询例如:”适合老人用的手机”,”500元手表”;

    (3)   对比型:已经缩小了购物意图,具体到了某几个产品。查询例如:”iPhone 5 三星盖世三″,”三星 i9300 i9400″;

    (4)   确定型:已经做了基本决定,重点考察某个对象。查询例如:”iPhone5″,”盖世三″。通过对你的购物意图的分析,主搜索会呈现出完全不同的结果来。

    之后的数个步骤后,主搜索系统便根据上述以及更多复杂的条件列出了搜索结果,这一切是由一千多台搜索服务器完成。然后你开始逐一点击浏览搜索出的宝贝。你开始查看宝贝详情页面。经常网购的亲们会发现,当你买过了一个宝贝之后,即便是商家多次修改了宝贝详情页,你仍然能够通过‘已买到的宝贝’查看当时的快照。那么显然,对于每年数十上百亿比交易的商品详情快照进行保存和快速调用不是一个简单的事情。这其中又涉及到数套系统的共同协作,其中较为重要的是Tair(注:淘宝自行研发的分布式KV存储方案)。

    然后无论你是否真正进行了交易,你的这些访问行为便忠实的被系统记录下来,用于后续的业务逻辑和数据分析。这些记录中访问日志记录便是最重要的记录之一,但是前边我们得知,这些访问是分布在各个地区很多不同的服务器上的,并且由于用户众多,这些日志记录都非常庞大,达到TB(注:1TB=1024GB)级别非常正常。那么为了快速及时传输同步这些日志数据,淘宝研发了TimeTunnel,用于进行实时的数据传输,交给后端系统进行计算报表等操作。

    你的浏览数据、交易数据以及其它很多很多的数据记录均会被保留下来。使得淘宝存储的历史数据轻而易举的便达到了十数甚至更多个 PB(注:1PB=1024TB=1048576GB)。如此巨大的数据量经过淘宝系统1:120的极限压缩存储在淘宝的数据仓库中。并且通过一个叫做云梯的,由数万台服务器组成的超大规模数据系统不断的进行分析和挖掘。

    从这些数据中淘宝能够知道小到你是谁,你喜欢什么,你的孩子几岁了,你是否在谈恋爱,喜欢玩魔兽世界的人喜欢什么样的饮料等,大到各行各业的零售情况、各类商品的兴衰消亡等等海量的信息。

    你刚访问了淘宝首页,而淘宝却做了这么多事情。

    说了这么多,其实也只是叙述了淘宝上正在运行的成千上万个系统中的寥寥几个。即便是你仅仅访问一次淘宝的首页,所涉及到的技术和系统规模都是你完全无法想象的,是淘宝3000多名顶级的工程师们的心血结晶,其中甚至包括长江学者、国家科学技术最高奖得主等众多大牛。同样,百度、腾讯等的业务系统也绝不比淘宝简单。你需要知道的是,你每天使用的互联网产品,看似简单易用,背后却凝聚着难以想象的智慧与劳动。

    展开全文
  • 快让的App分20亿吧!

    千次阅读 热门讨论 2021-02-24 19:42:01
    这个分钱呢,哦,不对,这个功能呢,咱们都应该知道首先肯定不是通过App更新来更新的,过节日为了更新一个图标让用户升级App,估计会被打死吧。这种功能的俗称叫做:动态替换App的图标。 activity-alias 其实 实现...
  • 在2003年的时候中国人民都在为国产CPU“汉芯”(或叫HISYS)而欢腾雀跃的时候人发现了该芯片以及它的制造者陈进教授背后存在着巨大的阴谋。3年之后,一个昵称为“深喉”的人在清华大学的BBS上揭露说汉芯CPU是...
  • 位立志在40岁非成为亿万富翁不可的先生,在35岁的时候,发现这样的愿望根本达不到,于是放弃工作开始创业,希望能一夜致富。五年间他开过旅行社、咖啡店,还有花店,可惜每次创业都失败,也陷家庭于绝境。 ...
  • 对于Python爬虫爱好者来说,不抓取亿的数据放在自己电脑上,都不过瘾
  • 在手机市场这「中心城市」已经完全被 Android 占领的情况下,鸿蒙核心着力点采取的是「边缘包围城市」的策略。 未来将是「Service as a Service」、「Everything is a service」,并且,所有服务都是可以被升级的...
  • 最近一则《Facebook隐私泄露事件继续发酵,黑客明码标价出售聊天信息》...曾经人反驳,免费使用产品,公司获得数据,这是一个公平的交易。显然,反对者还没有理解保护隐私为何那么重要。今天,就来谈谈:用户...
  • 那个忽悠马云10个亿,被阿里同事指着鼻子让他滚蛋的人,后来怎么样了?后来,他成为阿里巴巴集团首席技术官,而且被公认为,近10年来,中国最好的首席技术官。他叫王坚,被称为“...
  • 2017年如何实现1个亿的小目标?

    千次阅读 2017-03-31 19:56:42
    鸽姆第一个15年目标规划 去年首富王健林说了一个小目标,瞬间炸翻了整个网络。反对的,支持的,但是没有一个人讲述如何实现1个亿的目标!做到的不屑一顾,做不到的也没有可行之路!今天我就此话题,说...一个亿
  • 4月中旬,我与老朋友屈阳交流创业,详细聊了鸿学金信的整体运行思路,披露了平台当前运行情况等。...一个目标100亿的互联网+创业项目完整思路,一个怀着对年轻人诚信信心的创业者的互联网普惠金融之梦。”等等
  • 各位都非常年轻,我今天来的时候压力。因为我毕业快11年了,看到你们,真是觉得“长江后浪推前浪”。 我去年参加了武汉的校招,感觉新一代年轻人的素质确实都非常好。我昨天就在想,今天应该跟大家分享什么。想...
  • 40亿个数中快速查找

    千次阅读 2016-02-24 16:29:16
    给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中? 分析与解法 海量数据处理往往会很有趣,有趣在什么地方呢? 空间,available的内存不够,...
  • 微信一亿用户背后架构秘密

    千次阅读 2012-09-22 20:30:21
    微信——腾讯战略级产品,创造移动互联网增速记录,10月5000万手机用户,433天之内完成用户数从零到一亿的增长过程,千万级用户同时在线,摇摇每天次数过亿...在技术架构上,微信是如何做到的?日前,在腾讯大...
  • 代码之谜(五)- 浮点数(谁偷了的精度?)

    万次阅读 多人点赞 2012-11-13 12:27:14
    如果我告诉,中关村配置最高的电子计算机的计算精度还不如一个便利店卖的手持计算器,一定会反驳我:「今天写博客之前又忘记吃药了吧」。 可以用最主流的编程语言计算 0.2 + 0.4,如果使用的是 Chrome、...
  • DayDayUp:2018年末施瓦辛格热血演讲《关于成功·成功的真谛》—YouTuBe播放量超1个亿!—学习英文 导读 本文章是鸡汤,可以选择看,也可以选择关掉不看。 PS:祝2019,敢于折腾的人们,带着梦想,从心出发!,...
  • 一个早上读完了《20个月赚130亿-YouTube创始人陈士骏自传》这本书。这本书的书名实在是太俗了,公开场合下还真不太好意思给别人看到这本书的书名,太露骨了。要不是人推荐,还以为又是成功学之类的书,不过书的...
  • 点击“技术领导力”关注∆每天早上8:30推送来源|纯洁的微笑编者语:金山办公于2019年11月18日,正式在上交所科创板挂牌交易,股票简称“金山办公”,市值超过600...”回顾WPS 31年的成长之路,不得不提一个人,他就...
  • 作者 | 夕颜编辑 | Just出品 | AI 科技大本营(ID:rgznai100)【导读】2017 年,在当时微软的篇官方博客中,时任微软云开发服务副总裁的 Bri...
  • 举个例子,就像一个是西医,病的时候治病,而一个是中医,强调自身抵抗力的提升,自己身体更健康了,就很难生病了 。 区块链大本营: 形式化验证的原理到底是什么? 杨霞: 形式化验证是一种基于数学和逻辑学...
  • 位几年前带我入坑的前辈的话——坑就在面前,别总是犹豫徘徊,大胆一点:向前一步,入了这坑,莽着头就是往前冲,别多想,别回头,终有一天——>也会成为别人的前辈!???? 今日份鸡汤已成功送达,目
  • 那么在数据体积激增的当下,究竟哪个数据库才会适合的场景,下面看Moshe的分享。 【编者按】随着数据的爆发性增长,NoSQL得到的关注已越来越多,然而的用例真正需要使用NoSQL数据库吗?又真的适合使用NoSQL...
  • Top K 算法详解 应用场景:  搜索引擎会通过日志文件把用户每次检索使用的所有检索...一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。),请统计最热门的10个查询串,要求使用的内存不能超过1G。
  • 一个int型占4字节,10亿就是40亿字节(很明显就是4GB),也就是如果完全读入内存需要占用4GB,而题目只给1GB内存,显然不可能将所有数据读入内存。我们先不考虑时间复杂度,仅考虑解决问题。那么接下来的思路一般...
  • 2019年就这么匆匆过去了,就在前几天国家电影局发布了2019年中国电影市场数据,数据显示去年总票房为642....不过作为名严谨求实的数据分析师,我从官方数据中看出了一点端倪:国产票房增幅都已经高达8.65%了,为什...
  • 史玉柱的创业史可以分为上下两半场――1997年之前的巨人和1997年之后的巨人。...留下栋荒草肆虐的烂尾楼,外加几亿元巨债。死过次后,才知道死亡的滋味。这10年,史玉柱如履薄冰,小心翼翼,卖脑白金,
  • 网飞1998年成立,2002年上市,19年时间股价涨到,市值近2500亿美金(约相当于1.6万亿人民币),直追百年大厂迪士尼。 资本市场如此抢眼的科技和媒体巨头,它是靠什么样的管理制度驱动的呢? 这本书刷新了读者对...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 129,697
精华内容 51,878
关键字:

当你有一个亿的时候