摩登3娱乐登录地址_GitHub 40K Star工程师求职记

本文作者是牛客网知名大佬 CyC2018,在他的 GitHub 有一个高达 40K Star 的技术仓库(在所有仓库中排名前五十),可以说在开源项目方面是一骑绝尘的牛人。今天我们分享一下他的求职经历。(最终 Offer:百度、阿里、腾讯、头条、网易游戏、华为) 下面正文开始! 2018,有过迷茫,有过努力,也有很多收获。为了记录这一年以来的感受,于是有了这篇文章。 壹 offer一览 offer情况 经过了长达一年左右的复习,秋招也收到了几个比较满意的 Offer,参加面试的都通过了。 百度,企业智能平台; 阿里,高德地图,部门已联系,目前还在申报 Offer 中; 腾讯,IEG 游戏平台,后台研发,SP; 字节跳动,头条后台研发,SSP; 华为,Cloud Bu; 网易游戏,梦幻事业部; 顺丰科技 贰 前期准备 前期准备 也是在去年十一月份左右,看着身边两年制的同学经历了长时间而又艰难的秋招,我开始意识到自己应该提前准备了,否则自己的秋招会很惨。 本科的时候,虽然学过计算机网络、操作系统和数据结构等课程,而且 Leetcode 也刷了一两百题,但是离招聘要求还差的很远,学的都很浅只够应付考试,也没有实际的项目经验。 我的研究生方向是计算机图形学,研究生期间主要做一些科研项目。在选择招聘方向的时候,我也纠结了是不是找图形学相关方向的,但是考虑到图形学的选择不是很多,所以还是决定投后台研发相关的岗位。 于是开始收集各种学习资料,也买了很多纸质书。最开始的学习效率并不是很高,很迷茫,觉得要学的内容很多无从下手。那时候看别人的面经,感觉自己太弱了,很多内容都没接触过,于是更加迷茫。迷茫的时候总想着逃避,要是不复习多好,玩玩游戏每天多简单。 但是游戏玩的越多,那种焦虑感越是强烈。解决焦虑的唯一办法就是想办法解决当前问题。当慢慢地从消极的学习态度中调整过来,掌握的知识越多,那种焦虑感也随之消失。当然这个过程并不容易,不仅需要很好的毅力,也要根据自身情况找到问题的有效解决方法。 叁 春招历程 春招开始 三月份各个公司就开始春招了,那时候刚把一些基础知识简单地复习了一下,Leetcode 刷到了三四百题。但是没有后台研发相关的项目,于是花了一个星期左右用 PHP 做了一个微博系统。当时做简历特别痛苦,没内容可以写,看着其他人简历各种新技术,自己都没掌握,所以很虚。 阿里一轮游 最开始投的阿里,实验室大几届有个师兄在天猫精灵团队,所以给我内推了。于是我人生中第一场面试就是阿里,很自然地被虐了一遍。记得当时约好下午两点电话面试,午饭都没吃,怕吃完之后犯困影响状态,然后找了一个很安静又没人的地方呆到了两点,调整自己的状态。 可是面试官突然打电话来说有个会议要开,所以推迟了大概一个小时。苦苦等到三点左右,面试正式开始,不出所料面得非常糟糕。首先自己表述的很有问题,很多内容没回答到关键点上,自己会的内容也不怎么继续扩展回答。 其次知识掌握得确实不够,连线程安全、ThreadLocal、函数式编程都不会。虽然被虐的很惨,但是也有好处,知道了面试到底是怎样的,自己还有哪方面的不足,该怎么准备。 腾讯被鞭尸 第二场面试是腾讯,在经历了阿里的面试之后,并且又继续复习了一段时间,我对面试就比较有信心了。一面其实回答的挺理想的,虽然很多问题没有立马回答出来,但是经过面试官的耐心提示之后都能回答一些内容。 当时面了一个半小时,面试体验特别好。印象比较深刻的题目有,阅读一个 Redis 源码,分析存在哪些问题。其实就是一个计数器实现的限流算法,会有临界值的问题,但是当时没回答出来,只能听面试官给我解释。还有一个微信扫二维码,这个过程发生了什么,也没回答得很好,不过面试官也很耐心地纠正我回答上的错误。一面顺利通过了,但是总监面挂了。 总监面没有问什么技术问题,就是问了问项目和职业规划。自己的项目确实比较 Low,我自己在介绍的时候也说得很不堪。职业规划我说自己希望在一些方面深入学习,因为自己现在在这些方面还很薄弱… 面完之后我就知道挂了,因为整个面试过程我都特别虚,还主动说自己技术能力不行。不出所料,面完的当天晚上,状态变成了不合适。 但是过了几天,突然收到腾讯的电话,问我是否愿意去深圳参加面试(笔者学校在广州)。当然我毫不犹豫地答应了,很开心腾讯还能给我机会。经过了上一场面试的启示,这次面试我表现地非常自信,自己知道的知识都很有信心地表达出来,被问到不会的内容也不会那么慌张,和面试官探讨一些细节,然后说说自己的想法,还有自己看过相关的内容。 由于这是腾讯云部门,对 Linux 内核和 C++ 有很高的要求,问了几个相关的问题我都没回答出来,比如如何实现守护进程,Linux 信号机制,Linux 线程的不可中断阻塞状态如何进入等等。除了这些问题,其它地回答的都还行。遗憾的是,当天晚上面试官打电话告知我面试没通过。但是他说我其它方面都很不错,所以问我愿不愿意参加腾讯云 Java 部门的招聘,于是第二天我又去了一个新的部门面试。 这次面试是在部门的会议室进行的,进到公司之后说实话没有自己想象中那么好,工位很挤环境一般。一开始就先随便聊聊,学校的研究工作,学习之类的。然后看了看项目,看完之后我就知道凉了一半,这个项目确实太水了,面试官看了之后没有接着问,也能感受到面试官有点嫌弃。然后他就问了一些基础知识,问到进程调度算法,面试官让我实现一个任务调度系统。 因为是第一次手写代码,而且之前确实没考虑过这个问题,然后就胡乱写了一堆代码,特别乱,而且到处涂改。显然面试官是不满意的,写了也有十几分钟之后,我自己都知道已经凉了,然后面试官没让我接着写,也没给我任何提示,说就到这里,面试结束了,还有没有什么问题想问的。 当然看过任务调度系统相关的文章会觉得挺容易的,比如使用时间轮实现等等。我依然记得面试官送我出门时候的热情,送我坐电梯的时候还很热情地和我说,非常感谢参加本次面试,辛苦了。 肆 春招战果 虎牙过于自信 经过了阿里和腾讯的面试之后,我觉得自己大概已经知道该怎么面试了,面试时候该注意什么,该怎么表达等等。而且腾讯面试表现也不差,虽然最后没通过。所以在虎牙面试的时候特别放松,觉得应该能通过。 前面面的也都还行,虽然有几个问题没回答好,比如分析一下微博的时间线。通过了第一轮面试直接等第二轮,等到了晚上七点多才等到我。虎牙面试还是很注重技术的,虽然问的都不是很深入,只要简单回答到点上就不会接着问下去。 二面也有一些问题没回答好,比如 ConcurrentHashMap 的并发机制,问 Spring 直接说不会。也有一些问题回答得比较乱,没有条理。但是我觉得大部分问题都回答的不错,应该能通过。 可是面试完之后,面试官问有没有什么问题要问他,由于太过放松,我就问你们都加班到这么晚不吃饭吗,好饿啊,周六周日还加班吗… 问完之后面试官就很严肃了,说平常不加班的,我突然意识到了问题的严重性… 最后还是凉了。 百度第一个offer 被三家连续拒了之后,都开始怀疑自己了,不过还是提醒自己要保持信心。 幸运的是,百度的面试非常适合我,三轮都是技术面,而且手写算法题目居多,而我准备最多的是算法,所以很顺利通过了面试。但是面试表现并没有特别好,过了比较长的时间才被捞,而且是工程效率部门,做内部工具的,对个人成长并不好,所以不是特别满意。 网易游戏 最好的游戏体验 其实最开始没有打算投网易游戏的,因为被脉脉洗脑,已经放弃了做游戏。但是因为前面面试基本被拒了,担心没有实习 Offer,因此就试试看。 因为没有特别想去网易游戏,所以面试过程也比较放松,就当去聊聊天。面试官非常 nice,那天下午挤了很久地铁,比较口渴,然后面试官看我说得沙哑了,到门口帮我买了一瓶可乐,非常感激。面试之前我就提出我对 C++ 不熟悉,最近主要看 Java 的内容。 面试官还是说没关系,尽量回答就好。当然最后我都把问题往 Java 那里回答了,比如 Map 的实现,内存管理等等。最后聊了一些玩过的游戏,就让我回去等消息。网易游戏就一轮面试,确实就一轮。周五参加的面试,下周一就给 Offer 了,效率特别高。 微众玄学面试 通过微众面试我自己都非常吃惊,一面的时候就简单自我介绍了一下,然后面试官开始介绍他自己的工作经历,以及现在部门在做的内容。 之后问了我一个场景分析问题,我想了一会儿没想出来,于是面试官拿起草稿纸把各种需求详细说了一遍,然后把系统架构图也画了出来… 最后他问还有什么我优势的地方他没问到的,我问他怎么不问问算法题,他说笔试都通过了没必要再问。 面完之后我觉得聊得很开心,但是技术问题没回答好,出乎意料收到了二面通知。二面没问技术,就让介绍了项目,再问问家住哪之类的问题,也顺利通过了。HR 面就不用介绍。 收到了微众的 Offer,得知了部门是贷款科技部,非常核心,很吃香,近几年也在扩展一些业务,还是有点小心动的。虽然最后没选择去微众实习,但是一面面试官加了我微信,我很感谢他一面非常耐心给我讲解,并让我通过。他说我是他面试的第一顺位,也就是第一个面试者,所以会放宽很多,也希望我秋招能加入他们。 伍 实习回忆 实习选择 其实最理想的是去百度实习,秋招也会容易很多。但是考虑到百度是在北京,部门很边缘,而且需要实习很长时间也不一定能转正,所以还是放弃了。 最后只能在网易游戏和微众选,虽然自己不想做游戏,但是考虑到网易游戏的平台认可程度比微众好,秋招肯定会更容易一些。而且秋招如果还想进微众的话也会比较容易,因为面试官和 HR 都说秋招的时候会优先考虑我,所以最后还是去了网易游戏实习。 实习之前的快速学习期 经历了春招之后,认识到了自己身上的不足,比如交流表达能力的欠缺,知识积累得不够,项目深度不够。因此在实习之前的两三个月,开始针对这些问题逐个解决。 交流表达能力欠缺,就提前准备好各种非技术问题,然后对着镜子回答,把自己当成听众,并且也用录音机录下来。 知识积累不够,采取的策略是保证广度优先,并且在重要的内容上保证深度。其实之前基础知识已经掌握的比较好了,再学其它技术的时候都有很多相同的地方,所以学起来很快。…

