• 关于

    竞争算法怎么用

    的搜索结果

回答

最大的收获应该是对Java知识体系的补充,之前的自己的知识,怎么说呢,比较零散,不成框架与体系,总是这个学一点,那个学一点,工作要用什么就学什么,总是流于表面,对知识总是知道怎么用,但是为什么这样用,为什么这样设计,却没有深究,技术总是停滞在新手阶段。 趁着寒假,参加了阿里云的这次的21天打卡计划,至少自己养成了好的习惯,每天早起,坚持打卡,边学习边制作思维导图,用自己的话语讲述知识点,进行提炼总结,再自己手敲一边代码,进行实践。将知识融会贯通。在技术上获得了一些进步。也养成了不错的习惯。 阿里的技术图谱确实不错,内容很多很全,而且有很多阿里团队自己总结的一些电子书。总体上不错,但一些知识,比如Java高级工程师需要掌握的,比如JUC,JVM的知识没有或者不是那么的全面,一些框架mybatis,spring mvc, spring的一些源码知识也没有。可能需要后期补充上去。另外每个视频,应该是与一些培训班合作的,里面只有视频,没有对应的课件资料与源码,不方便学习。 作为Java开发者,我觉得Java的优势容易上手,生态很全面,基本上国内Java开发人数是最多的,竞争压力也是最大的。作为后端语言,目前的竞争对手是Go,Go在线程上的处理与云原生的一些方面有优势。等Java的协程出来,应该能弥补。Java的优势应该是JVM虚拟机,可以Write once, run anywhere。没有了C与C++的指针,而且越来越先进的GC算法,性能也上来了。还有强大的安全机制,很适合很多人写大型项目。 推荐的书籍,如果是新手,推荐看Java核心技术卷1与2。如果是3年工作经验的,推荐Java编程思想,深入理解Java虚拟机,高性能MySQL,Redis深度历险,Java并发编程实战,Head First Java,阿里的Java开发手册也不错,养成良好的编码习惯。有时间可以多刷刷LeetCode题目,对数据结构与算法有更好的理解。或者静下心来,多看看源码,理解大概的思想,借鉴别人写的不错的地方。多写写博客,做学习总结。
woshiamiaojiang 2021-03-04 10:36:37 0 浏览量 回答数 0

问题

人工智能技术百问——机器真的能取代人类吗

随着科技的飞速发展,“人工智能”无疑成为了当下最火的词。在这一领域,我们仍处于非常初级的阶段,很多事情我们还不了解。它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、...
yq传送门 2019-12-01 20:27:57 4467 浏览量 回答数 3

问题

我也想写点什么

其实好早之前就想写点什么了,参加这个竞赛,感触很多。 我从3月10几号比赛开始没几天就参加比赛了,从第一次在本地hadoop上运行程序,提交了所有的接触过的品牌,获得了2...
猥琐屯公爵 2019-12-01 21:55:06 6158 浏览量 回答数 2

问题

分库分表之后,id 主键如何处理?【Java问答】43期

面试题 分库分表之后,id 主键如何处理? 面试官心理分析 其实这是分库分表之后你必然要面对的一个问题,就是 id 咋生成?因为要是分成多个表之后,每个表都是从 1...
剑曼红尘 2020-06-23 11:48:33 23 浏览量 回答数 1

回答

疫情下的2020,程序员找工作和往年有什么不同?该如何寻找方向? ###行业环境 曾经 以前端为例,早期(2009年之前)的程序员岗位中,甚至都没有单独的前端岗位。页 面UI的设计与开发大多数都有后端包揽。存在感很小,那时候的程序员,也没有如今的火 热,在那个年代,金融行业仍是主流;那个电脑,程序员并没有如现在这般被大众所熟知与多金。 十年来风云莫测,Java易主了,node.js诞生了,互联网行业又重新注入了新的活力。 互联网行业同时也带动了周边相关行业的发展,比如IT培训、在线教育、社交电商等等, 从2011年淘宝双十一开始,淘宝真正成为国民电商平台的霸主。淘宝这个最大的电商平台, 可以说是一个集众多IT技术于一身的一个产物了。也是开启互联网时代的领头人,现如今 的时代,是移动互联网的世界。IT作为一个未来一个大时代的走向,是会越来越成熟,越 来越奔放的。 就薪资而言,曾经一直占领行业薪资top的金融行业,如今也被互联网岗位所取代。看到这里你可能会说某某财务总监年薪百万,可是你可曾想过,一个普通公司也许就那么一位或几位年薪百万的财务总监,但是在阿里巴巴这样的企业里,年薪百万未必非要坐上财务总监的位置,不完全统计,年薪百万的阿里人(开发岗)不低于4位数,技术驱动核心竞争力。那个时代,HTML5出世,移动互联网也迎来红利期,微信、今日头条、抖音等超级APP相继诞生 现在 不知怎么了,2019年起互联网行业内出现了很大波动,大批中小微企业倒闭、员工事业,不景气的企业用着正规或不正规的手段裁员,校招紧缩,员工生病被辞退等新闻被揭露。也许是互联网行业走向成熟,伴随着的优胜略汰的现象,如今的互联网,再也不是随便随便拿着PPT去路演就能拿到投资的行业,个人觉得,互联网行业在2020年将从“平台为王”向“服务为王”进行转换,谁能在服务上获得用户的认可,谁就有可能会获得更快的发展速度,所以对于大型互联网平台来说,2020年所面临的挑战还是非常大的。如果说在增量时代,互联网行业拼的是速度,那么在存量时代,互联网行业将开始拼服务,而服务体验度的不断提升是互联网行业发展的一个必然结果。 程序员现状 过去 过去的程序员找工作只要技术够牛就不会愁工作,2013年网上还盛传企业去教育培训机构挖人的新闻,如今这种现象是不会存在的。这也许就是一个行业走向稳定和成熟所伴随的稳重而不盲目。 对于程序员而言,所要关注的不该仅仅是技术本身了,学历、英语、沟通与表达能力也都非常重要。而前端为例,曾经写写jQ就能找到一份工作,在无内推的情况下,如今不会三大框架可能连简历都筛选不过去,行内盛传一句戏谑的话”面试造火箭,工作拧螺丝”,如今确实如此。个人决定,尽管行业不如从前,招聘要求也越来越高,作为一个有志气有报复的程序员,就应该紧跟行业的脚步,保持对行业的敏感,时时刻刻不能放弃学习,欲戴王冠必承其重。无论大家处于哪些行业哪种岗位,无论你是做算法岗还是业务应用开发,你都是在为互联网行业提供自己的一份力。GITHUB、StackOverFlow、掘金上那么多活跃的前辈、队友都在为互联网积极贡献开源项目,为这个行业发光发热。 未来 因为笔者是前端岗,我就以前端岗为例谈谈对当下及未来前端岗位的发展方向和技术要求。 当下前端热门的话题有AI、跨端应用、音视频等等。前端做AI在以前看来是否是不可能的事,我想大多数人和我一样,第一次听见“人工智能”这个词的时候都会觉得是一个很高大上、遥不可及的概念,我们对它的印象总是停留在各种各样神奇而又复杂的算法,这些仿佛都是那些名校博士才有能力去做的工作。我也曾一度以为自己和这个行业没有太多缘分,但自从Tensorflow发布了JS版本之后,这一领域又引起了我的注意。在python垄断的时代,发布JS工具库不就是意味着我们前端工程师也可以参与其中。可以参考JS图像识别项目(https://github.com/jerryOnlyZRJ/image-regression)。 随着JS引擎的计算能力不断增强,人工智能领域的不断发展,可以预见的是,在不久的将来,肯定能有一些简单的算法可以被移植到用户前端执行,这样既能减少请求,又能分担后端压力。这一切并不是无稽之谈,为什么tensorflow.js会应运而生,正是因为JS的社区在不断壮大,JS这款便捷的语言也在得到更为普遍的使用。 还是应征了那句老话:技术从来不会受限于语言,受限你的,永远只是思想。 谈到前端前端框架,目前有 Vue、React、Svelte、Angular (按GITHUB排行榜);初次之外,各种平台的框架也都层次不穷,以小程序为例就有taro、omi、uniapp、mpx、mpvue等等,前端轮子多,总有一款适合你。但是探究和比较框架已经没有实际意义了,狼叔在2019年的D2论坛上的演讲,其中那句话令我记忆深刻,“前端的纷争已经结束,接下来的重点是提效”,现在已经不是争论三驾马车和flutter框架之争、性能之争,而是如何运用前端技术去发力、提高生成效能。因为最终我们的生产成果需要接收社会大众的检验,学好技术是过程,做好产品是结果,不该把时间放在没有效率的事上。 保持学习的热情,保持编码的的热情,无论你现在是写算法亦或是写业务,术业有专职。 前端面试指南 针对招聘需求可能会要求的一些技术栈,我整理一些常用的前端框架和技能,但是很不够全面,比如canvs、webgl、threeJs、phaser、pixi等等绘图、可视化相关的东西都没有列举到,仅供大家参考。 2020谁的码生不迷茫 码生如佛,弓象征着码生的曲曲折折,一撇是那曾经走的弯路,那一竖是将要走的路,2020年,希望大家大道至简,学会权衡,懂得舍弃,持续进化,抓住机遇。共勉~
问问小秘 2020-03-23 10:08:43 0 浏览量 回答数 0