摩登3测速登录地址_是什么让Spring5放弃了使用Guava Cache?

来源:https://albenw.github.io/posts/a4ae1aa2/ 概要 Caffeine是一个高性能,高命中率,低内存占用,near optimal 的本地缓存,简单来说它是Guava Cache的优化加强版,有些文章把Caffeine称为“新一代的缓存”、“现代缓存之王”。本文将重点讲解Caffeine的高性能设计,以及对应部分的源码分析。 与Guava Cache比较 大家都知道,Spring5即将放弃掉Guava Cache作为缓存机制,而改用Caffeine作为新的本地Cache的组件,这对于Caffeine来说是一个很大的肯定。为什么Spring会这样做呢?其实在Caffeine的Benchmarks里给出了好靓仔的数据,对读和写的场景,还有跟其他几个缓存工具进行了比较,Caffeine的性能都表现很突出。 使用Caffeine Caffeine为了方便大家使用以及从Guava Cache切换过来(很有针对性啊~),借鉴了Guava Cache大部分的概念(诸如核心概念Cache、LoadingCache、CacheLoader、CacheBuilder等等),对于Caffeine的理解只要把它当作Guava Cache就可以了。 使用上,大家只要把Caffeine的包引进来,然后换一下cache的实现类,基本应该就没问题了。这对与已经使用过Guava Cache的同学来说没有任何难度,甚至还有一点熟悉的味道,如果你之前没有使用过Guava Cache,可以查看Caffeine的官方API说明文档,其中Population,Eviction,Removal,Refresh,Statistics,Cleanup,Policy等等这些特性都是跟Guava Cache基本一样的。 下面给出一个例子说明怎样创建一个Cache: private static LoadingCache<String, String> cache = Caffeine.newBuilder()            //最大个数限制            .maximumSize(256L)            //初始化容量            .initialCapacity(1)            //访问后过期(包括读和写)            .expireAfterAccess(2, TimeUnit.DAYS)            //写后过期            .expireAfterWrite(2, TimeUnit.HOURS)            //写后自动异步刷新            .refreshAfterWrite(1, TimeUnit.HOURS)            //记录下缓存的一些统计数据,例如命中率等            .recordStats()            //cache对缓存写的通知回调            .writer(new CacheWriter<Object, Object>() {                @Override                public void write(@NonNull Object key, @NonNull Object value) {                    log.info("key={}, CacheWriter write", key);                }                @Override                public void delete(@NonNull Object key, @Nullable Object value, @NonNull RemovalCause cause) {                    log.info("key={}, cause={}, CacheWriter delete", key, cause);                }            })            //使用CacheLoader创建一个LoadingCache            .build(new CacheLoader<String, String>() {                //同步加载数据                @Nullable                @Override                public String load(@NonNull String key) throws Exception {                    return "value_" + key;                }                //异步加载数据                @Nullable                @Override                public String reload(@NonNull String key, @NonNull String oldValue) throws Exception {                    return "value_" + key;                }            }); Caffeine的高性能设计 判断一个缓存的好坏最核心的指标就是命中率,影响缓存命中率有很多因素,包括业务场景、淘汰策略、清理策略、缓存容量等等。如果作为本地缓存, 它的性能的情况,资源的占用也都是一个很重要的指标。下面 我们来看看Caffeine在这几个方面是怎么着手的,如何做优化的。 (注:本文不会分析Caffeine全部源码,只会对核心设计的实现进行分析,但我建议读者把Caffeine的源码都涉猎一下,有个overview才能更好理解本文。如果你看过Guava Cache的源码也行,代码的数据结构和处理逻辑很类似的。 源码基于:(caffeine-2.8.0.jar) W-TinyLFU整体设计 上面说到淘汰策略是影响缓存命中率的因素之一,一般比较简单的缓存就会直接用到LFU(Least Frequently Used,即最不经常使用)或者LRU(Least Recently Used,即最近最少使用),而Caffeine就是使用了W-TinyLFU算法。 W-TinyLFU看名字就能大概猜出来,它是LFU的变种,也是一种缓存淘汰算法。那为什么要使用W-TinyLFU呢? LRU和LFU的缺点 LRU实现简单,在一般情况下能够表现出很好的命中率,是一个“性价比”很高的算法,平时也很常用。虽然LRU对突发性的稀疏流量(sparse bursts)表现很好,但同时也会产生缓存污染,举例来说,如果偶然性的要对全量数据进行遍历,那么“历史访问记录”就会被刷走,造成污染。 如果数据的分布在一段时间内是固定的话,那么LFU可以达到最高的命中率。但是LFU有两个缺点,第一,它需要给每个记录项维护频率信息,每次访问都需要更新,这是个巨大的开销;第二,对突发性的稀疏流量无力,因为前期经常访问的记录已经占用了缓存,偶然的流量不太可能会被保留下来,而且过去的一些大量被访问的记录在将来也不一定会使用上,这样就一直把“坑”占着了。 无论LRU还是LFU都有其各自的缺点,不过,现在已经有很多针对其缺点而改良、优化出来的变种算法。 TinyLFU TinyLFU就是其中一个优化算法,它是专门为了解决LFU上述提到的两个问题而被设计出来的。 解决第一个问题是采用了Count–Min Sketch算法。 解决第二个问题是让记录尽量保持相对的“新鲜”(Freshness Mechanism),并且当有新的记录插入时,可以让它跟老的记录进行“PK”,输者就会被淘汰,这样一些老的、不再需要的记录就会被剔除。 下图是TinyLFU设计图(来自官方) 统计频率Count–Min Sketch算法 如何对一个key进行统计,但又可以节省空间呢?(不是简单的使用HashMap,这太消耗内存了),注意哦,不需要精确的统计,只需要一个近似值就可以了,怎么样,这样场景是不是很熟悉,如果你是老司机,或许已经联想到布隆过滤器(Bloom Filter)的应用了。 没错,将要介绍的Count–Min Sketch的原理跟Bloom Filter一样,只不过Bloom Filter只有0和1的值,那么你可以把Count–Min Sketch看作是“数值”版的Bloom Filter。 更多关于Count–Min Sketch的介绍请自行搜索。 在TinyLFU中,近似频率的统计如下图所示: 对一个key进行多次hash函数后,index到多个数组位置后进行累加,查询时取多个值中的最小值即可。 Caffeine对这个算法的实现在FrequencySketch类。但Caffeine对此有进一步的优化,例如Count–Min Sketch使用了二维数组,Caffeine只是用了一个一维的数组;再者,如果是数值类型的话,这个数需要用int或long来存储,但是Caffeine认为缓存的访问频率不需要用到那么大,只需要15就足够,一般认为达到15次的频率算是很高的了,而且Caffeine还有另外一个机制来使得这个频率进行衰退减半(下面就会讲到)。如果最大是15的话,那么只需要4个bit就可以满足了,一个long有64bit,可以存储16个这样的统计数,Caffeine就是这样的设计,使得存储效率提高了16倍。 Caffeine对缓存的读写(afterRead和afterWrite方法)都会调用onAccesss方法,而onAccess方法里有一句: frequencySketch().increment(key); 这句就是追加记录的频率,下面我们看看具体实现 //FrequencySketch的一些属性//种子数static final long[] SEED = { // A mixture of seeds from FNV-1a, CityHash, and Murmur3    0xc3a5c85c97cb3127L, 0xb492b66fbe98f273L, 0x9ae16a3b2f90404fL, 0xcbf29ce484222325L};static final long RESET_MASK = 0x7777777777777777L;static final long ONE_MASK = 0x1111111111111111L;int sampleSize;//为了快速根据hash值得到table的index值的掩码//table的长度size一般为2的n次方,而tableMask为size-1,这样就可以通过&操作来模拟取余操作,速度快很多,老司机都知道int tableMask;//存储数据的一维long数组long[] table;int size;/** * Increments the popularity of the element if it does not exceed the maximum (15). The popularity * of all elements will be periodically down sampled when the observed events exceeds a threshold. * This process provides a frequency aging to allow expired long term entries to fade away. * * @param e the element to add */public void increment(@NonNull E e) {  if (isNotInitialized()) {    return;  }  //根据key的hashCode通过一个哈希函数得到一个hash值  //本来就是hashCode了,为什么还要再做一次hash?怕原来的hashCode不够均匀分散,再打散一下。  int hash = spread(e.hashCode());  //这句光看有点难理解  //就如我刚才说的,Caffeine把一个long的64bit划分成16个等分,每一等分4个bit。  //这个start就是用来定位到是哪一个等分的,用hash值低两位作为随机数,再左移2位,得到一个小于16的值  int start = (hash & 3) << 2;  //indexOf方法的意思就是,根据hash值和不同种子得到table的下标index  //这里通过四个不同的种子,得到四个不同的下标index  int index0 = indexOf(hash, 0);  int index1 = indexOf(hash, 1);  int index2 = indexOf(hash, 2);  int index3 = indexOf(hash, 3);  //根据index和start(+1, +2, +3)的值,把table[index]对应的等分追加1  //这个incrementAt方法有点难理解,看我下面的解释  boolean added = incrementAt(index0, start);  added |= incrementAt(index1, start + 1);  added |= incrementAt(index2, start + 2);  added |= incrementAt(index3, start + 3);  //这个reset等下说  if (added && (++size == sampleSize)) {    reset();  }}/** * Increments the specified counter by 1 if it is not already at the maximum value (15). * * @param i the table index (16 counters) * @param j the counter to increment * @return if incremented */boolean incrementAt(int i, int j) {  //这个j表示16个等分的下标,那么offset就是相当于在64位中的下标(这个自己想想)  int offset = j << 2;  //上面提到Caffeine把频率统计最大定为15,即0xfL  //mask就是在64位中的掩码,即1111后面跟很多个0  long mask = (0xfL << offset);  //如果&的结果不等于15,那么就追加1。等于15就不会再加了  if ((table[i] & mask) != mask) {    table[i] += (1L << offset);    return true;  }  return false;}/** * Returns the table index for the counter at the specified depth. * * @param item the element's hash * @param i the counter depth * @return the table index */int indexOf(int item, int i) {  long hash = SEED[i] * item;  hash += hash >>> 32;  return ((int) hash) & tableMask;}/** * Applies a supplemental hash function to a given hashCode, which defends against poor quality * hash functions. */int spread(int x) {  x = ((x >>> 16) ^ x) * 0x45d9f3b;  x = ((x >>> 16) ^ x) * 0x45d9f3b;  return (x >>> 16) ^ x;} 知道了追加方法,那么读取方法frequency就很容易理解了。 /** * Returns the estimated number of occurrences of an element, up to the maximum (15). * * @param e the element to count occurrences of * @return the estimated number of occurrences of the element; possibly zero but never negative */@NonNegativepublic int frequency(@NonNull E e) {  if (isNotInitialized()) {    return 0;  }  //得到hash值,跟上面一样  int hash = spread(e.hashCode());  //得到等分的下标,跟上面一样  int start = (hash & 3) << 2;  int frequency = Integer.MAX_VALUE;  //循环四次,分别获取在table数组中不同的下标位置  for (int i = 0; i < 4; i++) {    int index = indexOf(hash, i);    //这个操作就不多说了,其实跟上面incrementAt是一样的,定位到table[index] + 等分的位置,再根据mask取出计数值    int count = (int) ((table[index] >>> ((start + i) << 2)) & 0xfL);    //取四个中的较小值    frequency = Math.min(frequency, count);  }  return frequency;} 通过代码和注释或者读者可能难以理解,下图是我画出来帮助大家理解的结构图。 注意紫色虚线框,其中蓝色小格就是需要计算的位置: 保新机制 为了让缓存保持“新鲜”,剔除掉过往频率很高但之后不经常的缓存,Caffeine有一个Freshness Mechanism。做法很简答,就是当整体的统计计数(当前所有记录的频率统计之和,这个数值内部维护)达到某一个值时,那么所有记录的频率统计除以2。 从上面的代码 //size变量就是所有记录的频率统计之,即每个记录加1,这个size都会加1//sampleSize一个阈值,从FrequencySketch初始化可以看到它的值为maximumSize的10倍if (added && (++size == sampleSize)) {      reset();} 看到reset方法就是做这个事情 /** Reduces every counter by half of its original value. */void reset() {  int count = 0;  for (int i = 0; i < table.length; i++) {    count += Long.bitCount(table[i] & ONE_MASK);    table[i] = (table[i] >>> 1) & RESET_MASK;  }  size = (size >>> 1) - (count >>> 2);} 关于这个reset方法,为什么是除以2,而不是其他,及其正确性,在最下面的参考资料的TinyLFU论文中3.3章节给出了数学证明,大家有兴趣可以看看。 增加一个Window? Caffeine通过测试发现TinyLFU在面对突发性的稀疏流量(sparse bursts)时表现很差,因为新的记录(new items)还没来得及建立足够的频率就被剔除出去了,这就使得命中率下降。 于是Caffeine设计出一种新的policy,即Window Tiny LFU(W-TinyLFU),并通过实验和实践发现W-TinyLFU比TinyLFU表现的更好。 W-TinyLFU的设计如下所示(两图等价): 它主要包括两个缓存模块,主缓存是SLRU(Segmented LRU,即分段LRU),SLRU包括一个名为protected和一个名为probation的缓存区。通过增加一个缓存区(即Window Cache),当有新的记录插入时,会先在window区呆一下,就可以避免上述说的sparse bursts问题。 淘汰策略(eviction policy) 当window区满了,就会根据LRU把candidate(即淘汰出来的元素)放到probation区,如果probation区也满了,就把candidate和probation将要淘汰的元素victim,两个进行“PK”,胜者留在probation,输者就要被淘汰了。 而且经过实验发现当window区配置为总容量的1%,剩余的99%当中的80%分给protected区,20%分给probation区时,这时整体性能和命中率表现得最好,所以Caffeine默认的比例设置就是这个。 不过这个比例Caffeine会在运行时根据统计数据(statistics)去动态调整,如果你的应用程序的缓存随着时间变化比较快的话,那么增加window区的比例可以提高命中率,相反缓存都是比较固定不变的话,增加Main Cache区(protected区 +probation区)的比例会有较好的效果。 下面我们看看上面说到的淘汰策略是怎么实现的: 一般缓存对读写操作后都有后续的一系列“维护”操作,Caffeine也不例外,这些操作都在maintenance方法,我们将要说到的淘汰策略也在里面。 这方法比较重要,下面也会提到,所以这里只先说跟“淘汰策略”有关的evictEntries和climb。 /**   * Performs the pending maintenance work and sets the state flags during processing to avoid   * excess scheduling attempts. The read buffer, write buffer, and reference queues are   * drained, followed by expiration, and size-based eviction.   *   * @param task an additional pending task to run, or {@code null} if not present   */  @GuardedBy("evictionLock")  void maintenance(@Nullable Runnable task) {    lazySetDrainStatus(PROCESSING_TO_IDLE);    try {      drainReadBuffer();      drainWriteBuffer();      if (task != null) {        task.run();      }      drainKeyReferences();      drainValueReferences();      expireEntries();      //把符合条件的记录淘汰掉      evictEntries();      //动态调整window区和protected区的大小      climb();    } finally {      if ((drainStatus() != PROCESSING_TO_IDLE) || !casDrainStatus(PROCESSING_TO_IDLE, IDLE)) {        lazySetDrainStatus(REQUIRED);      }    }  } ``` 先说一下Caffeine对上面说到的W-TinyLFU策略的实现用到的数据结构: ``` //最大的个数限制long maximum;//当前的个数long weightedSize;//window区的最大限制long windowMaximum;//window区当前的个数long windowWeightedSize;//protected区的最大限制long mainProtectedMaximum;//protected区当前的个数long mainProtectedWeightedSize;//下一次需要调整的大小(还需要进一步计算)double stepSize;//window区需要调整的大小long adjustment;//命中计数int hitsInSample;//不命中的计数int missesInSample;//上一次的缓存命中率double previousSampleHitRate;final FrequencySketch  sketch; //window区的LRU queue(FIFO) final AccessOrderDeque > accessOrderWindowDeque; //probation区的LRU queue(FIFO) final AccessOrderDeque > accessOrderProbationDeque; //protected区的LRU queue(FIFO) final AccessOrderDeque > accessOrderProtectedDeque; 以及默认比例设置(意思看注释) /** The initial percent of the maximum weighted capacity dedicated to the main space. */static final double PERCENT_MAIN = 0.99d;/** The percent of the maximum weighted capacity dedicated to the main's protected space. */static final double PERCENT_MAIN_PROTECTED = 0.80d;/** The difference in hit rates that restarts the climber. */static final double HILL_CLIMBER_RESTART_THRESHOLD = 0.05d;/** The percent of the total size to adapt the window by. */static final double HILL_CLIMBER_STEP_PERCENT = 0.0625d;/** The rate to decrease the step size to adapt by. */static final double HILL_CLIMBER_STEP_DECAY_RATE = 0.98d;/** The maximum number of entries that can be transfered between queues. */ 重点来了,evictEntries和climb方法: /** Evicts entries if the cache exceeds the maximum. */@GuardedBy("evictionLock")void evictEntries() {  if (!evicts()) {    return;  }  //淘汰window区的记录  int candidates = evictFromWindow();  //淘汰Main区的记录  evictFromMain(candidates);}/** * Evicts entries from the window space into the main space while the window size exceeds a * maximum. * * @return the number of candidate entries evicted from the window space *///根据W-TinyLFU,新的数据都会无条件的加到admission window//但是window是有大小限制,所以要“定期”做一下“维护”@GuardedBy("evictionLock")int evictFromWindow() {  int candidates = 0;  //查看window queue的头部节点  Node  node = accessOrderWindowDeque().peek();    //如果window区超过了最大的限制,那么就要把“多出来”的记录做处理   …