问题

10天学会SEO:第二天SEO基础知识(二)

这是野狼10天学会SEO教程的第二天,今天继续了解SEO的基础。SEO基础部分,我们分为两天来学,第一天主要是一个心态调整以及从大局上对SEO工作有一个简单的认识,那么第二天就会学一些...
野狼seo团队 2019-12-01 21:58:14 8728 浏览量 回答数 7

问题

19年BAT常问面试题汇总:JVM+微服务+多线程+锁+高并发性能

一、Java 并发编程 1、在 java 中守护线程和本地线程区别? 2、线程与进程的区别? 3、什么是多线程中的上下文切换? 4、死锁与活锁的区别,死锁与饥饿的区别ÿ...
游客pklijor6gytpx 2020-01-09 10:31:29 1271 浏览量 回答数 3

问题

dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?【Java问答学堂】49期

面试题 dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢? 面试官心理分析 继续深问吧,这些都是用 dubbo 必须知道的一些东西,你得知道基本原理,...
剑曼红尘 2020-07-02 17:35:03 17 浏览量 回答数 1

问题

Java技术1000问(3)【精品问答】

为了方便Java开发者快速找到相关技术问题和答案,开发者社区策划了Java技术1000问内容,包含最基础的Java语言概述、数据类型和运算符、面向对象等维度内容。 我们会以每天至少50条的速度,增...
问问小秘 2020-06-02 14:27:10 11463 浏览量 回答数 3

问题

如何自己设计一个类似 Dubbo 的 RPC 框架?【Java问答学堂】54期

面试题 如何自己设计一个类似 Dubbo 的 RPC 框架? 面试官心理分析 说实话,就这问题,其实就跟问你如何自己设计一个 MQ 一样的道理,就考两个: 你有没...
剑曼红尘 2020-07-09 10:30:28 30 浏览量 回答数 1

问题

电商网站的商品详情页系统架构【Java问答学堂】61期

小型电商网站的商品详情页系统架构 小型电商网站的页面展示采用页面全量静态化的思想。数据库中存放了所有的商品信息,页面静态化系统,将数据填充进静态模板中,形成静态化页面,推入 Ngin...
剑曼红尘 2020-07-20 13:08:17 1491 浏览量 回答数 2

回答

遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?Java 中 List 遍历的最佳实践是什么? 遍历方式有以下几种: for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。 foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。 最佳实践:Java Collections 框架中提供了一个 RandomAccess 接口,用来标记 List 实现是否支持 Random Access。 如果一个数据集合实现了该接口,就意味着它支持 Random Access,按位置读取元素的平均时间复杂度为 O(1),如ArrayList。如果没有实现该接口,表示不支持 Random Access,如LinkedList。 推荐的做法就是,支持 Random Access 的列表可用 for 循环遍历,否则建议用 Iterator 或 foreach 遍历。 说一下 ArrayList 的优缺点 ArrayList的优点如下: ArrayList 底层以数组实现,是一种随机访问模式。ArrayList 实现了 RandomAccess 接口,因此查找的时候非常快。ArrayList 在顺序添加一个元素的时候非常方便。 ArrayList 的缺点如下: 删除元素的时候,需要做一次元素复制操作。如果要复制的元素很多,那么就会比较耗费性能。插入元素的时候,也需要做一次元素复制操作,缺点同上。 ArrayList 比较适合顺序添加、随机访问的场景。 如何实现数组和 List 之间的转换? 数组转 List:使用 Arrays. asList(array) 进行转换。List 转数组:使用 List 自带的 toArray() 方法。 代码示例: ArrayList 和 LinkedList 的区别是什么? 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全; 综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。 补充:数据结构基础之双向链表 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。 ArrayList 和 Vector 的区别是什么? 这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。性能:ArrayList 在性能方面要优于 Vector。扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。 Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。 Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。 插入数据时,ArrayList、LinkedList、Vector谁速度较快?阐述 ArrayList、Vector、LinkedList 的存储性能和特性? ArrayList、LinkedList、Vector 底层的实现都是使用数组方式存储数据。数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。 Vector 中的方法由于加了 synchronized 修饰,因此 Vector 是线程安全容器,但性能上较ArrayList差。 LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但插入数据时只需要记录当前项的前后项即可,所以 LinkedList 插入速度较快。 多线程场景下如何使用 ArrayList? ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。例如像下面这样: 为什么 ArrayList 的 elementData 加上 transient 修饰? ArrayList 中的数组定义如下: private transient Object[] elementData; 再看一下 ArrayList 的定义: public class ArrayList extends AbstractList implements List<E>, RandomAccess, Cloneable, java.io.Serializable 可以看到 ArrayList 实现了 Serializable 接口,这意味着 ArrayList 支持序列化。transient 的作用是说不希望 elementData 数组被序列化,重写了 writeObject 实现: 每次序列化时,先调用 defaultWriteObject() 方法序列化 ArrayList 中的非 transient 元素,然后遍历 elementData,只序列化已存入的元素,这样既加快了序列化的速度,又减小了序列化之后的文件大小。 List 和 Set 的区别 List , Set 都是继承自Collection 接口 List 特点:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。 Set 特点:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。 另外 List 支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。 Set和List对比 Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变 Set接口 说一下 HashSet 的实现原理? HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为PRESENT,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。 HashSet如何检查重复?HashSet是如何保证数据不可重复的? 向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合equles 方法比较。 HashSet 中的add ()方法会使用HashMap 的put()方法。 HashMap 的 key 是唯一的,由源码可以看出 HashSet 添加进去的值就是作为HashMap 的key,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V。所以不会重复( HashMap 比较key是否相等是先比较hashcode 再比较equals )。 以下是HashSet 部分源码: hashCode()与equals()的相关规定: 如果两个对象相等,则hashcode一定也是相同的 两个对象相等,对两个equals方法返回true 两个对象有相同的hashcode值,它们也不一定是相等的 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖 hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。 ** ==与equals的区别** ==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同 ==是指对内存地址进行比较 equals()是对字符串的内容进行比较3.==指引用是否相同 equals()指的是值是否相同 HashSet与HashMap的区别 Queue BlockingQueue是什么? Java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。 在 Queue 中 poll()和 remove()有什么区别? 相同点:都是返回第一个元素,并在队列中删除返回的对象。 不同点:如果没有元素 poll()会返回 null,而 remove()会直接抛出 NoSuchElementException 异常。 代码示例: Queue queue = new LinkedList (); queue. offer("string"); // add System. out. println(queue. poll()); System. out. println(queue. remove()); System. out. println(queue. size()); Map接口 说一下 HashMap 的实现原理? HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 HashMap的数据结构: 在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。 HashMap 基于 Hash 算法实现的 当我们往Hashmap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,则覆盖原始值;(2)如果key不同(出现冲突),则将当前的key-value放入链表中获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。 需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn) HashMap在JDK1.7和JDK1.8中有哪些不同?HashMap的底层实现 在Java中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是:寻址容易,插入和删除困难;链表的特点是:寻址困难,但插入和删除容易;所以我们将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做拉链法的方式可以解决哈希冲突。 JDK1.8之前 JDK1.8之前采用的是拉链法。拉链法:将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。 JDK1.8之后 相比于之前的版本,jdk1.8在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。 JDK1.7 VS JDK1.8 比较 JDK1.8主要解决或优化了一下问题: resize 扩容优化引入了红黑树,目的是避免单条链表过长而影响查询效率,红黑树算法请参考解决了多线程死循环问题,但仍是非线程安全的,多线程时可能会造成数据丢失问题。 HashMap的put方法的具体流程? 当我们put的时候,首先计算 key的hash值,这里调用了 hash方法,hash方法实际是让key.hashCode()与key.hashCode()>>>16进行异或操作,高16bit补0,一个数和0异或不变,所以 hash 函数大概的作用就是:高16bit不变,低16bit和高16bit做了一个异或,目的是减少碰撞。按照函数注释,因为bucket数组大小是2的幂,计算下标index = (table.length - 1) & hash,如果不做 hash 处理,相当于散列生效的只有几个低 bit 位,为了减少散列的碰撞,设计者综合考虑了速度、作用、质量之后,使用高16bit和低16bit异或来简单处理减少碰撞,而且JDK8中用了复杂度 O(logn)的树结构来提升碰撞下的性能。 putVal方法执行流程图 ①.判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容; ②.根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③; ③.判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals; ④.判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向⑤; ⑤.遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可; ⑥.插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。 HashMap的扩容操作是怎么实现的? ①.在jdk1.8中,resize方法是在hashmap中的键值对大于阀值时或者初始化时,就调用resize方法进行扩容; ②.每次扩展的时候,都是扩展2倍; ③.扩展后Node对象的位置要么在原位置,要么移动到原偏移量两倍的位置。 在putVal()中,我们看到在这个函数里面使用到了2次resize()方法,resize()方法表示的在进行第一次初始化时会对其进行扩容,或者当该数组的实际大小大于其临界值值(第一次为12),这个时候在扩容的同时也会伴随的桶上面的元素进行重新分发,这也是JDK1.8版本的一个优化的地方,在1.7中,扩容之后需要重新去计算其Hash值,根据Hash值对其进行分发,但在1.8版本中,则是根据在同一个桶的位置中进行判断(e.hash & oldCap)是否为0,重新进行hash分配后,该元素的位置要么停留在原始位置,要么移动到原始位置+增加的数组大小这个位置上 HashMap是怎么解决哈希冲突的? 答:在解决这个问题之前,我们首先需要知道什么是哈希冲突,而在了解哈希冲突之前我们还要知道什么是哈希才行; 什么是哈希? Hash,一般翻译为“散列”,也有直接音译为“哈希”的,这就是把任意长度的输入通过散列算法,变换成固定长度的输出,该输出就是散列值(哈希值);这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。 所有散列函数都有如下一个基本特性**:根据同一散列函数计算出的散列值如果不同,那么输入值肯定也不同。但是,根据同一散列函数计算出的散列值如果相同,输入值不一定相同**。 什么是哈希冲突? 当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们就把它叫做碰撞(哈希碰撞)。 HashMap的数据结构 在Java中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是:寻址容易,插入和删除困难;链表的特点是:寻址困难,但插入和删除容易;所以我们将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做链地址法的方式可以解决哈希冲突: 这样我们就可以将拥有相同哈希值的对象组织成一个链表放在hash值所对应的bucket下,但相比于hashCode返回的int类型,我们HashMap初始的容量大小DEFAULT_INITIAL_CAPACITY = 1 << 4(即2的四次方16)要远小于int类型的范围,所以我们如果只是单纯的用hashCode取余来获取对应的bucket这将会大大增加哈希碰撞的概率,并且最坏情况下还会将HashMap变成一个单链表,所以我们还需要对hashCode作一定的优化 hash()函数 上面提到的问题,主要是因为如果使用hashCode取余,那么相当于参与运算的只有hashCode的低位,高位是没有起到任何作用的,所以我们的思路就是让hashCode取值出的高位也参与运算,进一步降低hash碰撞的概率,使得数据分布更平均,我们把这样的操作称为扰动,在JDK 1.8中的hash()函数如下: static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);// 与自己右移16位进行异或运算(高低位异或) } 这比在JDK 1.7中,更为简洁,相比在1.7中的4次位运算,5次异或运算(9次扰动),在1.8中,只进行了1次位运算和1次异或运算(2次扰动); JDK1.8新增红黑树 通过上面的链地址法(使用散列表)和扰动函数我们成功让我们的数据分布更平均,哈希碰撞减少,但是当我们的HashMap中存在大量数据时,加入我们某个bucket下对应的链表有n个元素,那么遍历时间复杂度就为O(n),为了针对这个问题,JDK1.8在HashMap中新增了红黑树的数据结构,进一步使得遍历复杂度降低至O(logn); 总结 简单总结一下HashMap是使用了哪些方法来有效解决哈希冲突的: 使用链地址法(使用散列表)来链接拥有相同hash值的数据;使用2次扰动函数(hash函数)来降低哈希冲突的概率,使得数据分布更平均;引入红黑树进一步降低遍历的时间复杂度,使得遍历更快; **能否使用任何类作为 Map 的 key? **可以使用任何类作为 Map 的 key,然而在使用之前,需要考虑以下几点: 如果类重写了 equals() 方法,也应该重写 hashCode() 方法。 类的所有实例需要遵循与 equals() 和 hashCode() 相关的规则。 如果一个类没有使用 equals(),不应该在 hashCode() 中使用它。 用户自定义 Key 类最佳实践是使之为不可变的,这样 hashCode() 值可以被缓存起来,拥有更好的性能。不可变的类也可以确保 hashCode() 和 equals() 在未来不会改变,这样就会解决与可变相关的问题了。 为什么HashMap中String、Integer这样的包装类适合作为K? 答:String、Integer等包装类的特性能够保证Hash值的不可更改性和计算准确性,能够有效的减少Hash碰撞的几率 都是final类型,即不可变性,保证key的不可更改性,不会存在获取hash值不同的情况 内部已重写了equals()、hashCode()等方法,遵守了HashMap内部的规范(不清楚可以去上面看看putValue的过程),不容易出现Hash值计算错误的情况; 如果使用Object作为HashMap的Key,应该怎么办呢? 答:重写hashCode()和equals()方法 重写hashCode()是因为需要计算存储数据的存储位置,需要注意不要试图从散列码计算中排除掉一个对象的关键部分来提高性能,这样虽然能更快但可能会导致更多的Hash碰撞; 重写equals()方法,需要遵守自反性、对称性、传递性、一致性以及对于任何非null的引用值x,x.equals(null)必须返回false的这几个特性,目的是为了保证key在哈希表中的唯一性; HashMap为什么不直接使用hashCode()处理后的哈希值直接作为table的下标 答:hashCode()方法返回的是int整数类型,其范围为-(2 ^ 31)~(2 ^ 31 - 1),约有40亿个映射空间,而HashMap的容量范围是在16(初始化默认值)~2 ^ 30,HashMap通常情况下是取不到最大值的,并且设备上也难以提供这么多的存储空间,从而导致通过hashCode()计算出的哈希值可能不在数组大小范围内,进而无法匹配存储位置; 那怎么解决呢? HashMap自己实现了自己的hash()方法,通过两次扰动使得它自己的哈希值高低位自行进行异或运算,降低哈希碰撞概率也使得数据分布更平均; 在保证数组长度为2的幂次方的时候,使用hash()运算之后的值与运算(&)(数组长度 - 1)来获取数组下标的方式进行存储,这样一来是比取余操作更加有效率,二来也是因为只有当数组长度为2的幂次方时,h&(length-1)才等价于h%length,三来解决了“哈希值与数组大小范围不匹配”的问题; HashMap 的长度为什么是2的幂次方 为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀,每个链表/红黑树长度大致相同。这个实现就是把数据存到哪个链表/红黑树中的算法。 这个算法应该如何设计呢? 我们首先可能会想到采用%取余的操作来实现。但是,重点来了:“取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。 那为什么是两次扰动呢? 答:这样就是加大哈希值低位的随机性,使得分布更均匀,从而提高对应数组存储下标位置的随机性&均匀性,最终减少Hash冲突,两次就够了,已经达到了高位低位同时参与运算的目的; HashMap 与 HashTable 有什么区别? 线程安全: HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!); 效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它; 对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛NullPointerException。 **初始容量大小和每次扩充容量大小的不同 **: ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。 推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代。 如何决定使用 HashMap 还是 TreeMap? 对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。 HashMap 和 ConcurrentHashMap 的区别 ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的synchronized锁的粒度更精细了一些,并发性能更好,而HashMap没有锁机制,不是线程安全的。(JDK1.8之后ConcurrentHashMap启用了一种全新的方式实现,利用CAS算法。) HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。 ConcurrentHashMap 和 Hashtable 的区别? ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。 底层数据结构: JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用 数组+链表 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的; 实现线程安全的方式(重要): ① 在JDK1.7的时候,ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。(默认分配16个Segment,比Hashtable效率提高16倍。) 到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化) 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本;② Hashtable(同一把锁) :使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用 put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。 两者的对比图: HashTable: JDK1.7的ConcurrentHashMap: JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点 Node: 链表节点): 答:ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,HashTable 考虑了同步的问题。但是 HashTable 在每次同步执行时都要锁住整个结构。 ConcurrentHashMap 锁的方式是稍微细粒度的。 ConcurrentHashMap 底层具体实现知道吗?实现原理是什么? JDK1.7 首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。 在JDK1.7中,ConcurrentHashMap采用Segment + HashEntry的方式进行实现,结构如下: 一个 ConcurrentHashMap 里包含一个 Segment 数组。Segment 的结构和HashMap类似,是一种数组和链表结构,一个 Segment 包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护着一个HashEntry数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment的锁。 该类包含两个静态内部类 HashEntry 和 Segment ;前者用来封装映射表的键值对,后者用来充当锁的角色;Segment 是一种可重入的锁 ReentrantLock,每个 Segment 守护一个HashEntry 数组里得元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 锁。 JDK1.8 在JDK1.8中,放弃了Segment臃肿的设计,取而代之的是采用Node + CAS + Synchronized来保证并发安全进行实现,synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。 结构如下: 如果该节点是TreeBin类型的节点,说明是红黑树结构,则通过putTreeVal方法往红黑树中插入节点;如果binCount不为0,说明put操作对数据产生了影响,如果当前链表的个数达到8个,则通过treeifyBin方法转化为红黑树,如果oldVal不为空,说明是一次更新操作,没有对元素个数产生影响,则直接返回旧值;如果插入的是一个新节点,则执行addCount()方法尝试更新元素个数baseCount; 辅助工具类 Array 和 ArrayList 有何区别? Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。 对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。 如何实现 Array 和 List 之间的转换? Array 转 List: Arrays. asList(array) ;List 转 Array:List 的 toArray() 方法。 comparable 和 comparator的区别? comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用来排序 一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo方法或compare方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写compareTo方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的Collections.sort(). 方法如何比较元素? TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进 行排 序。 Collections 工具类的 sort 方法有两种重载的形式, 第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现元素的比较; 第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator 接口的子类型(需要重写 compare 方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java 中对函数式编程的支持)。
剑曼红尘 2020-03-24 14:41:57 0 浏览量 回答数 0