摩登3注册网址_干货分享!用VS Code找对象?不看脸的那种!

VS Code现在居然可以用来谈恋爱了。 为了用最硬核的方式找到男(女)朋友,23岁的程序员Ben Awad在VS Code里打造一个约会软件VSinder。 顾名思义,VSinder = VS Code + Tinder,就是把约会软件集成到了代码编辑器里,简直太对程序员胃口了。 VSinder和Tinder的操作逻辑一样,左滑把不喜欢的人pass掉,右滑收藏喜欢的人。 这款插件一上线,就快速赢得程序员们的认可,GitHub上已收获800 Star,3天的下载量超过9000次。 从代码中找到真爱 既然是面向程序员的约会软件,自然不能和其他约会App一样,一定要有特色。 VSinder的特点就是,可以根据编程语言和代码风格筛选对象。 比如你用的是Python,她用的是C,那么你们之间可能没有共同语言。(以免将来为哪种语言最好吵架。) 对方使用的语言会在人名旁边用一个logo展示出来。 当然,即使用同一种语言编程,水平也有高下,如果对方编程水平达不到自己的要求怎么办? 别怕,VSinder和只看脸的约会软件不同,它是靠代码吸引异性的。(毕竟代码才是程序员的脸面。) Code Pics一栏填入你最得意的代码,让对方一眼知道你的水平深浅。 VSinder也考虑到性取向问题,你也可以选择约会对象的性别。又或者是你只想找个一起交流代码的同性朋友,只需在程序中选择friendship。 当然,找对象,脸也是很重要的。VSinder暂不支持手动修改头像,而是自动抓取你的GitHub账户,如果想让自己帅(美)一点,只能去修改GitHub头像了。 还有手机App 既然是约会软件,怎么可以只在电脑上运行呢? 虽然手机不能跑VS Code,但是Ben还开发了VSinder的手机App供下载。现已经支持iOS和Android两大系统。 只需登上自己的GitHub账号,完善资料即可使用,和Tinder用起来没啥太大区别,除了没有大量美颜照片。 那么这三天来,有没有人在VSinder上找到男(女)朋友?恐怕是没有,有人滑了半个小时,也没有找到一个单身女程序员。 不过这种情况也不难预料,毕竟GitHub是“全球最大的同性交友社区”。 害,没有蹲到小姐姐?推荐试试 Rainbow Fart 彩虹屁插件,萌妹子陪你写代码。 在你写代码的时候,可根据关键字播放接近代码含义的语音。 请看下方示例视频,一定要打开声音(如果是在公司或公众场所,那戴好耳机或调低音量)。 开源地址:https://github.com/benawad/vsinder 插件下载地址:https://marketplace.visualstudio.com/items?itemName=benawad.vsinder 使用方法介绍:https://www.youtube.com/watch?v=bfd8RyAJh6c  来源:量子位 免责声明:本文内容来源于网络,文章版权归原作者所有,意在传播相关技术知识&行业趋势,供大家学习交流,若涉及作品版权问题,请联系删除或授权事宜。 End  微信搜一搜 点分享 点点赞 点在看 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3测试路线_软件定义未来,看懂云杉网络软价值与硬实力

量变引起质变。 正如同海量场效应管能够堆叠成极端复杂的处理器一样,简单结构的复杂套用总能产生结构和用途方面的惊喜。与此相对,当大量简单工作相互堆叠与嵌套,其导致的成本与复杂性则往往是常规组织难以承受的。而网络运维正是符合这一规律的最典型场景之一。 一个简单、节点数量有限的LeafSpine网络,其构建和维护往往是相当轻松的;但当这一架构当中包含了海量节点、庞大流量、无数种业务逻辑、多种虚拟化结构、N种厂牌的设备时,其运维则会变得极端复杂。更何况很多行业还要在这套网络结构上实现多地多中心、热备等高级功能…… 当然,这只是网络运维复杂性的成因之一。实际上,伴随系统的演进,多数大型企业的网络架构中即存在老的结构、也存在很多新的设计;即由传统的存储+服务器结构,也包含SDN架构与VMware、OpenStack、容器结构。维持这样一套结构庞大的、新旧并存的、细节丰富的网络正常运转,其难度可想而知。 因此,我们也就不难理解,为何很多大型企业每年都要花费数亿成本在网络运维之上了。 不过这些问题的出现并非一天两天,因此,像Overlay这样的解决思路在目前也是相当流行。 从超级控制器到NSP 随着网络在业务中的重要性日渐加深,企业对网络运维的重视也水涨船高。因此,很多网络设备供应商也开始在自家方案中以Overlay形式为用户提供众多SDN管理功能。设备与管理层完美对接,实现各种高级功能,网络管理由此便可轻松惬意……但现实不是童话,用户的思考逻辑也不会如此“一根筋”。 多数情况下,出于对被绑定和安全等因素的考虑,大型企业绝不会把所有网络工作交给一家供应商。而对于网络运维来说,这种决策思路则意味着网络中会存在多种体系、多个管理平台、多个入口,他们“鸡犬相闻却老死不相往来”互不兼容且相互独立。 因此,如何在横跨多种结构、多个厂牌的大型网络之上构建统一的管理界面,并实现尽可能多和先进的管理功能就成为了用户必须思考的现实问题。通常我们将这样的产品称为超级控制器,而云杉网络的NSP解决方案正是这片市场中一股不可忽视的力量。 看懂了NSP诞生的原因,我们便能对其作用略窥一二: 有效纳管多个资源池; 兼容传统网络架构与SDN等新型网络架构; 有效连接物理机、虚拟机、裸金属、容器等不同类型资源,并实现相同结构的跨资源池、跨区迁移; 纳管多个不同厂牌设备,构建统一功能界面; 实现网络管理和配置的自动化。 对此,云杉网络CTO张天鹏表示:NSP解决方案包含Controller控制器、Plugin插件和Edge网络服务集群等三个部分,分别实现网元纳管、资源管理和网络编排、网络服务等功能。NSP在保证企业网络的统一纳管、可维护性、可用性、安全等特性的同时亦能通过ResfulAPI提供对第三方网络应用的支持;是一套能够满足用户对网络虚拟化、混合云编排、安全、网络功能交付、生命周期管理、网络可视化等多种功能需求的开放平台。 作为方案的特色之一,NSP能够通过插件实现对不同类型资源池的支持,进而保证方案在面向未来时具备兼容和持续演进能力;NSP的最近一次更新便是加入了对容器的全面支持。而抽象于物理结构的控制面、存储面和数据面则是云杉NSP构建Overlay能力的核心;由此,用户便可在更高维度实现整个网络的虚拟化。 与此同时,横跨多个不同类型资源池的组网能力也能够帮助用户实现混合云的网络编排;而这正是复杂结构下,企业业务交付、应用创新和构建弹性网络所亟需的底层支持。当然,这套架构也同样能够为异地、多活、热备等高可靠功能提供支持。 对于NSP的实际应用效果,张天鹏举了一个非常生动的例子。在某互联网金融的案例中,该用户原本每月能够完成的业务变更操作只有十多次;而在部署NSP解决方案之后,该用户则能够实现每月300多次的大小业务变更。NSP所带来的业务创新效率提升可见一斑。 SDN+SD-WAN 组合拳打出网络运营新天地 没有互联网的数字化是不完整的,面向内网的NSP也仅是云杉网络整体产品体系的二分之一。NSP是企业构建内部网络SDN的效率之选,而面对更广泛的互联网业务,云杉也提供了DeepFlow解决方案。 公有云能够为企业提供更高的性价比和灵活性,因此,公有云+私有云也就成为很多大型企业的必然选择。但在实际的应用中,很多企业发现公有云不仅不便宜,而且很难实现统一的监控管理。 追根溯源,网络层面遍布的黑盒与盲区是原因之一。由于缺乏管理手段,企业很难搞清哪些数据去了云端、庞大的带宽都被哪些流量占据、如何确保公网业务的可靠性……而这些都是网络运营的成本黑洞。因此,云杉网络的DeepFlow应运而生。 作为一套面向混合云的全网流量采集与分发解决方案,DeepFlow不仅能够轻松对接兼容AWS、阿里云和腾讯云等主流云平台上的各类服务,更能通过海量探针高效采集和监控各类业务流量。由此,DeepFlow首先能够实现各类北向流量过滤、压缩、去重、特征标记,让用户获得各类流量的全知上帝视角;更进一步的,通过对各类云平台的对接深度兼容以及对流量的细致分析,用户还能够实现对各种云资源用量的统一监控。 与NSP一样,DeepFlow采用了分布式架构设计和开放的管理监控接口,用户即可以获得面向未来的持续演进能力,也能根据自身需求开发各类高级功能。而在安全层面,DeepFlow则具备海量探针秒级启停、系统自我监控及防过载、加密信令传输等众多特性。 NSP对内、DeepFlow对外,二者相结合,企业便可在统一的界面上实现混合云等复杂网络架构的全要素、全量统一监管。对于大型企业来说,在不借助硬件设备的情况下形成这些能力,至关重要;而如果能够在此之上并保持整个架构的灵活、高效、平滑演进,那更是锦上添花。 一招鲜,吃遍天;而内外网两手抓的云杉网络,显然更受用户青睐。 持续创新+持续服务 云杉网络未来可期 作为一家纯软件网络解决方案厂商,“不造设备”即是云杉网络的优势,也是对云杉网络实力的考验。通过软件来实现管理,云杉网络可以防止用户被绑定,从而降低用户对云杉的选择门槛;但另一方面,云杉网络也只能通过软件来实现对全部网元的纳管和兼容。云杉网络长期以来都与各大网络设备制造商保持产品级的深度合作,确保云杉网络解决方案能够获得优异的设备兼容性。因此,在谈及与设备厂商在实际项目中的关系时,张天鹏用“合大于竞”进行了精准的概括。 【IT葡萄皮】(公众号:itopics)由资深媒体人张垞运营。从业十二年的深度观察,只为一篇不吐不快的科技评论。 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3注册网址_青铜变王者,桌面云是如何逆袭的?