问题

分布式服务接口的幂等性如何设计(比如不能重复扣款)?【Java问答学堂】52期

面试题 分布式服务接口的幂等性如何设计(比如不能重复扣款)? 面试官心理分析 从这个问题开始,面试官就已经进入了实际的生产问题的面试了。 一个分布式系统中的某个接口࿰...
剑曼红尘 2020-07-08 09:15:27 3 浏览量 回答数 1

问题

一般实现分布式锁都有哪些方式?使用 Redis 如何设计分布式锁?使用 zk 来设计分布式锁可以吗?

面试题 一般实现分布式锁都有哪些方式?使用 Redis 如何设计分布式锁?使用 zk 来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高? 面试官心理分析 其实一般问问...
剑曼红尘 2020-07-14 09:42:35 19 浏览量 回答数 1

回答

在校生要找到好工作,主要靠几个光环,学校光环、竞赛光环、项目光环、实习光环。其中项目经验尤为重要。有些同学就有疑问了: “我校招没offer,没有项目经验,是不是要报个培训班?” “我转行计算机,是不是应该报个班?” “我也想自学,可怎么学啊,选哪个方向啊?” 对于有些同学,当我还在想办法劝他自学时,给我贴出了培训班的广告词,真可谓,人有多大胆,口号就有多不要脸: “0基础入学,三个月包就业” “毕业月入不过万,不收学费” “从前是你找工作,接下来是工作找你” 当我推荐某些同学去培训时,又给咔咔咔亮出了几个帖子,说培训出来的受歧视啊、有些同学培训出来还是找不到工作啊,等等。 其实,选择自学还是培训是看自身情况而定,无论选择自学还是培训,都只是入门的一种手段,各有优劣势,本文就详细说说自学/培训怎么选,选择以后怎么办,记得帮我点赞哦。   目录: 自学还是培训,怎么选? 自学怎么学? 培训班到底在培训什么? 有些企业歧视培训班学员,培训班的问题到底出在哪? 一些建议 一、自学还是培训,怎么选? 无论你是什么学历、有没有计算机基础,这些都不是决定你适合自学的条件,具备如下三个条件的人都可以选择自学: (1)、时间充足 如果说从零基础靠自学达到找工作的水平,需要多久呢?我觉得至少一年,有的人可能需要两年。所以,如果你是大一、大二、大三的学生,你还有时间,可以选择自学。如果你是已经工作的,想转行计算机,可以边工作边学习,这个过程会比较辛苦,但也不是绝对不可行。 对于大四的同学,以就业为导向,建议你去培训。不可否认,培训是最快入门的方式,对于时间不足的同学而言,培训是最优解。同样地,如果你是已工作的,不存在财务压力,我同样建议你去培训,工作后的时间很珍贵,比不上在校期间有大把时间可以浪费,如果做好了必转的决心,以最快速度转行才是最优解。 (2)、自控力强 能管得住自己,自己定的目标能想尽一切办法实现的同学,真不多,能占人群中1/4已经不错了。 有些人学了半小时就会累,休息一会,就成这样: 我见过太多的半途而废的同学,也见过太多自己安慰自己式的学习方式,但就业就是一个试金石,你这段时间的努力有没有回报,去找工作的时候,就水落石出。 如果在自律这方面不太行的话,可以看下这篇文章,《启舰:你是怎么变自律的?》,找到自已的驱动器,完成自己的梦想。 (3)、具备高中以上学历 计算机本身是数学家发明的,或多或少会用到一些基本的数学知识、经常用到的很多算法都是数学知识的延伸,没有基本的数学功底,自学确实很难。 至于英语阅读能力还好说,只要会用有道词典,不会的去搜去看,总会读懂的,而且入门级的文献和视频中文版的资料已足够你入门,英语应该不是太大的问题。 如果你这三点都满足,恭喜你,你具有了自学的基础,可以选择自学。 二、自学怎么学? 1、选定一个方向 首先,我们选择方向的目的是什么?不就是为了找份工作吗?那直接到招聘类网站去搜下相关的岗位数量及要求不就好了,哪个数量多,自己也喜欢,那就选这个即可。 其次,如果是大三、大四即将毕业的同学,想知道最近哪个岗位好找工作的话。还可以看看很多培训机构的培训内容,现在很多培训机构都声称保就业,真的以为,培训几个月能培训出朵花来吗?不可能的,编程是个需要长期训练的活,几个月的培训,仅是入门而已,入门的水平能保证找份工作,就靠的是这个岗位门槛低,需求大,好找工作。 如果实在不知道选什么,我帮你找几个方向:python、java后端、Html5就业岗位都挺多,就业门槛低,相对好就业,如果也有其它方向推荐,大家可以留言。 2、找到几套视频教材 在入门时强烈不建议跟着书学 第一,不一定能看得懂 第二,书本的知识不成体系,入门有入门的书,进阶有进阶的书,实战有实战的书,需要自己去选择,本身就不是一件易事。 第三,视频可以看到老师的操作,而书本全靠自己摸 现在某某培训班的入门、进阶、实战的系列视频不要太好找,找到这么两套视频,对比着看,或者跟着一套视频深入看,来得更容易。人家培训班安排好的路线跟着学,不懂的自己搜,就已经排除了自已给自己安排路线的难点,况且人家本身就是面向就业的,培训出来的同学能保就业,只要你能跟着学通学会,自然找到工作也不是问题。 我精心整理了计算机各个方向的从入门、进阶、实战的视频课程和电子书,都是技术学习路上必备的经验,跟着视频学习是进步最快的,而且所有课程都有源码,直接跟着去学!!! 只要关注微信公众号【启舰杂谈】后回复你所需方向的关键字即可,比如『Android』、『java』、『ReactNative』、『H5』、『javaweb』、『面试』、『机器学习』、『web前端』、『设计模式』等关键字获取对应资料。(所有资料免费送,转发宣传靠大家自愿) 视频内容非常多,总共2184G、一千六百多册电子书,九百多套视频教程,涉及43个方向。我整理了很长时间,有些资料是靠买的,希望大家能最快的提升自己。帮我点个赞吧。 启舰:全网2184G计算机各方向视频教程/电子书汇总(持续更新中)​   3、自学,除了知识,你还能学到什么? 自学的缺点很明显: 第一:速度慢,所有进度完全靠自己把控,没有氛围 第二:遇到问题需要自己解决,无人请教 那优点恰恰是从这些缺点中磨练出来的,进度靠自己把握,完全磨练了你的意志力。而所有问题靠自己解决,恰恰培养了你的解决问题的能力。 而这些能力都是培训班教不出来的、无法速成的。而这些能力却是真正的开发高手所必备的 问题定义、分析与设计阶段,这是最需要智商、创造力和经验的阶段,真正的开发高手,就是在这一阶段体现出远超普通人的水平,而在这一阶段所需要的能力,对不起,培训班教不出来,也无法速成,只能靠人自己的努力,慢慢地培养和增强。 4、自学建议 (1)、多做笔记、多复习 刚开始学习时,很难,真的很难。很多东西听不懂,很多东西需要自己搜,自己定的进度很可能完不成。 没关系,坚持下去,都是这么过来的。我刚开始自学的时候,也是无数次想死的冲动…… 学会做笔记,把自己学到的东西及时记下来,形成目录,在后面用到的时候,根据笔记再去看一遍,刚开始经常会出现,听得懂,跟着学会,自己弄就不会的现象。这都是正常的,技术本就是个熟能生巧的过程。 多动手,多总结,就慢慢熟练了。 (2)、多写代码!听得懂、看得懂,并没什么用 入门级知识,本就是语法和框架的熟悉过程,说到底就是工具的使用方法熟悉的过程。既然是工具,那就必然要多用。熟能生巧,指的是用的熟。很多同学看的懂,听的会,自己一下手就问题百出,就是练的少! (3)、听不懂,搜一下,再不懂就放过 刚学的时候很多概念听不懂,没关系,自己搜一下,能理解了就理解,理解不了就算。听一遍就行,学到后面的时候,你就懂些了回头,再看看那些知识,基本上你都懂了。 (4)、多写注释 刚开始的时候,很多逻辑弄不懂,没关系,自己把代码拆解,并对其加以注释,这样,你在反过来再看这些代码时,能很快弄懂它的逻辑。你要知道,你后面学习时还是会碰到这些知识的,而在只看一遍的情况下是不可能记得住的,到时候,你还是会返回来复习这些知识的。 增加注释,看起来浪费时间,其实是整理代码逻辑的过程。浑浑噩噩敲出来的代码,自己都不明白什么意思的话,其实相当于没有真正学会。 三、培训班到底在培训什么? 去培训的主要原因,说到底还是因为自己啥都不会。但不会与不会间是有区别的。 对于科班出身的,上学又好好学了的同学,虽然他们没有系统的编程知识,没有项目经验,但他们有计算机基础,他懂得操作系统原理、数据结构与算法等原理性知识。 而对于跨专业和在玩了四年的同学而言,那才是真正的零基础。 而对于培训机构而言,它的责任就是让你实现从0到1的入门过程,而有经验的老鸟都知道,编程入门仅仅是知识的堆积,并没有什么技巧性可言。所有的语法和框架运用,简单来说,就是学会编程套路,学习工具使用。 而培训机构的责任,就是把这些套路教给你。只要你不太笨,经过几个月的强化训练,大部分人都能学得会。 所以,培训班教你的就是工具的使用,目的,就是以最快的速度塞给你,助你找到工作。 四、有些企业歧视培训班学员,培训班的问题到底出在哪? 培训机构有着熟练的授课体系,老师手把手答疑,让你在学习路上没有一丁点的思考时间,为的就是以最快的速度让你达标,好结课,开始下一波培训。 1、问题就出在速度上。 认知科学的研究成果表明,知识的消化与吸收,职业技能的学习与精通,本质上是在大脑神经元之间建立连接,重塑大脑结构的过程,这个过程的时间可以缩短,但不能无限地缩短。另外,不同的人,拥有不同的背景和基础,在学习与掌握相同的知识与职业技能时,所花的时间是不一样的。 而培训机构才不管这些,他的目的就是挣钱,以最快的速度挣钱,能在三天内把所有内容塞给你绝不用四天,只要最终能糊弄住面试官,让学员找到一份工作就可以了。 所以,必然会出现下面的现象: 对于原来有一些基础的,学习能力较强的同学,在学习之前已经有较扎实的基础,所以在培训期间能够自己构建成技术体系,知识吸收相对较好: 而另一些学员,则会出现消化不良的情况: 2、培训后遗症 对于软件开发而言,所有的软件开发都大致分为两个阶段: 1、分析、定义、设计阶段。这个阶段是需要有解决问题、分析问题的能力。而这个能力培训班培训不出来,只能是慢慢增强。 2、语法、工具的使用,将设计的内容实现出来。这一块就比较机械了,工具嘛,学一学都能会,培训班在这一块的效率是很高效的,它们多半能在较短的时间内,教会学员特定编程语言(比如Python)特定工具(比如Git)与特定技术的使用(比如Spring MVC),并且传授给他们一些开发的“套路”(比如分层架构与设计模式),从而将学员成功地培养成为一个能够“搬砖”的软件工人,即初级程序员。 培训班一般都会选择门槛低、就业岗位多的方向进行培训,对于这类岗位,人才缺口大,只要能直接上手写代码的初级程序员,都很容易找到一份工作。这也就是为什么培训班多半会收学生五位数的学费,而学生也愿意支付的根本原因。 (1)、解决问题能力差,动不动就得人教 经过几个月饭来张口、衣来伸手的填鸭式集训,有些人在工作后,却依然认为,当他遇到问题时,从来不想着自己搜搜资料解决,而是依赖同事帮他答疑! 自学能力差、解决问题能力差,是很多人找到了工作,过不了试用期的根本原因。 (2)、培训效果立竿见影,却又很快遗忘 任何的知识都是一样,短时间内填鸭式学到的知识,在一段时间不用后,就会遗忘。这就是有些同学刚从培训班出来时,能找到份工作,当学到的东西在工作中几个月用不到时,就很快忘记,总觉得自己还是啥都不会的原因。 永远要记住:学历不行靠实力,实力不行靠态度!!! 当我们初入职场,尽心尽责地把自己的工作做完做好的同时,千万不要忘记像海绵一样,以最快的速度给自己充水。 像培训完的同学,在校期间已经做了很多的笔记,工作之余,多复习,重新练,利用时间将它理解,真正内化为自己的本领。 对于自学的同学,多找进阶性书籍和视频去看,以最快的速度提升自己。 文末我整理了计算机各个方向的从入门、进阶、实战的视频课程和电子书,都是技术学习路上必备的经验,跟着视频学习是进步最快的,而且所有课程都有源码,直接跟着去学!!! 五、一些建议 1、非科班同学建议 对于非科班转行计算机的同学,有太多的知识需要补足,如果你靠的是自学,需要强有力的自律能力,只要时间还够,是可以靠自学的,在跟着视频学的时候,哪里听不懂及时去搜相关的资料去补足。 刚开始自学时,即便是科班出身也是有想死的冲动的,大家都一样。我也是靠自学过来的,很多的东西不会,很多的东西听不懂。没关系,多做笔试,多搜资料,把不会的弄会,你会发现,学习起来越来越容易。 所有的困难只不过是纸老虎,坚持过去就成功了。 如果你是通过培训找到了一份工作,你需要比别人更努力补充计算机知识,基础知识的缺乏,会使你很难在这条路上走很远,所有的大神,都是自学能力很强的人,你想,你也可以。 2、所有开发方向都必须从C++开始? 经常会有要校生问我:我要做H5开发,是不是要先学C++? 其实,各个语言之间是没有任何关联的,完全都是有各自的语法体系和开发工具的,简单来讲,他们都是不同类型的工具。 你学会一种工具,只会对另一种类似的工具更容易上手,而不是完全不用学。所以,想学哪个方向,直接去学就行了,没必须先从C++入手迂回一下,纯属浪费时间。 但,如果你还在上学,现在正在学C++,那我还是建议你好好学,必须C语言语法更接近低层编译器原理,学会了它,对理解低层分配、释放、编译机制都是很有用的,但就以工作为导向而言,如果你不从事C++相关工作,是没必要学的。 3、培训出来人人工资过万? 有个男生非常沮丧的找我,自己是专科毕业,培训完,小公司不想进,大点的公司进不去,给的工资也不高,问我怎么办? 上面我们已经讲到,对于不同程度的同学,在培训出来的结果是不一样的,你要分清,你培训完的情况是属于这种: 还是这种? 对于没有名校光环的同学,建议以先就业为主。 别看培训班招你的时候给你洗脑,培训完人人过万,但能不能过万,最终靠的是自己,而不是培训班。 认请自己的情况,可以先就业,再优化自己履历,而进步步高升。 4、建议不要暴露自己的培训经历 你百度、知乎搜一下,遍地的培训歧视,很多公司根本不要培训出来的同学. 业界对培训有偏见,因为写代码是一个逐渐学习、熟练的过程,经过几个月集中的培训,虽然看起来什么都接触到了,但真正能内化为自己知识的部分其实不多。在工作中并不能熟练运用,仅是入门水平而已。 而且大家普遍认为参加培训的主要原因是因为,大学中没好好学,临近毕业了,催熟一把。不然,谁会花这几万块钱呢?对普通家庭而言,其实也并不是个小数目了。 有一个外包公司的朋友,技术总监,招人时培训公司出来都不要,原因就是干活能力不行。当然这仅代表个例,但大家需要注意的是,业界并不认为培训是一件光彩的事,千万不要搞错了!!! 5、培训班防骗三十六计 现在太多的培训机构,一个个把自己吹的天花乱坠,我也建议过小伙伴去培训,但小孩子交完钱培训一个月就退费了,深感自己好心做了坏事,这里建议大家培训市场,鱼龙混杂,一定要提前做好防骗准备。 谎言之所以真实是因为年青的心太不甘寂寞,太急于求成! 从网上找了,培训班防骗三十六计,供大家参考: “借刀杀人”:培训班间竞争激烈,彼此勾心斗角,正好为我所用。去培训班甲问乙如何,到培训班乙打听甲。Ha.Ha..,狗咬狗开始了,一时间内幕迭报:乙设备不全,很多实验不能做;甲的那个号称CCIE的老师只过了笔试,没过实验室,假的! “声东击西”:与甲约好星期六考察学校,结果星期X跑去(1=< X <= 5)。   “你怎么来了?”   “我星期六有事,所以提前来看看……” “抛砖引玉”:有时候,拿不定注意或者培训班在外地,实地考察有难度,何不到论坛发个帖子征求意见,要是能得到已经培训过的前辈的释疑,那你绝对是不虚此帖了! “假痴不癫”:有时候你可能偶然拥有一些内幕消息,不如试试他们的诚实度。   “听说你们的教师是CCIE!”   “那当然,技术首屈一指,……”   此时此刻,看着乙那得意样样的小样,不知是好笑,还是可气。不过记住:一个没有诚信的公司是什么都干的出来的! “反间计”:一个卑鄙的培训班后面一般都有一个卑鄙的流氓大亨,他不仅千方百计的从学员那里榨取钱财,对自己的手下也不会心慈手软,本着人们内部矛盾的原则发展一个或多个间谍。 “走为上计”:经过一番打探,知道他们都不是东西,还犹豫什么?宁缺毋滥,走人! 最后,如论怎么选,自终也只是入门阶段,为了找到一份工作。对于初入职场的你们,给一条最终建议:学校不行靠实力,实力不行靠态度。记得帮我点赞哦。 ———————————————— 版权声明:本文为CSDN博主「启舰」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/harvic880925/article/details/103413853
问问小秘 2020-01-07 10:55:15 0 浏览量 回答数 0