1981年8月12日,IBM公司推出世界上第一台个人电脑,并将其命名为IBM 5150。 IBM 5150 IBM 5150的出现,标志着人类正式进入了PC时代,越来越多的用户开始购买和使用计算机。 若干年后,比尔盖茨创办的微软公司陆续发布了一系列版本的Windows“视窗”操作系统。这些操作系统的使用界面,被人们亲切地称之为——桌面(DESKTOP)。 Win98的桌面,暴露了年龄 桌面的出现,降低了PC的使用难度,改善了用户体验,进而加速了PC的全面普及。 进入21世纪后,电脑硬件加速升级,软件日新月异,我们的“桌面”也变得越来越酷炫。 然而,我们会发现,陪伴我们多年的PC和“桌面”,其实并不完美。尤其是对于企业用户来说,痛点很多。 例如,当新员工领用新PC的时候,需要耗费大量时间和精力去安装操作系统、驱动程序、工作软件和补丁。 再例如,PC软硬件频繁出现的故障,往往影响员工的正常工作,浪费宝贵的时间。 更要命的是,如果本机硬盘损坏或误删,很有可能导致数据永久性丢失,给公司造成无法挽回的损失。 此外,PC的信息安全防护也是大问题。员工使用PC,可能会通过USB端口进行文件拷贝,或者通过网络进行资料外发,泄露公司机密。 面对传统PC如此之多的痛点,IT厂商们想出了一个不错的解决方案,那就是桌面云。 ▉ 什么是桌面云 桌面云,简单来说,就是把“桌面”搬到云上。 它把个人计算环境集中存储于云端,由云端按需生成桌面环境。本地用户借助终端设备和网络,可以随时随地访问和使用云端的个人桌面。 桌面云的核心技术有两个,一是虚拟化技术,二是桌面传输协议。 虚拟化技术,大家应该很熟悉了,它是云计算的基础。借助虚拟化技术,云端的服务器才能虚拟出CPU、内存、硬盘等组件,进而生成虚拟桌面。 桌面传输协议就更容易理解了,就像我们通过FTP协议下载文件一样,桌面传输协议可以帮助本地用户顺畅地访问和使用云端上面的虚拟桌面,就像使用本地PC一样。 真正意义上的第一代桌面云解决方案,诞生于2006年左右。 当时,敢于吃螃蟹的用户不多,只有一些对数据安全需求极强的用户(例如政府和银行用户)积极进行了试用。除此之外,大部分企业选择了观望。 这是为什么呢? 很简单,因为不好用。 当时的桌面云,虽然有很好的设计理念,但因为技术不成熟的原因,访问速度慢,运行效率低,用户体验差,没办法媲美传统PC。 所以,员工对桌面云心存抵触,企业管理者也顾虑重重。 后来,随着时间的推移,云计算虚拟化技术和桌面传输协议变得越来越成熟,桌面云也迅速迭代升级,带来了显著的用户体验提升。 就在桌面云苦练内功,准备再次发力的时候,外部市场的需求环境也发生了有利的变化。 首先,是移动办公需求的大爆发。 近年来,企业规模迅速扩张,异地办公变得非常普遍。旺盛的经济发展,也带来了频繁的商业差旅。这一切,都属于移动办公需求。 今年就更不用说了,意料之外的新冠疫情,让“在家上班”成了很多企业员工的常态。 第二个重大变化,就是信息安全危机的大爆发。 信息安全是企业的生存命脉。这些年来,我们经常看到员工私自拷贝核心代码甚至删库跑路的新闻。 这些行为,严重影响了企业的正常经营,甚至可能导致企业倒闭。 因此,企业越来越重视信息安全防护,迫切希望加强办公桌面环境的安全管控。尤其是移动办公场景下的安全防护,更是重中之重。 就这样,内因+外因,第二代桌面云闪亮逆袭的机会终于来了。 ▉ 既安全,又好用,桌面云是如何办到的? 说了半天,桌面云到底是如何满足用户需求的呢? 我们就拿目前国内市场占有率排名第一 * 的深信服桌面云解决方案为例,给大家详细解释一下桌面云技术的秘诀。 *数据来源:IDC《中国VDI客户终端市场追踪报告,2020Q1&Q2》 深信服桌面云解决方案,整体上包括终端接入区和数据中心区两部分。 终端接入区的设备,既可以是深信服的桌面云终端aDesk,也可以是PC、手机、PAD等常见终端。 aDesk,采用ARM架构,外形精致小巧,无风扇,无噪音,耗电量10W以内。 数据中心区,硬件上主要是桌面云一体机(VDS)和桌面云控制器(VDC)。 VDS是一款专为“云桌面”量身定制的软硬件一体化服务器, 可以建设简单、易运维、高性能的桌面云环境。VDC,虚拟桌面接入控制器,主要起管理作用,提供用户认证管理、细粒度策略控制、桌面/云终端统一监控及管理等功能。 VDS、VDC共同组成了深信服桌面云服务端,创建并管理桌面资源,为用户提供桌面服务。 下面这张图,就是一个针对软件开发场景的深信服桌面云案例。 在案例中,桌面云可以实现: 每个用户通过终端接入系统,系统会自动下发安全策略,统一管控外设的使用权限,通过设置USB黑白名单,杜绝病毒引入,也可以防止数据泄密。 本地终端所有的上网行为,都由服务端进行行为策略控制并记录,文件的外发权限也由服务端进行控制和审计。 所有虚拟桌面的数据都存储在服务端,本地终端0数据。即使拆走了本地硬盘,也带不走任何数据。 终端到云端的数据传输采用了加密通信协议,可以防止信息被窃取。 桌面可以分为开发桌面池和上网桌面池,环境物理隔离。既降低了开发环境感染病毒、遭受攻击的风险,也不影响员工使用外网查阅资料。 众所周知,深信服是一家做安全起家的公司,安全已经被刻入他们的DNA。那些凝结了深信服20年安全技术积累的分布式防火墙、屏幕水印、应用软件管控等技术,足以让系统“固若金汤”。 不管是本地办公,还是远程(移动)办公,都不留安全隐患。 一句话,老板安心! 老板安心很关键,但,不是全部。还要看员工用的爽不爽,往人性了说,它关乎员工的办公体验与情绪。往资本家了说,它关乎业务的产出效率。这背后就扯出了桌面云的终端用户体验问题。 除了安全之外,深信服的桌面云还有极佳的用户体验。 大家应该有很多人用过远程桌面软件,例如windows自带的那个。 远程桌面软件多采用RDP协议,占用带宽大,一旦网络速度慢或不稳定,就会卡顿甚至连接中断,影响正常操作。 深信服桌面云解决方案采用了自研的高效能桌面编码协议,将流量削减到极致,同时可根据链路质量自动调节画面传输帧率。单用户普通办公场景下,带宽可以降至惊人的600Kb。 有人可能觉得,桌面云从云端访问资源,性能速度肯定没有本地PC快。 其实,现在的桌面云早已今非昔比。桌面云的背后是企业级的服务器,高性能CPU、内存和硬盘,配合高性能显示协议,轻松完胜PC。即使是复杂的图形处理工作,也完全可以hold住。 最后,是IT运维简化。这简直再明显不过了。 深信服桌面云将所有桌面集中到云端,管理员可以通过Web图形化控制台进行统一的管理维护,员工在本地也可以通过自助界面进行简单维护,从而减免了大量的IT运维工作量。 利用模板克隆等技术,深信服桌面云可以在几分钟内创建上百个桌面。软件和驱动的安装部署,也只需要几秒钟就可以完成,新员工分分钟就可以开始工作。 为了拥有更高的效率,深信服还引入了AI算法,进行智能化运维。 根据粗略的估计,桌面云的维护效率相比传统PC模式,至少提升了4倍以上。 总而言之,现在的桌面云,完全可以做到老板放心、员工开心、IT运维省心。 凭借前面所说的种种优势,桌面云在企业市场受到了越来越多的用户欢迎,普及率直线上升。 包括软件开发、安全办公、图纸设计、车间操作、客服中心、第三方外包等在内的众多企业用户场景,开始抱着试一试的心态使用桌面云,并且试了之后发现,“哎哟,不错哟”。 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3注册开户_DIY | 电路与艺术相结合

来源 | 凡亿PCB 你以为搞电路只是一门技术吗? 当然不是 电路也可 是 一门艺术! 免责声明:本文部分素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。 ———— 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3内部554258_我的单片机成长之路

背景 写这篇文章的初衷要从最近带我一个朋友入坑学习单片机的经历开始讲起; 我要用梁静茹给我的勇气写写如何入坑单片机; 我的一个朋友以前是汽车电子技术专业,毕业之后去做了和汽车相关的工作,修了一年车; 其实干一行爱一行,三百六十行,行行出状元,确实挺好的; 不过修车总给他一种一眼看到头的感觉(子非鱼,安知鱼之乐?对不起,他自己告诉我的); 于是,他跳槽了,找了一份电子工程师的工作; 工作内容和我差不多,平日里打打杂; 平淡的日子就这样重复着,直到有一天,他说想学单片机;我准备给他支支招。 基础部分 DAY 1 第一天,帮他整理了整体的学习路线,基础知识篇; C语言是一本必须掌握的编程语言,看视频的效率相对来说会高一点,所以我给他推荐了B站 浙大翁恺老师的C语言视频; 因为视频还挺长的,我只推荐他看了比较基础的部分,做一下课后习题,掌握基本的语法,if,while,for等语句; 纸上得来终觉浅,学单片机还是重在实践;为了开源节流,我把以前吃灰的STM32开发板拿给他,毕竟资料很多嘛,学起来也方便; 理想是很丰满:原本计划用cubemx+st官方的HAL库来进行实践,毕竟B站还有之前开发板的配套资料也不少; 现实却很骨感: 装cubemx软件就搞的满头大汗了,最后是安装的JDK版本不对,直接裂开,一个晚上时间没了; 我给他操作了一遍使用cubemx配置自动生成代码,然后点亮一个LED,整个过程很顺利,没有写一行代码,但是我给他解释代码的时候,他是完全懵逼的状态,不知其所以然,这里有十万个黑人问号脸!!! 好吧,毕竟HAL库封装的很不错,感觉对新手不太友好(前面提到他C语言基础还不是很扎实); 后来我知道他偷偷跑去看结构体和指针的内容了。 看来还是得用51单片机,因为简单,可以先点亮一个灯,建立起兴趣; 给他推荐了某宝的一块51单片机开发板,随便找的,功能都大同小异; DAY 2 —DAY N 开发板隔天就到了,看配套视频,写下了单片机的hello world,然后灯就亮了; #include  sbit LED=P1^0;void main(void){        LED = 1;    while(1){            }} 同样是点亮一个LED,但是这次好像有内味道了,看到实验成果,他笑出了猪叫; 后面给他推荐了郭天祥的视频《十天学会单片机》; 看视频,一边补充C语言知识,一边对照着每个单片机讲解视频进行学习,视频中的讲解大多比较浅显易懂,对于新手比较友好; 把课后习题一个一个做掉,流水灯,数码管,串口,定时器,外部中断,初步掌握这些基本的外设的应用之后, 他还尝试做了一个循迹小车;虽然循迹小车比较简单,但是很有里程碑意义的,这里面涉及到传感器技术,直流电机的驱动,以及微控制器等技术; 虽然《十天学会单片机》的视频标题略显浮躁,但是作为入门,他花的时间远比十天要长,所以新手千万不要因为自己学得没有别人快而焦虑,产生挫败感,从而自我否定,自我怀疑; 但是需要及时思考和总结自己的学习方法是否高效,是否有办法优化效率; 最后,按照我个人的观点(如有偏驳,请轻拍),对于零基础的新手,方法策略是实践; 刚开始要避免学习冗杂的理论,选择简单友好的开发环境,不是一上来就是啃厚厚的理论书,学习工具链,学习Linux环境,汇编,这样学习曲线太陡峭,容易产生挫败感; 设置阶段性的学习目标,可以拆分成容易完成的小任务,每完成一个任务都能形成正向反馈,增加信心,从而坚信自己能学好,能继续学下去; 掌握对单片机进行应用的方法之后,可以以点带面,再对知识盲区进行扫盲,从而拓宽知识的广度同时,增加深度; 回归正题 好了,下面言归正传,问题是如何系统地学习单片机,所以本文着眼于讨论如何系统地学习单片机,而单片机这门技术是否有前景,则不做阐述。 如何系统地学习单片机?我感觉很难系统学习,因为这是一个多学科交叉的技术; 另外,如果你用单片机做不同的项目,应用到不同的领域,那有可能会涉及新的知识盲区; 所以是掌握好单片机这个技术的理论知识作为基础支撑,然后不断拓展自己的知识面,不断提高知识深度; 下图是我平时整理的思维导图,做的不是很好,都是每次想到一些就补充一些,所以还有些凌乱; 如果觉得对你有帮助,可以在[小麦大叔]公众号后台回复[技术思维导图]领取xmind格式的文件; 贴这张图的目的是什么呢?只是想说明和单片机相关的技术会涉及到很多东西,所以着眼点应该是加强基础知识的建设; 基础编程 C语言必须精通,但绝非一朝一夕的事情,需要大量时间去实践,去写代码,去调试,去做项目,同时还得学习理论,通过实践加深理解,推荐书籍《C 和指针》,《C 陷阱与缺陷》等; 语言只是工具,学会了C语言,你已经知道如何砌砖了,但是如何把楼盖高,盖牢,盖的好看呢? 这时候,就需要学习数据结构,算法和设计模式,这里推荐《算法导论》,《代码大全》都不错,也是经典了,而且这两本书也会长期陪伴着你; 再到后面,发现裸机编程已经很难满足学习欲望了,这时候可能会学习实时系统了,FreeRTOS,RTThread,都是十分优秀的项目; 慢慢地学会读这些项目的源码,读优秀项目的源码,这是提高很快的途径; 这时候,还不够,操作系统,微机原理(EE)/计算机组成原理(CS),这些书可以操作起来了; 后来还可能会接触到Linux,这是个庞然大物,LKD,LDD,ULK,这三本书,就够啃了;当然前提还得学会Linux环境下编程,shell脚本,makefile等等等,内容太多了,我对Linux涉猎不是很深入,如果是做应用的话,AUPE啃一下,一定会受益匪浅的; 硬件部分 模拟电子技术和数字电子技术,如果是EE科班都会开设这两门课程的,如果是非科班,零基础,可以自学一下; 推荐麻省理工的公开课《电路与电子学》,教授讲得很好,里面已经涵盖了模电和数电的内容; 原理图设计,能看懂数据手册,根据项目需求进行电子元器件的选型; 前提是,熟悉最基本的电子元器件,阻容,磁珠,MOS管,二极管等等; 另外还有功能元器件也需要了解,运放,数字IC,存储芯片等等; 但是这还远远不够,可能还要板载电源,用LDO,还是DCDC,如果是DCDC还得考虑纹波,噪声等等,不过这好像和单片机又扯远了(通常会有专门电源工程师),如果没有,那你上; PCB的Layout,需要学习一款EDA软件,Altium designer用的比较多,Pads,开源的KiCad也不错,多用用就熟练了,不懂的多问搜索引擎; Layout的设计规范可以参考一下华为的设计规范,注意一下板机的EMC,布线,铺铜,接地方式以及回流面积,如果是低速板,相对难度会小一点,硬件的坑很深,甚踩; 最后我想说的是最重要的还是实践,实践,实践,自己做个板子,发出去打样,现在打样还是很便宜了,甚至连SMT都包了,软件靠精力,硬件靠经历,多爬坑,学的就多了,会的也就多了,技术在于积累。 总结 本文简单介绍了学习单片机的技术路线,分别从软件角度和硬件角度给出了简单的方法,单片机开发是软硬结合的,所以软件的学习和硬件的学习,缺一不可; 笔者能力和水平有限,文中难免存在错误和纰漏,请大佬不吝赐教。 —— The End — — 推荐好文   点击蓝色字体即可跳转  如何优雅地解决STM32的Flash写保护的问题?  当心!别再被大小端的问题坑了  全网最通俗易懂SPWM入门教程,快来白嫖  简易PID算法的快速扫盲 增量式PID到底是什么? 三面大疆惨败,因为不懂PID的积分抗饱和 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3注册开户_Netflix是怎样做系统监控的?

原文链接:https://netflixtechblog.com/telltale-netflix-application-monitoring-simplified-5c08bfa780ba 作为知名的流媒体巨头,Netflix 在全球拥有近 2 亿订阅用户,服务遍及多个国家。本文阐述了 Netflix 的系统监控实践:自研 Telltale,成功运行并监控着 Netflix 100 多个生产应用程序的运行状况。 1 难忘的经历 相信很多运维人都有过这样的经历: 监控系统某个指标超过阈值,触发告警。大半夜里,你被紧急召唤。半睁着眼,你满脸疑惑:“系统真出问题了吗,还是仅仅需要调整下告警?上一次有人调整我们的告警阈值是在什么时候?有没有可能是上游或者下游的服务出现了问题?” 鉴于这是一次非常重要的应用告警,因此你不得不从床上爬起来,迅速打开电脑,然后浏览监控仪表盘来追踪问题源头。忙了半天,你还没确认这个告警是来自于系统的问题,但也意识到,从海量数据中寻找线索时,时间正在流逝。你必须尽快定位告警的原因,并祈祷系统稳定运行。 对我们的用户来讲,稳健的 Netflix 服务至关重要。当你坐下来看《养虎为患》时,你肯定希望它能顺利播放。 多年来,我们从经常在深夜被召唤的工程师那里了解到应用程序监控的痛点: 过多的告警 太多滚动浏览的仪表盘 太多的配置 过多的维护 https://netflixtechblog.com/full-cycle-developers-at-netflix-a08c31f83249 2 Telltale 我们的流媒体团队需要一个全新的监控系统,可以让团队成员快速地诊断和修复问题;因为在系统告警的紧急情况下,每一秒都至关重要!我们的 Node 团队 需要一个仅需一小撮人就能运维大型集群的系统。 因此,我们构建了 Telltale。 Telltale 监控时间轴  Telltale 的特性 1. 汇集监控数据源,创建整体监控视图 Telltale 汇集了各种监控数据源,从而能创建关于应用程序运行状况的整体监控视图。 2. 多维度判断应用程序的健康状况 Telltale 可以通过多个维度判断一个应用程序的健康情况,而无需根据单一指标频繁调整告警阈值。 3. 及时告警 因为我们知道应用程序在什么情况下是正常的,所以能在应用程序有异常趋势时及时通知应用程序的所有者。 4. 显示关键数据 指标是了解应用程序运行状态的关键。但很多时候,你拥有太多的指标、太多的图表以及太多的监控仪表盘。而 Telltale 仅显示应用程序中有用的相关数据及其上游和下游服务的数据。 5. 用颜色区分问题的严重程度 我们使用不同的颜色来表示问题的严重程度(除选择颜色之外,还可以让 Telltale 显示不同的数字),以便运维人员一眼就能判断出应用程序的运行状况。 6. 高亮提示 我们还会对一些监控事件进行高亮提示,比如局部区域的网络流量疏散及就近的 服务部署,这些信息对于全面了解服务的健康情况至关重要,尤其是在真正发生系统故障的情况下。 这就是我们的 Telltale 监控。它现已成功运行并提供监控服务,监控着 Netflix 100 多个生产应用程序的运行状况。 3应用程序健康评估模型 微服务并非是孤立存在和运行的。它需要特定的依赖,与其他服务进行数据交互,甚至位于不同的AWS区域。 上面的调用图是一个相对简单的图,其中涉及许多服务,实际的调用链可能会更深更复杂。一个应用程序是系统生态的一部分,它的运行状态可能会受到相关属性变化的微弱影响,也有可能会受到区域范围内某些事件的影响从而发生根本性改变。canary的启动可能会对应用程序产生一定影响。在一定程度上,上游或下游服务的部署同样也可以带来一定的影响。 https://netflixtechblog.com/automated-canary-analysis-at-netflix-with-kayenta-3260bc7acc69 Telltale 通过使用多个维度的数据源构建一个不断自我优化的模型来监控应用程序的健康度: Atlas 时序指标 区域网络流量疏散 Mantis 实时流数据 基础架构变更事件 Canary 部署及使用 上、下游服务的运行状况 表征 QoE 的相关指标 告警平台发出的报警 不同的数据源对应用程序健康度的影响权重不同。例如,与错误率增加相比,响应时间的增加对应用程序的影响要小很多;错误代码有很多,但是某些特定的错误代码的影响要比其他错误代码的影响大。 在服务下游部署 canary 可能不如在上游部署带来的效果明显 区域网络流量转移意味着某个区域的网络流量降为零而另一个区域的网络流量会加倍。你可以感受下不同的指标对于监控的影响。监控指标的具体含义决定了我们应该如何科学有效地使用它来进行监控。 https://netflixtechblog.com/project-nimble-region-evacuation-reimagined-d0d0568254d4 在构建应用程序健康状况视图时,Telltale 考虑了所有这些因素。 应用程序健康评估模型是 Telltale 的核心。 4智能监控 每个服务运维人员都知道告警阈值调整的难度。将阈值设置得太低,你会收到大量虚假告警。如果过度补偿并放宽告警阈值,就会错过重要的异常警告。这样导致的最终结果是对告警缺乏信任。Telltale 可以帮助你免除不断调整相关配置的繁琐工作。 通过提供准确的和严格管理的数据源,我们能让应用程序所有者的设置和配置过程变得更加容易。这些数据源通过按照一定的组合应用到程序的配置中,以实现最常见的服务类型配置。 Telltale 可以自动追踪服务之间的依赖关系,以构建应用程序健康评估模型中的拓扑。通过数据源管理以及拓扑监测,在不用付出很大的努力情况下就能使配置保持最新状态。那些需要手动实践的一些场景仍然支持手动配置和调整。 没有任何一个独立的算法可以适用我们所有的监控场景。因此,我们采用了混合算法,包括统计算法、基于规则的算法和机器学习算法。 不久后,我们将在 Netflix Tech Blog 上发表一篇针对我们监控算法的文章。 Telltale 还具有分析器,可用于趋势探测或内存泄漏监测。智能监控意味着我们的用户可以信赖我们的监控结果。这表明故障发生时,用户能更快地定位和解决系统异常问题。 5智能告警 智能监控必然会促进智能告警。当 Telltale 检测到应用程序中的运行异常时,就会产生异常事件。团队可以选择通过 Slack、电子邮件或 PagerDuty(均由我们的内部告警系统提供支持)进行告警。 如果该异常问题是由上游或下游系统引起的,则 Telltale…

摩登3内部554258_Redis的8大数据类型,写得非常好!