回答

转自:阿飞的博客 一、数据库技术选型的思考维度 我们做选型的时候首先要问: 谁选型?是负责采购的同学、 DBA 还是业务研发? 如果选型的是采购的同学,他们更注重成本,包括存储方式、网络需求等。 如果选型的是 DBA 同学,他们关心的: ① 运维成本 首先是运维成本,包括监控告警是否完善、是否有备份恢复机制、升级和迁移的成本是否高、社区是否稳定、是否方便调优、排障是否简易等; ② 稳定性 其次,DBA会关注稳定性,包括是否支持数据多副本、服务高可用、多写多活等; ③ 性能 第三是性能,包括延迟、QPS 以及是否支持更高级的分级存储功能等; ④ 拓展性 第四是扩展性,如果业务的需求不确定,是否容易横向扩展和纵向扩容; ⑤ 安全 最后是安全,需要符合审计要求,不容易出现 SQL 注入或拖库情况。 ⑥ 其他 除了采购和 DBA之外,后台应用研发的同学同样会关注稳定性、性能、扩展性等问题,同时也非常关注数据库接口是否便于开发,是否便于修改数据库 schema 等问题。 接下来我们来看一下爱奇艺使用的数据库类型: MySQL,互联网业务必备系统; TiDB,爱奇艺的 TiDB 实践会有另外的具体介绍; Redis,KV 数据库,互联网公司标配; Couchbase,这个在爱奇艺用得比较多,但国内互联网公司用得比较少,接下来的部分会详细说明; 其他,比如 MongoDB、图数据库、自研 KV 数据库 HiKV 等; 大数据分析相关系统,比如 Hive、Impala 等等。 可以看到爱奇艺的数据库种类还是很多的,这会造成业务开发的同学可能不太清楚在他的业务场景下应该选用哪种数据库系统。 那么,我们先对这些数据库按照接口(SQL、NoSQL)和面向的业务场景(OLTP、OLAP)这两位维度进行一个简单非严谨的分类。 下图中,左上角是面向 OLTP、支持 SQL 的这样一类系统,例如 MySQL,一般支持事务不同的隔离级别, QPS 要求比较高,延时比较低,主要用于交易信息和关键数据的存储,比如订单、VIP 信息等。 左下角是 NoSQL 数据库,是一类针对特殊场景做优化的系统,schema 一般比较简单,吞吐量较高、延迟较低,一般用作缓存或者 KV 数据库。 整个右侧都是 OLAP 的大数据分析系统,包括 Clickhouse、Impala等,一般支持SQL、不支持事务,扩展性比较好,可以通过加机器增加数据的存储量,响应延迟较长。 还有一类数据库是比较中立的,在数据量比较小的时候性能比较好,在数据量较大或复杂查询的时候性能也不差,一般通过不同的存储引擎和查询引擎来满足不同的业务需求,我们把它叫做 HTAP,TiDB 就是这样一种数据库。 二、iQIYI对数据库的优化与完善 前面我们提到了很多种的数据库,那么接下来就和大家介绍一下在爱奇艺我们是怎么使用这些数据库的。 1、MySQL在爱奇艺的使用 ① MySQL 首先是 MySQL。MySQL 基本使用方式是 master-slave + 半同步,支持每周全备+每日增量备份。我们做了一些基本功能的增强,首先是增强了数据恢复工具 Xtrabackup 的性能。 之前遇到一个情况,我们有一个全量库是 300G 数据,增量库每天 70G 数据,总数据量 700G 左右。我们当时只需要恢复一个表的数据,但该工具不支持单表恢复,且整库恢复需要 5 个小时。 针对这个情况我们具体排查了原因,发现在数据恢复的过程中需要进行多次写盘的 IO 操作并且有很多串行操作,所以我们做了一些优化。例如删减过程中的一些写盘操作,减少落盘并将数据处理并行化,优化后整库恢复耗时减少到 100 分钟,而且可以直接恢复单表数据。 然后是适配 DDL 和 DML 工具到内部系统,gh-ostt 和 oak-online-alter-table 在数据量大的时候会造成 master-slave 延时,所以我们在使用工具的时候也增加了延时上的考虑,实时探测Master-Slave 库之间延时的情况,如果延时较大会暂停工具的使用,恢复到正常水平再继续。 ② MySQL高可用 第二是 MySQL 高可用。Master-slave 加上半同步这种高可用方式不太完善,所以我们参照了 MHA 并进行了改动,采用 master + agent 的方式。Agent 在每一个物理机上部署,可以监控这个物理机上的所有实例的状态,周期性地向 master 发送心跳,Master 会实时监测各个Agent的状态。 如果 MySQL故障,会启动 Binlog 补偿机制,并切换访问域名完成 failover。考虑到数据库跨机房跨地区部署的情况,MHA 的 master 我们也做了高可用设计,众多 master 会通过 raft 组成一个 raft group,类似 TiDB 的 PD 模块。目前 MySQL failover 策略支持三种方式:同机房、同地域跨机房以及跨地域。 ③ MySQL拓展能力 第三是提高MySQL扩展能力,以提供更大容量的数据存储。扩展方式有 SDK,例如开源的 ShardingSphere,在爱奇艺的使用也比较广泛。另外就是 Proxy,开源的就更多了。但是 SDK 和 Proxy 使用的问题是支持的 SQL 语句简单,扩容难度大,依赖较多且运维复杂,所以部分业务已经迁移至 TiDB。 ④ 审计 第四是审计。我们在 MySQL 上做了一个插件获取全量 SQL 操作,后端打到 Kafka,下游再接入包括 Clickhouse 等目标端进行 SQL 统计分析。除此之外还有安全策略,包括主动探索是否有 SQL 注入及是否存在拖库情况等,并触发对应的告警。 MySQL 审计插件最大的问题是如何降低对 MySQL 性能的影响,对此我们进行了一些测试,发现使用 General Log 对性能损耗较大,有 10%~20% 的降低。 于是我们通过接口来获取 MySQL 插件里的监控项,再把监控项放到 buffer 里边,用两级的 RingBuffer 来保证数据的写入不会有锁资源竞争。在这个插件里再启动一个线程,从 RingBuffer 里读取数据并把数据打包写到 FIFO 管道里。 我们在每台 MySQL 的物理机里再启动一个 Agent,从管道里阻塞地读取数据发至 Kafka。优化后我们再次进行压测,在每台机器上有 15 万的更新、删除或插入操作下不会丢失数据,性能损耗一般情况下小于 2%。 目前已经在公司内部的集群上线了一年时间,运行比较稳定,上线和下线对业务没有影响。 ⑤ 分级存储 第五是分级存储。MySQL 里会存一些过程性的数据,即只需要读写最近一段时间存入的数据,过段时间这些数据就不需要了,需要进行定时清理。 分级存储就是在 MySQL 之上又用了其他存储方式,例如 TiDB 或其他 TokuDB,两者之间可以进行数据自动搬迁和自动归档,同时前端通过 SDK + Proxy 来做统一的访问入口。这样一来,业务的开发同学只需要将数据存入 MySQL 里,读取时可能从后端接入的任意数据库读出。这种方式目前只是过渡使用,之后会根据 TiDB 的特性进行逐步迁移。 Redis在爱奇艺的使用 接下来是 Redis。Redis 也是使用 master - slave 这种方式,由于网络的复杂性我们对 Sentinel 的部署进行了一些特殊配置,在多机房的情况下每个机房配置一定数量 Sentinel 来避免脑裂。 备份恢复方面介绍一个我们的特殊场景,虽然 Redis 是一个缓存,但我们发现不少的业务同学会把它当做一个 KVDB 来使用,在某些情况下会造成数据的丢失。 所以我们做了一个 Redis 实时备份功能,启动一个进程伪装成 Redis 的 Slave 实时获取数据,再放到后端的 KV 存储里,例如 ScyllaDB,如果要恢复就可以从 ScyllaDB 里把数据拉出来。 我们在用 Redis 时最大的痛点就是它对网络的延迟或抖动非常敏感。如有抖动造成 Redis Master 超时,会由 Sentinel 重新选出一个新的节点成为 Master,再把该节点上的数据同步到所有 Slave 上,此过程中数据会放在 Master 节点的 Buffer 里,如果写入的 QPS 很高会造成 Buffer 满溢。如果 Buffer 满后 RDB 文件还没有拷贝过去,重建过程就会失败。 基于这种情况,我们对 Redis 告警做了自动化优化,如有大量 master - slave 重建失败,我们会动态调整一些参数,例如把 Buffer 临时调大等, 此外我们还做了 Redis 集群的自动扩缩容功能。 我们在做 Redis 开发时如果是 Java 语言都会用到 Jedis。用 Jedis 访问客户端分片的 Redis 集群,如果某个分片发生了故障或者 failover,Jedis 就会对所有后端的分片重建连接。如果某一分片发生问题,整个 Redis 的访问性能和 QPS 会大幅降低。针对这个情况我们优化了 Jedis,如果某个分片发生故障,就只针对这个分片进行重建。 在业务访问 Redis 时我们会对 Master 绑定一个读写域名,多个从库绑定读域名。但如果我们进行 Master failover,会将读写域名从某旧 Master 解绑,再绑定到新 Master 节点上。 DNS 本身有一个超时时间,所以数据库做完 failover 后业务程序里没有立刻获取到新的 Master 节点的 IP的话,有可能还会连到原来的机器上,造成访问失败。 我们的解决方法是把 DNS 的 TTL 缩短,但对 DNS 服务又会造成很大的压力,所以我们在 SDK 上提供 Redis 的名字服务 RNS,RNS 从 Sentinel 里获取集群的拓扑和拓扑的变化情况,如果集群 failover,Sentinel 会接到通知,客户端就可以通过 RNS 来获取新的 Master 节点的 IP 地址。我们去掉域名,通过 IP 地址来访问整个集群,屏蔽了 DNS 的超时,缩短了故障的恢复时间。 SDK 上还做了一些功能,例如 Load Balance 以及故障检测,比如某个节点延时较高的话会被临时熔断等。 客户端分片的方式会造成 Redis 的扩容非常痛苦,如果客户端已经进行了一定量的分片,之后再增加就会非常艰难。 Redis 在 3.0 版本后会提供 Redis Cluster,因为功能受限在爱奇艺应用的不是很多,例如不支持显示跨 DC 部署和访问,读写只在主库上等。 我们某些业务场景下会使用 Redis 集群,例如数据库访问只发生在本 DC,我们会在 DC 内部进行 Cluster 部署。 但有些业务在使用的过程中还是想做 failover,如果集群故障可以切换到其他集群。根据这种情况我们做了一个 Proxy,读写都通过它来进行。写入数据时 Proxy 会做一个旁路,把新增的数据写在 Kafka 里,后台启用同步程序再把 Kafka 里的数据同步到其他集群,但存在一些限制,比如我们没有做冲突检测,所以集群间数据需要业务的同学做单元化。线上环境的Redis Cluster 集群间场景跨 DC 同步 需要 50 毫秒左右的时间。 2、Couchbase在爱奇艺的使用 Redis 虽然提供 Cluster 这种部署方式,但存在一些问题。所以数据量较大的时候(经验是 160G),就不推荐 Redis 了,而是采用另一种存储方式 Couchbase。 Couchbase 在国内互联网公司用的比较少,一开始我们是把他当做一个 Memcached 来使用的,即纯粹的缓存系统。 但其实它性能还是比较强大的,是一个分布式高性能的 KV 系统,支持多种存储引擎 (bucket)。第一种是 Memcached bucket,使用方式和 Memcached 一样为 KV 存储,不支持数据持久化也没有数据副本,如果节点故障会丢失数据; 第二种是 Couchbase bucket,支持数据持久化,使用 Json 写入,有副本,我们一般会在线上配置两个副本,如果新加节点会对数据进行 rebalance,爱奇艺使用的一般是 Couchbase bucket 这种配置。 Couchbase 数据的分布如下图,数据写入时在客户端上会先进行一次哈希运算,运算完后会定位 Key 在哪一个 vBucket (相当于数据库里的某个分片)。之后客户端会根据 Cluster Map 发送信息至对应的服务端,客户端的 Cluster Map 保存的是 vBucket 和服务器的映射关系,在服务端数据迁移的过程中客户端的 Cluster Map 映射关系会动态更新,因此客户端对于服务端的 failover 操作不需要做特殊处理,但可能在 rebalance 过程中会有短暂的超时,导致的告警对业务影响不大。 Couchbase 在爱奇艺应用比较早,2012 年还没有 Redis Cluster 的时候就开始使用了。集群管理使用 erlang 语言开发,最大功能是进行集群间的复制,提供多种复制方式:单向、双向、星型、环式、链式等。 爱奇艺从最初的 1.8 版本使用到如今的 5.0 版本,正在调研的 6.0,中间也遇到了很多坑,例如 NTP 时间配置出错会导致崩溃,如果每个集群对外 XDCR 并发过高导致不稳定,同步方向变更会导致数据丢失等等,我们通过运维和一些外部工具来进行规避。 Couchbase 的集群是独立集群,集群间的数据同步通过 XDCR,我们一般配置为双向同步。对于业务来说,如果 Cluster 1 写入, Cluster 2 不写入,正常情况下客户端会写 Cluster 1。如果 Cluster 1 有故障,我们提供了一个 Java SDK,可以在配置中心把写入更改到 Cluster 2,把原来到 Cluster 1 的连接逐步断掉再与Cluster 2 新建连接。这种集群 failover 的过程对于客户端来说是相对透明和无感的。 3、爱奇艺自研数据库HiKV的使用 Couchbase 虽然性能非常高,并且数据的存储可以超过内存。但是,如果数据量超过内存 75% 这个阈值,性能就会下降地特别快。在爱奇艺,我们会把数据量控制在可用内存的范围之内,当做内存数据库使用。但是它的成本非常高,所以我们后面又开发了一个新的数据库—— HiKV。 开发 HiKV 的目的是为了把一些对性能要求没那么高的 Couchbase 应用迁移到 HiKV 上。HiKV 基于开源系统 ScyllaDB,主要使用了其分布式数据库的管理功能,增加了单机存储引擎 HiKV。 ScyllaDB 比较吸引人的是它宣称性能高于 Cassandra 十倍,又完全兼容 Cassandra 接口,设计基本一致,可以视为 C++ 版 Cassandra 系统。 ScyllaDB 性能的提升主要是使用了一些新的技术框架,例如 C++ 异步框架 seastar,主要原理是在j每台物理机的核上会 attach 一个应用线程,每个核上有自己独立的内存、网络、IO 资源,核与核之间没有数据共享但可以通信,其最大的好处是内存访问无锁,没有冲突过程。 当一个数据读或写到达 ScyllaDB 的 server 时,会按照哈希算法来判断请求的 Key 是否是该线程需要处理的,如果是则本线程处理,否则会转发到对应线程上去。 除此之外,它还支持多副本、多数据中心、多写多活,功能比较强大。 在爱奇艺,我们基于 SSD 做了一个 KV 存储引擎。Key 放在内存里,Value 放在盘上的文件里,我们在读和写文件时,只需要在内存索引里定位,再进行一次盘的 IO 开销就可以把数据读出来,相比 ScyllaDB 原本基于 LSM Tree 的存储引擎方式对 IO 的开销较少。 索引数据全部放在内存中,如果索引长度较长会限制单机可存储的数据量,于是我们通过开发定长的内存分布器,对于比较长的 Key 做摘要缩短长度至 20 字节,采用红黑树索引,限制每条记录在内存里的索引长度至为 64 字节。内存数据要定期做 checkpoint,客户端要做限流、熔断等。 HiKV 目前在爱奇艺应用范围比较大,截至目前已经替换了 30% 的 Couchbase,有效地降低了存储成本。 4、爱奇艺的数据库运维管理 爱奇艺数据库种类较多,如何高效地运维和管理这些数据库也是经历了不同的阶段。 最初我们通过 DBA 写脚本的方式管理,如果脚本出问题就找 DBA,导致了 DBA 特别忙碌。 第二个阶段我们考虑让大家自己去查问题的答案,于是在内部构建了一个私有云,通过 Web 的方式展示数据库运行状态,让业务的同学可以自己去申请集群,一些简单的操作也可以通过自服务平台实现,解放了 DBA。一些需要人工处理的大型运维操作经常会造成一些人为故障,敲错参数造成数据丢失等。 于是在第三个阶段我们把运维操作 Web 化,通过网页点击可以进行 90% 的操作。 第四个阶段让经验丰富的 DBA 把自身经验变成一些工具,比如有业务同学说 MySQL master-slave 延时了,DBA 会通过一系列操作排查问题。现在我们把这些操作串起来形成一套工具,出问题时业务的同学可以自己通过网页上的一键诊断工具去排查,自助进行处理。 除此之外我们还会定期做预警检查,对业务集群里潜在的问题进行预警报告;开发智能客服,回答问题;通过监控的数据对实例打标签,进行削峰填谷地智能调度,提高资源利用率。 三、不同场景下数据库选型建议 1、实用数据库选型树 最后来说一些具体数据库选型建议。这是 DBA 和业务一起,通过经验得出来的一些结论。 对于关系型数据库的选型来说,可以从数据量和扩展性两个维度考虑,再根据数据库有没有冷备、要不要使用 Toku 存储引擎,要不要使用 Proxy 等等进行抉择。 NoSQL 也是什么情况下使用 master-slave,什么情况下使用客户端分片、集群、Couchbase、HiKV 等,我们内部自服务平台上都有这个选型树信息。 2、一些思考 ① 需求 我们在选型时先思考需求,判断需求是否真实。 你可以从数据量、QPS、延时等方面考虑需求,但这些都是真实需求吗?是否可以通过其他方式把这个需求消耗掉,例如在数据量大的情况下可以先做数据编码或者压缩,数据量可能就降下来了。 不要把所有需求都推到数据库层面,它其实是一个兜底的系统。 ② 选择 第二个思考的点是对于某个数据库系统或是某个技术选型我们应该考虑什么?是因为热门吗?还是因为技术上比较先进?但是不是能真正地解决你的问题?如果你数据量不是很大的话就不需要选择可以存储大数据量的系统。 ③ 放弃 第三是放弃,当你放弃一个系统时真的是因为不好用吗?还是没有用好?放弃一个东西很难,但在放弃时最好有一个充分的理由,包括实测的结果。 ④ 自研 第四是自研,在需要自己开发数据库时可以参考和使用一些成熟的产品,但不要盲目自研。 ⑤ 开源 最后是开源,要有拥抱开源的态度。
茶什i 2019-12-27 14:17:56 0 浏览量 回答数 0

云产品推荐

上海奇点人才服务相关的云产品 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务 阿里云AIoT