来源:https://blog.itzhouq.cn/redis2 NoSQL 开发中或多或少都会用到,也是面试必问知识点。 最近这几天的面试每一场都问到了,但是感觉回答的并不好,还有很多需要梳理的知识点,这里通过几篇 Redis 笔记整个梳理一遍。关注公众号Java技术栈回复面试也可以刷我整理的系列面试题。 Redis 的八大数据类型 官网可查看命令:http://www.redis.cn/commands.html Redis-key 127.0.0.1:6379> keys *(empty list or set)127.0.0.1:6379> set name xxxOK127.0.0.1:6379> keys *1) "name"127.0.0.1:6379> set age 1OK127.0.0.1:6379> keys *1) "age"2) "name"127.0.0.1:6379> exists name  # 判断key 是否存在(integer) 1127.0.0.1:6379> exists name1(integer) 0127.0.0.1:6379> move name 1(integer) 1127.0.0.1:6379> keys *1) "age"127.0.0.1:6379> set name yyyOK127.0.0.1:6379> expire name 10  # 设置key的过期时间,单位是秒(integer) 1127.0.0.1:6379> ttl name  # 查看当前key的剩余过期时间(integer) 7127.0.0.1:6379> ttl name(integer) -2127.0.0.1:6379> type age  # 查看当前key的类型string127.0.0.1:6379> Redis 有以下 8 种数据类型 1、String(字符串) 127.0.0.1:6379> set key1 v1   #设置值OK127.0.0.1:6379> get key1"v1"127.0.0.1:6379> append key1 "hello"  # 追加值,如果不存在,相当于 set key(integer) 7127.0.0.1:6379> get key1"v1hello"127.0.0.1:6379> strlen key1  # 获取字符串长度(integer) 7127.0.0.1:6379> 自增、自减 127.0.0.1:6379> set views 0OK127.0.0.1:6379> get views"0"127.0.0.1:6379> incr views  # 自增 1(integer) 1127.0.0.1:6379> get views"1"127.0.0.1:6379> decr views       # 自减 1(integer) 0127.0.0.1:6379> decr views(integer) -1127.0.0.1:6379> get views"-1"127.0.0.1:6379> incrby views 10  # 设置步长、自增 10 (integer) 9127.0.0.1:6379> decrby views 5      # 设置步长、自减 5(integer) 4 字符串范围 127.0.0.1:6379> set key1 "hello,world!"OK127.0.0.1:6379> get key1"hello,world!"127.0.0.1:6379> getrange key1 0 3  # 截取字符串\[0, 3\]"hell"127.0.0.1:6379> getrange key1 0 -1  # 获取全部的字符串,和 get key一样"hello,world!"127.0.0.1:6379> 替换: 127.0.0.1:6379> set key2 abcdefgOK127.0.0.1:6379> get key2"abcdefg"127.0.0.1:6379> setrange key2 1 xx(integer) 7127.0.0.1:6379> get key2"axxdefg"127.0.0.1:6379> setex(set with expire):设置过期时间 和setnx(set if not exist):不存在再设置(在分布式锁中会经常使用) 127.0.0.1:6379> setex key3 30 "hello"  # 设置 30 秒后过期OK127.0.0.1:6379> ttl key3     # 剩余过期时间(integer) 25127.0.0.1:6379> setnx mykey "redis"   # mykey 不存在时设置成功(integer) 1127.0.0.1:6379> keys *1) "key2"2) "key1"3) "views"4) "mykey"127.0.0.1:6379> setnx mykey "mongoDB"  # mykey 存在时设置失败(integer) 0127.0.0.1:6379> get mykey     # mykey 值不变"redis"127.0.0.1:6379> mset 和 mget 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3  # 同时设置多个值OK127.0.0.1:6379> keys *1) "k1"2) "k3"3) "k2"127.0.0.1:6379> mget k1 k2 k3   # 同时获取多个值1) "v1"2) "v2"3) "v3"127.0.0.1:6379> msetnx k1 v1 k4 v4       # msetnx 是一个原子性的操作,要么一起成功,要么都失败(integer) 0127.0.0.1:6379> get k4(nil)127.0.0.1:6379> 对象 set user:1 {name:zhangsan, age:3}     # 设置一个 user:1 对象 值为 json  字符来保存一个对象127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2OK127.0.0.1:6379> mget user:1:name user:1:age1) "zhangsan"2) "2"127.0.0.1:6379> getset:先 get 再 set 127.0.0.1:6379> getset db redis  # 如果不存在值,则返回 nil(nil)127.0.0.1:6379> get db"redis"127.0.0.1:6379> getset db mongodb  # 如果存在值,获取原来的值,并设置新的值"redis"127.0.0.1:6379> get db"mongodb"127.0.0.1:6379> String 的使用场景:value 除了是字符串以外还可以是数字 计数器 统计多单位的数量 粉丝数 对象缓存存储 2、List(列表) 基本的数据类型,列表。 在 Redis 中可以把 list 用作栈、队列、阻塞队列。 list 命令多数以 l开头。 127.0.0.1:6379> lpush list one   # 将一个值或者多个值,插入到列表的头部(左)(integer) 1127.0.0.1:6379> lpush list two(integer) 2127.0.0.1:6379> lpush list three (integer) 3127.0.0.1:6379> lrange list 0 -1   # 查看全部元素1) "three"2) "two"3) "one"127.0.0.1:6379> lrange list 0 1    # 通过区间获取值1) "three"2) "two"127.0.0.1:6379> rpush list right   # 将一个值或者多个值,插入到列表的尾部(右)(integer) 4127.0.0.1:6379> lrange list 0 -11) "three"2) "two"3) "one"4) "right"127.0.0.1:6379> 弹出 pop 127.0.0.1:6379> lrange list 0 -11) "!"2) "world"3) "world"4) "hello"127.0.0.1:6379> lpop list  # 移除list的第一个元素"!"127.0.0.1:6379> lrange list 0 -11) "world"2) "world"3) "hello"127.0.0.1:6379> rpop list   # 移除list的第一个元素"hello"127.0.0.1:6379> lrange list 0 -11) "world"2) "world"127.0.0.1:6379> 索引 Lindex 127.0.0.1:6379> lrange list 0 -11) "hjk"2) "world"3) "world"127.0.0.1:6379> lindex list 1  # 通过下标获取list中的某一个值"world"127.0.0.1:6379> lindex list 0"hjk"127.0.0.1:6379> Llen 长度: 127.0.0.1:6379> llen list(integer) 3127.0.0.1:6379> 移除指定的值: 127.0.0.1:6379> lrange list 0 -11) "hjk"2) "world"3) "world"127.0.0.1:6379> lrem list 1 world  # 移除list集合中指定个数的value,精确匹配(integer) 1127.0.0.1:6379> lrange list 0 -11) "hjk"2) "world"127.0.0.1:6379> lpush list hjk(integer) 3127.0.0.1:6379> lrange list 0 -11) "hjk"2) "hjk"3) "world"127.0.0.1:6379> lrem list 2 hjk(integer) 2127.0.0.1:6379> lrange list 0 -11) "world"127.0.0.1:6379> trim 截断 127.0.0.1:6379> lrange mylist 0 -11) "hello1"2) "hello2"3) "hello3"4) "hello4"127.0.0.1:6379> ltrim mylist 1 2 # 通过下标截取指定长度,这个list已经被破坏了,截断之后只剩下截断后的元素OK127.0.0.1:6379> lrange mylist 0 -11) "hello2"2) "hello3"127.0.0.1:6379> rpoplpush :移除列表的最后一个元素,将他移动到新的列表中。 127.0.0.1:6379> lrange mylist 0 -11) "hello1"2) "hello2"3) "hello3"127.0.0.1:6379> rpoplpush mylist myotherlist  # 移除列表的最后一个元素,将他移动到新的列表中。"hello3"127.0.0.1:6379> lrange mylist 0 -1  # 查看原来的列表1) "hello1"2) "hello2"127.0.0.1:6379> lrange myotherlist 0 -1  # 查看目标列表中,确实存在该值1) "hello3"127.0.0.1:6379> lset:将列表中指定下标的值替换为另一个值,更新操作 127.0.0.1:6379> exists list  # 判断这个列表是否存在(integer) 0127.0.0.1:6379> lset list 0 item  # 如果不存在的话,更新会报错(error) ERR no such key127.0.0.1:6379> lpush list value1(integer) 1127.0.0.1:6379> lrange list 0 0 1) "value1"127.0.0.1:6379> lset list 0 item  # 如果存在,更新当前下标的值OK127.0.0.1:6379> lset list 1 other  # 如果不存在的话,更新会报错(error) ERR index out of range127.0.0.1:6379> linsert:将某个具体的value插入到列表中某个元素的前面或者后面 127.0.0.1:6379> lrange mylist 0 -11) "hello1"2) "hello2"127.0.0.1:6379> linsert mylist before "hello2" hello(integer) 3127.0.0.1:6379> lrange mylist 0 -11) "hello1"2) "hello"3) "hello2"127.0.0.1:6379> linsert mylist after "hello2" hello(integer) 4127.0.0.1:6379> lrange mylist 0 -11) "hello1"2) "hello"3) "hello2"4) "hello"127.0.0.1:6379> 小结: list 实际上是一个链表,前后都可以插入 如果key不存在,创建新的链表 如果移除了所有的值,空链表,也代表不存在 在两边插入或者改动值,效率最高。 3、Set (集合) 127.0.0.1:6379> sadd myset "hello"  # set 集合中添加元素(integer) 1127.0.0.1:6379> sadd myset "world"(integer) 1127.0.0.1:6379> smembers myset      # 查看指定Set的所有值1) "world"2) "hello"127.0.0.1:6379> sismember myset hello  # 判断某一个值是不是在set中(integer) 1127.0.0.1:6379> sismember myset hello1(integer) 0127.0.0.1:6379> 127.0.0.1:6379> scard myset  # 获取集合中的个数(integer) 2127.0.0.1:6379> sadd myset "hello2"(integer) 1127.0.0.1:6379> smembers myset   1) "world"2) "hello2"3) "hello"127.0.0.1:6379> srem myset hello   # 移除元素(integer) 1127.0.0.1:6379> smembers myset1) "world"2) "hello2"127.0.0.1:6379> 127.0.0.1:6379> smembers myset1) "kkk"2) "world"3) "hjk"4) "hello2"127.0.0.1:6379> srandmember myset   # 随机抽取一个元素"hjk"127.0.0.1:6379> srandmember myset"hello2"127.0.0.1:6379> srandmember myset 2   # 随机抽取指定个数的元素1) "world"2) "hello2"127.0.0.1:6379> srandmember myset 21) "hello2"2) "hjk"127.0.0.1:6379> 127.0.0.1:6379> smembers myset1) "kkk"2) "world"3) "hjk"4) "hello2"127.0.0.1:6379> spop myset  # 随机删除元素"hjk"127.0.0.1:6379> smembers myset1) "kkk"2) "world"3) "hello2"127.0.0.1:6379> spop myset"hello2"127.0.0.1:6379> smembers myset1) "kkk"2) "world"127.0.0.1:6379> 127.0.0.1:6379> smembers myset1) "kkk"2) "world"127.0.0.1:6379> sadd myset2 set2(integer) 1127.0.0.1:6379> smove myset myset2 "kkk"   # 将一个特定的值,移动到另一个set集合中(integer) 1127.0.0.1:6379> smembers myset1) "world"127.0.0.1:6379> smembers myset21) "kkk"2) "set2"127.0.0.1:6379> 127.0.0.1:6379> smembers key11) "b"2) "a"3) "c"127.0.0.1:6379> smembers key21) "e"2) "d"3) "c"127.0.0.1:6379> sdiff key1 key2   # 差集1) "b"2) "a"127.0.0.1:6379> sinter key1 key2         # 交集1) "c"127.0.0.1:6379> sunion key1 key2  # 并集1) "e"2) "a"3) "c"4) "d"5) "b" 4、Hash(哈希) 也是 key – value 形式的,但是value 是一个map。 127.0.0.1:6379> hset myhash field xxx  # set 一个 key-value(integer) 1127.0.0.1:6379> hget myhash field   # 获取一个字段值"xxx"127.0.0.1:6379> hmset myhash field1 hello field2 world  # set 多个 key-valueOK127.0.0.1:6379> hmget myhash field field1 field2   # 获取多个字段值1) "xxx"2) "hello"3) "world"127.0.0.1:6379> hgetall myhash    # 获取全部的数据1) "field"2) "xxx"3) "field1"4) "hello"5) "field2"6) "world" 127.0.0.1:6379> hdel myhash field1  # 删除指定的key,对应的value也就没有了(integer) 1127.0.0.1:6379> hgetall myhash1) "field"2) "xxx"3) "field2"4) "world"127.0.0.1:6379> 127.0.0.1:6379> hlen myhash  # 获取长度(integer) 2127.0.0.1:6379> hexists myhash field1   # 判断指定key是否存在(integer) 0127.0.0.1:6379> hexists myhash field2(integer) 1127.0.0.1:6379> hkeys myhash  # 获取所有的key1) "field"2) "field2"127.0.0.1:6379> hvals myhash  # 获取所有的value1) "xxx"2) "world"127.0.0.1:6379> 127.0.0.1:6379> hset myhash field3 5(integer) 1127.0.0.1:6379> hincrby myhash field3 1  # 指定增量(integer) 6127.0.0.1:6379> hincrby myhash field3 -1(integer) 5127.0.0.1:6379> hsetnx myhash field4 hello  # 如果不存在则可以设置(integer) 1127.0.0.1:6379> hsetnx myhash field4 world  # 如果存在则不能设置(integer) 0127.0.0.1:6379> Hash 适合存储经常变动的对象信息,String 更适合于存储字符串。关注公众号Java技术栈,回复 Redis,可以获取我整理的 Redis 系列教程。…

摩登3娱乐怎么样?_5G领跑者的坚守

全球领先的综合通信解决方案提供商 中国最大的通信设备上市公司 全球最具价值品牌500强 国家高新技术创新示范企业 …… 这是中兴通讯的印迹 而疫情之下的2020年 全球经济形势严峻 中兴通讯的步子迈向何方? 后疫情时代,5G引领下的数字经济加速 中兴通讯在5G领域又有哪些动作? 本期《璐演》对话 中兴通讯执行副总裁 首席运营官谢峻石 在主持人邓璐博士的“三问”中 我们似乎可以找到答案 (建议在wifi环境下观看专访视频) 惟其艰难,更显勇毅。 2020世界5G大会期间,中兴通讯以“筑路数字经济,绽放5G价值”为参展主题亮相大会,带来最新创新技术和方案,展示新基建大背景下如何利用5G技术赋能各行各业数字化转型的典型场景成功案例。 Q1 2019年业绩说明会,李自学董事长表示 2019年是“谨慎、艰难、扎实”的一年。 如果让您来形容2020年的中兴 您会用什么词? 关键词:“三步走”战略 谢峻石 实际上我们在2018年之后对中兴通讯新的发展制定了“三步走”的战略。 2018年到2019年是恢复期,希望公司的经营能够恢复到2017年的水平;2020年到2021年是发展期;2022年我们希望公司能够进入战略的超越期,所以2019年属于我们恢复期的最后一年。 从今年年初疫情到中国5G的快速发展,我觉得作为我们中兴通讯战略发展期的第一年,为我们后续的发展奠定了良好基础。 如果要用几个词来形容2020年的中兴通讯,我想第一个是“凝心聚力”,尤其是在今年疫情当下,我们所有7万名员工跟我们全球的客户合作伙伴以及整个产业链一起凝心聚力,为整个通信行业的发展,为整个5G的发展贡献自己的力量。我们克服供应链、生产、生活等方面的困难,大家携手同行。聚的是力量,聚的是人心。 第二个词我想用“突破”,中国5G商用一年多,今年第三季度我国已提前完成了年底建成60万个5G基站的目标,有1.6亿的终端的连接。 全球的数据是95万个基站,中国已经超过了70%,这里面中兴通讯也做出了自己应有的贡献。我们目前在国内的基站发货数量已超过20万个,基本上是占比超过30%的市场份额,同时我们也积极拉动我们上下游的合作伙伴,一起来建立一个5G开放共赢的生态。 不管是在国内的5G建设,还是在整个5G行业,甚至包括在我们整个全球各业务方面,我们还是取得了一定的突破。 第三是“数字化”。这也是今年的热门话题。所有的伟大其实都是被逼出来的,如果没有这种外在的动力压力,其实一个企业发生变化也是蛮难的一件事情。 罗马不是一天建成的,中兴的数字化也不是一天铸就的。 面对行业的碎片化需求,中兴通讯以行业场景为中心,依托分布式精准云和确定性精准网,为行业客户提供积木式灵活便捷的云网融合定制方案,助力行业转型升级。 目前中兴通讯已在工业、交通、能源等15个行业发展了超过500家合作伙伴,共同探索了86个5G创新应用场景,全球范围成功开展超过60个示范项目。 在5G行业展区,中兴通讯集中带来了5G智慧交通、5G智慧钢铁、5G智能电网、5G智能制造、5G全息访谈等7大行业应用成果展示。 其中5G智慧钢铁以沙盘形式,直观地呈现了基于5GC下沉的工业互联专网,在高炉皮带机器人、风机预测性维护、机器视觉、无人智能行车等多个场景部署的5G创新应用,该项目由广东联通、湛江宝钢、上海宝信、中兴通讯联合打造,是全国第一个商用的整套5GC下沉的工业互联专网,荣获工信部第三届“绽放杯”大赛一等奖。 Q2 怎么去定义中兴的角色? 是领跑者还是跟随者? 5G商用中国一定是领跑者,你认同吗? 关键词:5G先锋 谢峻石 我们在2016年给自己定义的就是“5G先锋”角色。我们希望能够做到技术领先、商用领先,以及市场规模的领先。从今年的情况来看,我觉得我们至少在5G领域是领跑者。 至于中国在5G商用上的领跑,我非常认同,而且我们也有底气跟信心,使得中国在全球5G领域成为一个领跑者。 第一,国家重视。把5G上升到整个国家的战略,已经作为新基建的一个基石,得到了各级政府的大力支持。 第二,我们整个通信行业里面不管是中兴还是华为,在国内已经有一个不断成熟的产业链,而且我们确实在5G这个领域已经处于领先地位。 中国在5G标准必要专利的占比已占全球35% 以上,也意味着我们已经成为规则制定的参与者,我想这是非常大的变化。 第三,现在整个中国科技创新的氛围浓厚。一个是创新的驱动,第二个是我们的人口红利,使得我们的创新更容易转化为成果,这也进一步驱动我们愿意在创新上进行投入。 Q3 中兴通讯2017-2019年年均研发 投入约121亿元,但并未快速转化成盈利。 如何看待这个颇为尖锐的问题? 关键词:研发投入产出比 谢峻石 实际上我们从最早的90年代自主研发出第一台数字程控交换机后,就一直坚持在研发投入下功夫,积累到今天才有5G的领先。 我们现在基本上已经步入了业务增长,然后再加大技术投入,技术领先带来下一轮的业务增长的良性循环中。 通信行业有两个特点: 第一,你没有办法做“小而美”的公司,我们必须要保持不断的增长,这是我们前进的方向。 第二,我们一定要有市场占有率的不断提升。如果哪一天我们能够在这个行业里排名第三,甚至第二,我们整个的收益或者研发投入的一个产出比才能够更高。 5G正成为新基建的核心引擎。中兴通讯致力于成为数字经济筑路者。 在产业层面,中兴通讯定位为数字化产业的引领者,聚焦数字信息领域,不做“万能胶”,坚持在自身领域做强做扎实;   在方案层面,采用精简积木化组合架构,为行业客户定制精准服务,让不同的领域能够快速的实施;   在产品层面,发挥芯片、嵌入式操作系统、数据库等核心技术优势,支撑各行业数字化解决方案,为用户来赋能,来提升整个产业的快速成熟度。 目前中兴通讯正不断加大研发投入,持续创新,例如中兴通讯基于Massive MIMO技术的深厚积累,创新提出SSB 1+X立体协同覆盖方案,可将高层楼宇的覆盖性能提升30%以上;推出PowerPilot绿色节能解决方案,在传统载波/通道/符号关断和深度休眠等基础节能技术上,进一步通过引入AI算法,在保护用户体验基础上最大化降低网络能耗,目前已在全球20多张网络超过600,000站点商用等。 在自主研发展区,中兴通讯重点展示了自研芯片、操作系统、分布式数据库、数通产品等领域取得的最新成果,其中工业级操作系统获得中国工业大奖,已在电信、高铁等关键行业广泛应用;GoldenDB分布式数据库已率先在大型银行核心业务系统成功投产。 中兴进入5G领域已经有很多年的累积,谢峻石觉得,在广东或者粤港澳大湾区实现5G商用可能会更优先、更领先的原因,主要在于创新氛围和行业聚集。 “整个大湾区的年轻活力、对人才的培育培养机制特别好,形成了大家一起创新的氛围。另外,物以类聚,大家抱团打天下,5G行业里越来越多的人聚集在此。5G时代,我们不是工业时代的零和关系,更像在热带雨林一个共生的生态里,大家一起把上下游的产业链聚合起来,才能够把共同的事业做大。” ▲ 谢  峻  石 当疫情给世界经济按下了暂停键时,5G所引领的数字经济新发展却给经济重新启动注入新动能,为疫情防控、保障人民生活、对冲行业压力、促进传统经济转型提供了有力支撑。 。不难看出,中兴通讯正努力走出困境,携手行业合作伙伴共探5G,赋能千行百业,推进5G产业生态繁荣,推动数字经济发展再上新台阶。 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!