• 关于 关联模型怎么用 的搜索结果

回答

queryphp框架的hello world,并对queryphp框架有了大致的了解。这一章,我们将解释ORM。对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。 简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,php利用__set __get __call等方式使用,这也同时暗示者额外的执行开销;然而,如果ORM作为一种中间件实现,则会有很多机会做优化,而这些在手写的持久层并不存在。 更重要的是用于控制转换的元数据需要提供和管理;但是同样,这些花费要比维护手写的方案要少;而且就算是遵守ODMG规范的对象数据库依然需要类级别的元数据。  数据类型映射模式       1.1简单数据类型模式:建立UML和关系型数据库中简单数据类型的映射表以指导映射。       1.2枚举数据类型模式:每种枚举类型对应一个表,只有一个列(_EnumLiteral)表示枚举值。       1.3基于类的数据类型模式:使用外键约束,将基础列与基于类的类型实例相关联。 类映射模型 每个类对应一个表。单值属性、多值属性、继承关系可以用下述方法映射,而引用属性将在关联映射模式中提到。       2.1单值属性模式:是cardinality的上界为1的属性,映射到类所对应的表的列上。若其下界也为1(必须有的属性),列属性为NOT NULL。       2.2多值属性模式:每个多值属性映射成一个独立的表,使用外键连接到类所对应的表上。       2.3继承模式:每加入一个类的实例时,根据其继承关系自顶向下生成每个类的对象,这些对象具有相同的ID(根对象对应记录的主键)。 删除对象实例时,自底向上删除数据。遇到从中间删的情况怎么办?多重继承怎么处理? 关联映射模式       3.1一对一关联模式:在关联两端各加一列。       3.2一对多关联模式:和3.1一样。如果多这端是有序的,还需加入一列表示序号。       3.3多对多关联模式:将关联单独作一个表。 一般有人说ORM有什么用,喜欢写sql这类 ORM在数据建模,领域设计方面很有用。 比如:  echo $supply->get(5)->Books->classname;  //自动取得supply和books关联中内容 如果用sql怎么写,先取得$supply中的值,先然后再写sql取得books中classname $result=mysql_query(select * from supply where id=5) $row=mysql_fetch_array($result); mysql_query(select * from book where supplyid=$row[supplyid]); $books=mysql_fetch_array($result); 大概这样子,虽然功能相同,但是在做数据建模时候可以不是这样子想的,这样受到干扰太多了,在做领域设计时候,也很不好看。 目前ORM基设计完成,以后不断在优化程序性能和使用方法尽量避免接触到真实表操作和数据库操作。这些操作将会在模型配置文件中完成这样完成程序后,再改动数据库或表不完影响程序,比如原来由mysql改成sqllite也不会修改程序,程序员只要注重于数据模型操作,不需要知道数据来源

一枚小鲜肉帅哥 2020-06-02 12:43:53 0 浏览量 回答数 0

回答

如果某个属性可能有多条数据,就应该建多一个表,例如配图表,然后在配图表中增加药品id的字段来关联呗。 ######@红薯 : 谢谢!######@hil2010 : 这个看你们自己的需求,如果允许格式丰富多彩,当然是kindeditor好啦######@红薯 : 谢谢,在录入数据的时候用kindEditor做?还是用一个textarea配一个图片在线剪裁(JCrop)来做呢?哪个更好呢?######@hil2010 : 大文本的搜索可以用 Lucene 建立索引库######谢谢红薯大侠,那检索那一块怎么作呢?直接用sql like可行吗?######建好了给一份啊 ######建议多建立一些字段备用。或者用文档数据库把?######谢谢!######看这个需求,没有明显的关系形规范的要求,更贴近于文档方面的需求。而文档数据库的模型比较灵活,适合全文索引。

kun坤 2020-06-01 09:50:05 0 浏览量 回答数 0

问题

如何在MongoDB/NoSQL中设计篮球联赛的数据模型?

落地花开啦 2019-12-01 19:47:29 1148 浏览量 回答数 1

新用户福利专场,云服务器ECS低至96.9元/年

新用户福利专场,云服务器ECS低至96.9元/年

问题

搞懂了这几点,你就学会了Web编程

技术小菜鸟 2019-12-01 21:20:38 2373 浏览量 回答数 1

回答

解析SQL语法,再校验权限、结构、内容,最后再转回SQL, 不说性能问题,真要这么好搞业内也应该有不错的开源方案了。   而且SQL不能直观地反映返回JSON的数据结构, APIJSON就能做到看请求知结果,所求即所得。   APIJSON的 提取字段、远程函数 功能也不是SQL方案能方便地实现的。 还有 自动加注释、自动生成封装请求JSON的代码,用SQL方案实现也很困难,甚至根本不可能准确地实现。   为什么要用APIJSON?或者APIJSON有什么用? https://github.com/TommyLemon/APIJSON/wiki######坏人######我就认为graphql是个超级kpi项目######你写sql从来不考虑执行时间么?看楼主只是一个前端吧,语言都是互通的,有个半天几本能上手开发,没必要去学。graphql虽然还没在业务上使用,从优点来看,可以非常优雅获取后台交互的数据,schema即是文档,便于维护(开发什么的有什么难的,维护才最麻烦,写一大堆鬼都看不懂的sql,到时候业务变动,连改都懒得改,直接重写,重写完发现,操效率低这么多,还得tmd的优化,最后发现连自己都看不懂的天书,让下一个接手的人继续上面的循环)。--(一个在postgre上优化了n多次merge join到hash join的人,鬼知道自己怎么优化的,一次一次的尝试)######我并不是否定模型(schema)的作用,也认同可维护性带来的好处,只是觉得再早一门query language的优势在何处。 难道不能直接吧sql的语法作为query language,后端需要优化完全可以parse sql后拆分成n个sql执行都不重要。######APIJSON与GraphQL全方位对比解析(一)-基础功能 https://http://juejin.im/post/5ae80edd51882567277433cf APIJSON与GraphQL全方位对比解析(二)-权限控制 https://http://juejin.im/post/5b17518c6fb9a01e75463096 APIJSON与GraphQL全方位对比解析(三)-表关联查询 https://http://juejin.im/entry/5b4ff88f6fb9a04f914a8df5

kun坤 2020-05-29 22:56:29 0 浏览量 回答数 0

问题

【精品问答】大数据计算技术1000问

问问小秘 2019-12-01 21:57:13 3431 浏览量 回答数 1

问题

【精品问答】130+大数据面试汇总

问问小秘 2019-12-01 21:52:42 1644 浏览量 回答数 2

回答

面试官心理分析 这个问题是肯定要问的,说白了,就是看你有没有实际干过 es,因为啥?其实 es 性能并没有你想象中那么好的。很多时候数据量大了,特别是有几亿条数据的时候,可能你会懵逼的发现,跑个搜索怎么一下 5~10s,坑爹了。第一次搜索的时候,是 5~10s,后面反而就快了,可能就几百毫秒。 你就很懵,每个用户第一次访问都会比较慢,比较卡么?所以你要是没玩儿过 es,或者就是自己玩玩儿 demo,被问到这个问题容易懵逼,显示出你对 es 确实玩儿的不怎么样? 面试题剖析 说实话,es 性能优化是没有什么银弹的,啥意思呢?就是不要期待着随手调一个参数,就可以万能的应对所有的性能慢的场景。也许有的场景是你换个参数,或者调整一下语法,就可以搞定,但是绝对不是所有场景都可以这样。 性能优化的杀手锏——filesystem cache 你往 es 里写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到 filesystem cache 里面去。 es 的搜索引擎严重依赖于底层的 filesystem cache,你如果给 filesystem cache 更多的内存,尽量让内存可以容纳所有的 idx segment file 索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高。 性能差距究竟可以有多大?我们之前很多的测试和压测,如果走磁盘一般肯定上秒,搜索性能绝对是秒级别的,1秒、5秒、10秒。但如果是走 filesystem cache,是走纯内存的,那么一般来说性能比走磁盘要高一个数量级,基本上就是毫秒级的,从几毫秒到几百毫秒不等。 这里有个真实的案例。某个公司 es 节点有 3 台机器,每台机器看起来内存很多,64G,总内存就是 64 * 3 = 192G。每台机器给 es jvm heap 是 32G,那么剩下来留给 filesystem cache 的就是每台机器才 32G,总共集群里给 filesystem cache 的就是 32 * 3 = 96G 内存。而此时,整个磁盘上索引数据文件,在 3 台机器上一共占用了 1T 的磁盘容量,es 数据量是 1T,那么每台机器的数据量是 300G。这样性能好吗? filesystem cache 的内存才 100G,十分之一的数据可以放内存,其他的都在磁盘,然后你执行搜索操作,大部分操作都是走磁盘,性能肯定差。 归根结底,你要让 es 性能要好,最佳的情况下,就是你的机器的内存,至少可以容纳你的总数据量的一半。 根据我们自己的生产环境实践经验,最佳的情况下,是仅仅在 es 中就存少量的数据,就是你要用来搜索的那些索引,如果内存留给 filesystem cache 的是 100G,那么你就将索引数据控制在 100G 以内,这样的话,你的数据几乎全部走内存来搜索,性能非常之高,一般可以在 1 秒以内。 比如说你现在有一行数据。id,name,age .... 30 个字段。但是你现在搜索,只需要根据 id,name,age 三个字段来搜索。如果你傻乎乎往 es 里写入一行数据所有的字段,就会导致说 90% 的数据是不用来搜索的,结果硬是占据了 es 机器上的 filesystem cache 的空间,单条数据的数据量越大,就会导致 filesystem cahce 能缓存的数据就越少。其实,仅仅写入 es 中要用来检索的少数几个字段就可以了,比如说就写入 es id,name,age 三个字段,然后你可以把其他的字段数据存在 mysql/hbase 里,我们一般是建议用 es + hbase 这么一个架构。 hbase 的特点是适用于海量数据的在线存储,就是对 hbase 可以写入海量数据,但是不要做复杂的搜索,做很简单的一些根据 id 或者范围进行查询的这么一个操作就可以了。从 es 中根据 name 和 age 去搜索,拿到的结果可能就 20 个 doc id,然后根据 doc id 到 hbase 里去查询每个 doc id 对应的完整的数据,给查出来,再返回给前端。 写入 es 的数据最好小于等于,或者是略微大于 es 的 filesystem cache 的内存容量。然后你从 es 检索可能就花费 20ms,然后再根据 es 返回的 id 去 hbase 里查询,查 20 条数据,可能也就耗费个 30ms,可能你原来那么玩儿,1T 数据都放 es,会每次查询都是 5~10s,现在可能性能就会很高,每次查询就是 50ms。 数据预热 假如说,哪怕是你就按照上述的方案去做了,es 集群中每个机器写入的数据量还是超过了 filesystem cache 一倍,比如说你写入一台机器 60G 数据,结果 filesystem cache 就 30G,还是有 30G 数据留在了磁盘上。 其实可以做数据预热。 举个例子,拿微博来说,你可以把一些大V,平时看的人很多的数据,你自己提前后台搞个系统,每隔一会儿,自己的后台系统去搜索一下热数据,刷到 filesystem cache 里去,后面用户实际上来看这个热数据的时候,他们就是直接从内存里搜索了,很快。 或者是电商,你可以将平时查看最多的一些商品,比如说 iphone 8,热数据提前后台搞个程序,每隔 1 分钟自己主动访问一次,刷到 filesystem cache 里去。 对于那些你觉得比较热的、经常会有人访问的数据,最好做一个专门的缓存预热子系统,就是对热数据每隔一段时间,就提前访问一下,让数据进入 filesystem cache 里面去。这样下次别人访问的时候,性能一定会好很多。 冷热分离 es 可以做类似于 mysql 的水平拆分,就是说将大量的访问很少、频率很低的数据,单独写一个索引,然后将访问很频繁的热数据单独写一个索引。最好是将冷数据写入一个索引中,然后热数据写入另外一个索引中,这样可以确保热数据在被预热之后,尽量都让他们留在 filesystem os cache 里,别让冷数据给冲刷掉。 你看,假设你有 6 台机器,2 个索引,一个放冷数据,一个放热数据,每个索引 3 个 shard。3 台机器放热数据 index,另外 3 台机器放冷数据 index。然后这样的话,你大量的时间是在访问热数据 index,热数据可能就占总数据量的 10%,此时数据量很少,几乎全都保留在 filesystem cache 里面了,就可以确保热数据的访问性能是很高的。但是对于冷数据而言,是在别的 index 里的,跟热数据 index 不在相同的机器上,大家互相之间都没什么联系了。如果有人访问冷数据,可能大量数据是在磁盘上的,此时性能差点,就 10% 的人去访问冷数据,90% 的人在访问热数据,也无所谓了。 document 模型设计 对于 MySQL,我们经常有一些复杂的关联查询。在 es 里该怎么玩儿,es 里面的复杂的关联查询尽量别用,一旦用了性能一般都不太好。 最好是先在 Java 系统里就完成关联,将关联好的数据直接写入 es 中。搜索的时候,就不需要利用 es 的搜索语法来完成 join 之类的关联搜索了。 document 模型设计是非常重要的,很多操作,不要在搜索的时候才想去执行各种复杂的乱七八糟的操作。es 能支持的操作就那么多,不要考虑用 es 做一些它不好操作的事情。如果真的有那种操作,尽量在 document 模型设计的时候,写入的时候就完成。另外对于一些太复杂的操作,比如 join/nested/parent-child 搜索都要尽量避免,性能都很差的。 分页性能优化 es 的分页是较坑的,为啥呢?举个例子吧,假如你每页是 10 条数据,你现在要查询第 100 页,实际上是会把每个 shard 上存储的前 1000 条数据都查到一个协调节点上,如果你有个 5 个 shard,那么就有 5000 条数据,接着协调节点对这 5000 条数据进行一些合并、处理,再获取到最终第 100 页的 10 条数据。 分布式的,你要查第 100 页的 10 条数据,不可能说从 5 个 shard,每个 shard 就查 2 条数据,最后到协调节点合并成 10 条数据吧?你必须得从每个 shard 都查 1000 条数据过来,然后根据你的需求进行排序、筛选等等操作,最后再次分页,拿到里面第 100 页的数据。你翻页的时候,翻的越深,每个 shard 返回的数据就越多,而且协调节点处理的时间越长,非常坑爹。所以用 es 做分页的时候,你会发现越翻到后面,就越是慢。 我们之前也是遇到过这个问题,用 es 作分页,前几页就几十毫秒,翻到 10 页或者几十页的时候,基本上就要 5~10 秒才能查出来一页数据了。 有什么解决方案吗? 不允许深度分页(默认深度分页性能很差) 跟产品经理说,你系统不允许翻那么深的页,默认翻的越深,性能就越差。 类似于 app 里的推荐商品不断下拉出来一页一页的 类似于微博中,下拉刷微博,刷出来一页一页的,你可以用 scroll api,关于如何使用,自行上网搜索。 scroll 会一次性给你生成所有数据的一个快照,然后每次滑动向后翻页就是通过游标 scroll_id 移动,获取下一页下一页这样子,性能会比上面说的那种分页性能要高很多很多,基本上都是毫秒级的。 但是,唯一的一点就是,这个适合于那种类似微博下拉翻页的,不能随意跳到任何一页的场景。也就是说,你不能先进入第 10 页,然后去第 120 页,然后又回到第 58 页,不能随意乱跳页。所以现在很多产品,都是不允许你随意翻页的,app,也有一些网站,做的就是你只能往下拉,一页一页的翻。 初始化时必须指定 scroll 参数,告诉 es 要保存此次搜索的上下文多长时间。你需要确保用户不会持续不断翻页翻几个小时,否则可能因为超时而失败。 除了用 scroll api,你也可以用 search_after 来做,search_after 的思想是使用前一页的结果来帮助检索下一页的数据,显然,这种方式也不允许你随意翻页,你只能一页页往后翻。初始化时,需要使用一个唯一值的字段作为 sort 字段。 往期回顾: 【Java问答学堂】1期 为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么区别,以及适合哪些场景? 【Java问答学堂】2期 如何保证消息队列的高可用? 【Java问答学堂】3期 如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性? 【Java问答学堂】4期 如何保证消息的可靠性传输?(如何处理消息丢失的问题?) 【Java问答学堂】5期 如何保证消息的顺序性? 【Java问答学堂】6期 如何解决消息队列的延时以及过期失效问题? 【Java问答学堂】7期 如果让你写一个消息队列,该如何进行架构设计? 【Java问答学堂】8期 es 的分布式架构原理能说一下么(es 是如何实现分布式的啊)? 【Java问答学堂】9期 es 写入数据的工作原理是什么啊?es 查询数据的工作原理是什么啊?

剑曼红尘 2020-04-28 14:17:05 0 浏览量 回答数 0

问题

【Java问答学堂】10期 es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?

剑曼红尘 2020-04-28 14:16:56 0 浏览量 回答数 1

回答

转自:阿里云官网 — 知乎 写好代码,阿里专家沉淀了一套“如何写复杂业务代码”的方法论,在此分享给大家,相信同样的方法论可以复制到大部分复杂业务场景。 一文教会你如何写复杂业务代码 了解我的人都知道,我一直在致力于应用架构和代码复杂度的治理。 这两天在看零售通商品域的代码。面对零售通如此复杂的业务场景,如何在架构和代码层面进行应对,是一个新课题。针对该命题,我进行了比较细致的思考和研究。结合实际的业务场景,我沉淀了一套“如何写复杂业务代码”的方法论,在此分享给大家。 我相信,同样的方法论可以复制到大部分复杂业务场景。 一个复杂业务的处理过程 业务背景 简单的介绍下业务背景,零售通是给线下小店供货的B2B模式,我们希望通过数字化重构传统供应链渠道,提升供应链效率,为新零售助力。阿里在中间是一个平台角色,提供的是Bsbc中的service的功能。 在商品域,运营会操作一个“上架”动作,上架之后,商品就能在零售通上面对小店进行销售了。是零售通业务非常关键的业务操作之一,因此涉及很多的数据校验和关联操作。 针对上架,一个简化的业务流程如下所示: 过程分解 像这么复杂的业务,我想应该没有人会写在一个service方法中吧。一个类解决不了,那就分治吧。 说实话,能想到分而治之的工程师,已经做的不错了,至少比没有分治思维要好很多。我也见过复杂程度相当的业务,连分解都没有,就是一堆方法和类的堆砌。 不过,这里存在一个问题:即很多同学过度的依赖工具或是辅助手段来实现分解。比如在我们的商品域中,类似的分解手段至少有3套以上,有自制的流程引擎,有依赖于数据库配置的流程处理: 本质上来讲,这些辅助手段做的都是一个pipeline的处理流程,没有其它。因此,我建议此处最好保持KISS(Keep It Simple and Stupid),即最好是什么工具都不要用,次之是用一个极简的Pipeline模式,最差是使用像流程引擎这样的重方法。 除非你的应用有极强的流程可视化和编排的诉求,否则我非常不推荐使用流程引擎等工具。第一,它会引入额外的复杂度,特别是那些需要持久化状态的流程引擎;第二,它会割裂代码,导致阅读代码的不顺畅。大胆断言一下,全天下估计80%对流程引擎的使用都是得不偿失的。 回到商品上架的问题,这里问题核心是工具吗?是设计模式带来的代码灵活性吗?显然不是,问题的核心应该是如何分解问题和抽象问题,知道金字塔原理的应该知道,此处,我们可以使用结构化分解将问题解构成一个有层级的金字塔结构: 按照这种分解写的代码,就像一本书,目录和内容清晰明了。以商品上架为例,程序的入口是一个上架命令(OnSaleCommand), 它由三个阶段(Phase)组成。 @Command public class OnSaleNormalItemCmdExe { @Resource private OnSaleContextInitPhase onSaleContextInitPhase; @Resource private OnSaleDataCheckPhase onSaleDataCheckPhase; @Resource private OnSaleProcessPhase onSaleProcessPhase; @Override public Response execute(OnSaleNormalItemCmd cmd) { OnSaleContext onSaleContext = init(cmd); checkData(onSaleContext); process(onSaleContext); return Response.buildSuccess(); } private OnSaleContext init(OnSaleNormalItemCmd cmd) { return onSaleContextInitPhase.init(cmd); } private void checkData(OnSaleContext onSaleContext) { onSaleDataCheckPhase.check(onSaleContext); } private void process(OnSaleContext onSaleContext) { onSaleProcessPhase.process(onSaleContext); } } 每个Phase又可以拆解成多个步骤(Step),以OnSaleProcessPhase为例,它是由一系列Step组成的: @Phase public class OnSaleProcessPhase { @Resource private PublishOfferStep publishOfferStep; @Resource private BackOfferBindStep backOfferBindStep; //省略其它step public void process(OnSaleContext onSaleContext){ SupplierItem supplierItem = onSaleContext.getSupplierItem(); // 生成OfferGroupNo generateOfferGroupNo(supplierItem); // 发布商品 publishOffer(supplierItem); // 前后端库存绑定 backoffer域 bindBackOfferStock(supplierItem); // 同步库存路由 backoffer域 syncStockRoute(supplierItem); // 设置虚拟商品拓展字段 setVirtualProductExtension(supplierItem); // 发货保障打标 offer域 markSendProtection(supplierItem); // 记录变更内容ChangeDetail recordChangeDetail(supplierItem); // 同步供货价到BackOffer syncSupplyPriceToBackOffer(supplierItem); // 如果是组合商品打标,写扩展信息 setCombineProductExtension(supplierItem); // 去售罄标 removeSellOutTag(offerId); // 发送领域事件 fireDomainEvent(supplierItem); // 关闭关联的待办事项 closeIssues(supplierItem); } } 看到了吗,这就是商品上架这个复杂业务的业务流程。需要流程引擎吗?不需要,需要设计模式支撑吗?也不需要。对于这种业务流程的表达,简单朴素的组合方法模式(Composed Method)是再合适不过的了。 因此,在做过程分解的时候,我建议工程师不要把太多精力放在工具上,放在设计模式带来的灵活性上。而是应该多花时间在对问题分析,结构化分解,最后通过合理的抽象,形成合适的阶段(Phase)和步骤(Step)上。 过程分解后的两个问题的确,使用过程分解之后的代码,已经比以前的代码更清晰、更容易维护了。不过,还有两个问题值得我们去关注一下: 1、领域知识被割裂肢解什么叫被肢解? 因为我们到目前为止做的都是过程化拆解,导致没有一个聚合领域知识的地方。每个Use Case的代码只关心自己的处理流程,知识没有沉淀。相同的业务逻辑会在多个Use Case中被重复实现,导致代码重复度高,即使有复用,最多也就是抽取一个util,代码对业务语义的表达能力很弱,从而影响代码的可读性和可理解性。 2、代码的业务表达能力缺失 试想下,在过程式的代码中,所做的事情无外乎就是取数据--做计算--存数据,在这种情况下,要如何通过代码显性化的表达我们的业务呢? 说实话,很难做到,因为我们缺失了模型,以及模型之间的关系。脱离模型的业务表达,是缺少韵律和灵魂的。 举个例子,在上架过程中,有一个校验是检查库存的,其中对于组合品(CombineBackOffer)其库存的处理会和普通品不一样。原来的代码是这么写的: boolean isCombineProduct = supplierItem.getSign().isCombProductQuote(); // supplier.usc warehouse needn't check if (WarehouseTypeEnum.isAliWarehouse(supplierItem.getWarehouseType())) { // quote warehosue check if (CollectionUtil.isEmpty(supplierItem.getWarehouseIdList()) && !isCombineProduct) { throw ExceptionFactory.makeFault(ServiceExceptionCode.SYSTEM_ERROR, "亲,不能发布Offer,请联系仓配运营人员,建立品仓关系!"); } // inventory amount check Long sellableAmount = 0L; if (!isCombineProduct) { sellableAmount = normalBiz.acquireSellableAmount(supplierItem.getBackOfferId(), supplierItem.getWarehouseIdList()); } else { //组套商品 OfferModel backOffer = backOfferQueryService.getBackOffer(supplierItem.getBackOfferId()); if (backOffer != null) { sellableAmount = backOffer.getOffer().getTradeModel().getTradeCondition().getAmountOnSale(); } } if (sellableAmount < 1) { throw ExceptionFactory.makeFault(ServiceExceptionCode.SYSTEM_ERROR, "亲,实仓库存必须大于0才能发布,请确认已补货.\r[id:" + supplierItem.getId() + "]"); } } 然而,如果我们在系统中引入领域模型之后,其代码会简化为如下: if(backOffer.isCloudWarehouse()){ return; } if (backOffer.isNonInWarehouse()){ throw new BizException("亲,不能发布Offer,请联系仓配运营人员,建立品仓关系!"); } if (backOffer.getStockAmount() < 1){ throw new BizException("亲,实仓库存必须大于0才能发布,请确认已补货.\r[id:" + backOffer.getSupplierItem().getCspuCode() + "]"); } 有没有发现,使用模型的表达要清晰易懂很多,而且也不需要做关于组合品的判断了,因为我们在系统中引入了更加贴近现实的对象模型(CombineBackOffer继承BackOffer),通过对象的多态可以消除我们代码中的大部分的if-else。 过程分解+对象模型 通过上面的案例,我们可以看到有过程分解要好于没有分解,过程分解+对象模型要好于仅仅是过程分解。对于商品上架这个case,如果采用过程分解+对象模型的方式,最终我们会得到一个如下的系统结构: 写复杂业务的方法论 通过上面案例的讲解,我想说,我已经交代了复杂业务代码要怎么写:即自上而下的结构化分解+自下而上的面向对象分析。 接下来,让我们把上面的案例进行进一步的提炼,形成一个可落地的方法论,从而可以泛化到更多的复杂业务场景。 上下结合 所谓上下结合,是指我们要结合自上而下的过程分解和自下而上的对象建模,螺旋式的构建我们的应用系统。这是一个动态的过程,两个步骤可以交替进行、也可以同时进行。这两个步骤是相辅相成的,上面的分析可以帮助我们更好的理清模型之间的关系,而下面的模型表达可以提升我们代码的复用度和业务语义表达能力。其过程如下图所示: 使用这种上下结合的方式,我们就有可能在面对任何复杂的业务场景,都能写出干净整洁、易维护的代码。 能力下沉 一般来说实践DDD有两个过程: 1. 套概念阶段 了解了一些DDD的概念,然后在代码中“使用”Aggregation Root,Bonded Context,Repository等等这些概念。更进一步,也会使用一定的分层策略。然而这种做法一般对复杂度的治理并没有多大作用。 2. 融会贯通阶段 术语已经不再重要,理解DDD的本质是统一语言、边界划分和面向对象分析的方法。 大体上而言,我大概是在1.7的阶段,因为有一个问题一直在困扰我,就是哪些能力应该放在Domain层,是不是按照传统的做法,将所有的业务都收拢到Domain上,这样做合理吗?说实话,这个问题我一直没有想清楚。 因为在现实业务中,很多的功能都是用例特有的(Use case specific)的,如果“盲目”的使用Domain收拢业务并不见得能带来多大的益处。相反,这种收拢会导致Domain层的膨胀过厚,不够纯粹,反而会影响复用性和表达能力。 鉴于此,我最近的思考是我们应该采用能力下沉的策略。 所谓的能力下沉,是指我们不强求一次就能设计出Domain的能力,也不需要强制要求把所有的业务功能都放到Domain层,而是采用实用主义的态度,即只对那些需要在多个场景中需要被复用的能力进行抽象下沉,而不需要复用的,就暂时放在App层的Use Case里就好了。 注:Use Case是《架构整洁之道》里面的术语,简单理解就是响应一个Request的处理过程 通过实践,我发现这种循序渐进的能力下沉策略,应该是一种更符合实际、更敏捷的方法。因为我们承认模型不是一次性设计出来的,而是迭代演化出来的。 下沉的过程如下图所示,假设两个use case中,我们发现uc1的step3和uc2的step1有类似的功能,我们就可以考虑让其下沉到Domain层,从而增加代码的复用性。 指导下沉有两个关键指标:代码的复用性和内聚性。 复用性是告诉我们When(什么时候该下沉了),即有重复代码的时候。 内聚性是告诉我们How(要下沉到哪里),功能有没有内聚到恰当的实体上,有没有放到合适的层次上(因为Domain层的能力也是有两个层次的,一个是Domain Service这是相对比较粗的粒度,另一个是Domain的Model这个是最细粒度的复用)。 比如,在我们的商品域,经常需要判断一个商品是不是最小单位,是不是中包商品。像这种能力就非常有必要直接挂载在Model上。 public class CSPU { private String code; private String baseCode; //省略其它属性 /** * 单品是否为最小单位。 * */ public boolean isMinimumUnit(){ return StringUtils.equals(code, baseCode); } /** * 针对中包的特殊处理 * */ public boolean isMidPackage(){ return StringUtils.equals(code, midPackageCode); } } 之前,因为老系统中没有领域模型,没有CSPU这个实体。你会发现像判断单品是否为最小单位的逻辑是以StringUtils.equals(code, baseCode)的形式散落在代码的各个角落。这种代码的可理解性是可想而知的,至少我在第一眼看到这个代码的时候,是完全不知道什么意思。 业务技术要怎么做 写到这里,我想顺便回答一下很多业务技术同学的困惑,也是我之前的困惑:即业务技术到底是在做业务,还是做技术?业务技术的技术性体现在哪里? 通过上面的案例,我们可以看到业务所面临的复杂性并不亚于底层技术,要想写好业务代码也不是一件容易的事情。 业务技术和底层技术人员唯一的区别是他们所面临的问题域不一样。业务技术面对的问题域变化更多、面对的人更加庞杂。而底层技术面对的问题域更加稳定、但对技术的要求更加深。比如,如果你需要去开发Pandora,你就要对Classloader有更加深入的了解才行。 但是,不管是业务技术还是底层技术人员,有一些思维和能力都是共通的。比如,分解问题的能力,抽象思维,结构化思维等等。 用我的话说就是:“做不好业务开发的,也做不好技术底层开发,反之亦然。业务开发一点都不简单,只是我们很多人把它做“简单”了因此,如果从变化的角度来看,业务技术的难度一点不逊色于底层技术,其面临的挑战甚至更大。 因此,我想对广大的从事业务技术开发的同学说:沉下心来,夯实自己的基础技术能力、OO能力、建模能力... 不断提升抽象思维、结构化思维、思辨思维... 持续学习精进,写好代码。我们可以在业务技术岗做的很”技术“!。

茶什i 2020-01-10 11:53:44 0 浏览量 回答数 0

回答

12月17日更新 请问下同时消费多个topic的情况下,在richmap里面可以获取到当前消息所属的topic吗? 各位大佬,你们实时都是怎样重跑数据的? 有木有大神知道Flink能否消费多个kafka集群的数据? 这个问题有人遇到吗? 你们实时读取广业务库到kafka是通过什么读的?kafka connector 的原理是定时去轮询,这样如果表多了,会不会影响业务库的性能?甚至把业务库搞挂? 有没有flink 1.9 连接 hive的例子啊?官网文档试了,没成功 请问各位是怎么解决实时流数据倾斜的? 请问一下,对于有状态的任务,如果任务做代码升级的时候,可否修改BoundedOutOfOrdernessTimestampExtractor的maxOutOfOrderness呢?是否会有影响数据逻辑的地方呢? 老哥们有做过统计从0点开始截止到现在时刻的累计用户数吗? 比如五分钟输出一次,就是7点输出0点到7点的累计用户,7:05输出0点到7:05的累计用户。 但是我这里有多个维度,现在用redis来做的。 想知道有没有更好的姿势? 实时数仓用什么存储介质来存储维表,维表有大有小,大的大概5千万左右。 各位大神有什么建议和经验分享吗? 请教个问题,就是flink的窗口触发必须是有数据才会触发吗?我现在有个这样的需求,就是存在窗口内没有流数据进入,但是窗口结束是要触发去外部系统获取上一个窗口的结果值作为本次窗口的结果值!现在没有流数据进入窗口结束时如何触发? kafkaSource.setStartFromTimestamp(timestamp); 发现kafkasource从指定时间开始消费,有些topic有效,有效topic无效,大佬们有遇到过吗? 各位大佬,flink两个table join的时候,为什么打印不出来数据,已经赋了关联条件了,但是也不报错 各位大佬 请教一下 一个faile的任务 会在这里面存储展示多久啊? 各位大佬,我的程序每五分钟一个窗口做了基础指标的统计,同时还想统计全天的Uv,这个是用State就能实现吗? 大佬们,flink的redis sink是不是只适用redis2.8.5版本? 有CEP 源码中文注释的发出来学习一下吗? 有没有拿flink和tensorflow集成的? 那位大神,给一个java版的flink1.7 读取kafka数据,做实时监控和统计的功能的代码案例。 请问下风控大佬,flink为风控引擎做数据支撑的时候,怎么应对风控规则的不断变化,比如说登录场景需要实时计算近十分钟内登录次数超过20次用户,这个规则可能会变成计算近五分钟内登录次数超过20次的。 想了解一下大家线上Flink作业一般开始的时候都分配多少内存?广播没办法改CEP flink支持多流(大于2流)join吗? 谁能帮忙提供一下flink的多并行度的情况下,怎么保证数据有序 例如map并行度为2 那就可能出现数据乱序的情况啊 请教下现在从哪里可以可以看单任务的运行状况和内存占用情况,flink页面上能看单个任务的内存、cpu 大佬们 flink1.9 停止任务手动保存savepoint的命令是啥? flink 一个流计算多个任务和 还是一个流一个任务好? flink 1.9 on yarn, 自定义个connector里面用了jni, failover以后 就起不来了, 报错重复load so的问题。 我想问一下 这个,怎么解决。 难道flink 里面不能用jni吗。 ide里面调试没有问题,部署到集群就会报错了,可能什么问题? 请教一下对于长时间耗内存很大的任务,大家都是开checkpoint机制,采用rocksdb做状态后端吗? 请问下大佬,flink jdbc读取mysql,tinyin字段类型自动转化为Boolean有没有好的解决方法 Flink 1.9版本的Blink查询优化器,Hive集成,Python API这几个功能好像都是预览版,请问群里有大佬生产环境中使用这些功能了吗? 想做一个监控或数据分析的功能,如果我flink 的datastreaming实现消费Kafka的数据,但是我监控的规则数据会增加或修改,但是不想停这个正在运行的flink程序,要如何传递这个动态变化的规则数据,大神给个思路,是用ConnectedStream这个吗?还是用Broadcast ?还有一个,比如我的规则数据是存放在Mysql表中,用什么事件隔30秒去触发读取mysql规则表呢?谢谢! 想做一个监控或数据分析的功能,如果我flink 的datastreaming实现消费Kafka的数据,但是我监控的规则数据会增加或修改,但是不想停这个正在运行的flink程序,要如何传递这个动态变化的规则数据,大神给个思路,是用ConnectedStream这个吗?还是用Broadcast ?还有一个,比如我的规则数据是存放在Mysql表中,用什么事件隔30秒去触发读取mysql规则表呢?谢谢! 各位大佬,在一个 Job 计算过程中,查询 MySQL 来补全额外数据,是一个好的实践嘛?还是说流处理过程中应该尽量避免查询额外的数据? Flink web UI是jquery写的吗? 12月9日更新 成功做完一次checkpoint后,会覆盖上一次的checkpoint吗? 数据量较大时,flink实时写入hbase能够异步写入吗? flink的异步io,是不是只是适合异步读取,并不适合异步写入呀? 请问一下,flink将结果sink到redis里面会不会对存储的IO造成很大的压力,如何批量的输出结果呢? 大佬们,flink 1.9.0版本里DataStream api,若从kafka里加载完数据以后,从这一个流中获取数据进行两条业务线的操作,是可以的吗? flink 中的rocksdb状态怎么样能可视化的查看有大佬知道吗? 感觉flink 并不怎么适合做hive 中的计算引擎来提升hive 表的查询速度 大佬们,task端rocksdb状态 保存路径默认是在哪里的啊?我想挂载个新磁盘 把状态存到那里去 flink 的state 在窗口滑动到下一个窗口时候 上一个窗口销毁时候 state会自己清除吗? 求助各位大佬,一个sql里面包含有几个大的hop滑动窗口,如15个小时和24个小时,滑动步长为5分钟,这样就会产生很多overlap 数据,导致状态会很快就达到几百g,然后作业内存也很快达到瓶颈就oom了,然后作业就不断重启,很不稳定,请问这个业务场景有什么有效的解决方案么? 使用jdbcsink的时候,如果连接长时间不使用 就会被关掉,有人遇到过吗?使用的是ddl的方式 如何向云邪大佬咨询FLink相关技术问题? 请问各位公司有专门开发自己的实时计算平台的吗? 请问各位公司有专门开发自己的实时计算平台的吗? 有哪位大佬有cdh集成安装flink的文档或者手册? 有哪位大佬有cdh集成安装flink的文档或者手册? 想问下老哥们都是怎么统计一段时间的UV的? 是直接用window然后count嘛? Flink是不是也是这样的? 请问现在如有个实时程序,根据一个mysql的维表来清洗,但是我这个mysql表里面就只有几条信息且可能会变。 我想同一个定时器去读mysql,然后存在对象中,流清洗的时候读取这个数据,这个想法可行吗?我目前在主类里面定义一个对象,然后往里面更新,发现下面的map方法之类的读不到我更新进去的值 有大佬做过flink—sql的血缘分析吗? 12月3日更新 请教一下,为什么我flume已经登录成功了keytab认证的kafka集群,但是就是消费不到数据呢? flink 写入mysql 很长一段时间没有写入,报错怎么解决呢? flink timestamp转换为date类型,有什么函数吗 Run a single Flink job on YARN 我采用这种模式提交任务,出现无法找到 开启 HA 的ResourceManager Failed to connect to server: xxxxx:8032: retries get failed due to exceeded maximum allowed retries number: 0 有大佬遇到过吗 ? 各位大佬,请问有Flink写S3的方案吗? flink 连接hbase 只支持1.4.3版本? onnector: type: hbase version: "1.4.3" 请问 flink1.9能跑在hadoop3集群上吗? 滑动窗口 排序 报错这个是什么原因呢? 这个pravega和kafka有啥区别? flink 开发里数据源配置了RDS,但是在RDS里没有看到创建的表,是为什么呢? Tumbling Window里的数据,是等窗口期内的数据到齐之后一次性处理,还是到了一条就处理一条啊 双流join后再做time window grouping. 但是双流join会丢失时间属性,请问大家如何解决 stream processing with apache flink,这本书的中译版 现在可以买吗? flink on yarn时,jm和tm占用的内存最小是600M,这个可以修改吗? 各位大佬,使用默认的窗口Trigger,在什么情况下会触发两次啊?窗口关闭后,然后还来了这个窗口期内的数据,并且开了allowedLateness么? flink web里可以像storm那样 看每条数据在该算子中的平均耗时吗? 各位大佬,flink任务的并发数调大到160+以后,每隔几十分钟就会出现一次TM节点连接丢失的异常,导致任务重启。并发在100时运行比较稳定,哪位大佬可以提供下排查的思路? 感觉stateful function 是下一个要发力的点,这个现在有应用案例吗? 我有2个子网(a子网,b子网)用vpn联通,vpn几周可能会断一次。a子网有一个kafka集群,b子网运行我自己的flink集群和应用,b子网的flink应用连接到a子网的kafka集群接收消息来处理入库到数仓去。我的问题是,如果vpn断开,flink consumer会异常整个作业退出吗?如果作业退出,我重连vpn后,能从auto checkpoint再把flink应用恢复到出错时flink kafka consumer应该读取的partition/offset位置吗?flink的checkpoint除了保存自己开发的算子里的state,kafkaconsumer里的partition/offset也会保存和恢复吗? flink的反压为什么不加入metrics呢 hdfs是不是和flink共用一个集群? flink消费kafka,可以从指定时间消费的吗?目前提供的接口只是根据offset消费?有人知道怎么处理? flink 的Keyby是不是只是repartition而已?没有将key相同的数据放到一个组合里面 电商大屏 大家推荐用什么来做吗? 我比较倾向用数据库,因为有些数据需要join其他表,flink充当了什么角色,对这个有点迷,比如统计当天订单量,卖了多少钱,各个省的销量,销售金额,各个品类的销售量销售金额 开源1.9的sql中怎么把watermark给用起来,有大神知道吗? 有没有人能有一些flink的教程 代码之类的分享啊 采用了checkpoint,程序停止了之后,什么都不改,直接重启,还是能接着继续运行吗?如果可以的话,savepoint的意义又是什么呢? 有人做过flink 的tpc-ds测试吗,能不能分享一下操作的流程方法 checkpoint是有时间间隔的,也就可以理解为checkpoint是以批量操作的,那如果还没进行ckecnpoint就挂了,下次从最新的一次checkpoint重启,不是重复消费了? kafka是可以批量读取数据,但是flink是一条一条处理的,应该也可以一条一条提交吧。 各位大佬,flink sql目前是不是不支持tumbling window join,有人了解吗? 你们的HDFS是装在taskmanager上还是完全分开的,请问大佬们有遇到这种情况吗? 大佬们flink检查点存hdfs的话怎么自动清理文件啊 一个128M很快磁盘就满了 有谁遇到过这个问题? 请教一下各位,这段代码里面,我想加一个trigger,实现每次有数据进window时候,就输出,而不是等到window结束再输出,应该怎么加? 麻烦问下 flink on yarn 执行 客户端启动时 报上面错,是什么原因造成的 求大佬指点 ERROR org.apache.flink.client.program.rest.RestClusterClient - Error while shutting down cluster java.util.concurrent.ExecutionException: org.apache.flink.runtime.concurrent.FutureUtils$RetryException: Could not complete the operation. Number of retries has been exhausted. 大家怎么能动态的改变 flink WindowFunction 窗口数据时间 flink on yarn之后。yarn的日志目录被写满,大家如配置的? Flink1.9 启动 yarn-session报这个错误 怎么破? yarn 模式下,checkpoint 是存在 JobManager的,提交任务也是提交给 JobManager 的吧? heckpoint机制,会不会把window里面的数据全部放checkpoint里面? Flink On Yarn的模式下,如果通过REST API 停止Job,并触发savepiont呢 jenkins自动化部署flink的job,一般用什么方案?shell脚本还是api的方式? 各位大佬,开启增量checkpoint 情况下,这个state size 是总的checkpoint 大小,还是增量上传的大小? 想用状态表作为子表 外面嵌套窗口 如何实现呢 因为状态表group by之后 ctime会失去时间属性,有哪位大佬知道的? 你们有试过在同样的3台机器上部署两套kafka吗? 大家有没有比较好的sql解析 组件(支持嵌套sql)? richmapfuntion的open/close方法,和处理数据的map方法,是在同一个线程,还是不同线程调用的? flink on yarn 提交 参数 -p 20 -yn 5 -ys 3 ,我不是只启动了5个container么? Flink的乱序问题怎么解决? 我对数据流先进行了keyBy,print的时候是有数据的,一旦进行了timeWindow滑动窗口就没有数据了,请问是什么情况呢? 搭建flinksql平台的时候,怎么处理udf的呀? 怎么查看sentry元数据里哪些角色有哪些权限? 用java api写的kafka consumer能消费到的消息,但是Flink消费不到,这是为啥? 我state大小如果为2G左右 每次checkpoint会不会有压力? link-table中的udaf能用deltaTrigger么? flink1.7.2,场景是一分钟为窗口计算每分钟传感器的最高温度,同时计算当前分钟与上一分钟最高温 001 Flink集群支持kerberos认证吗?也就是说flink客户端需要向Flink集群进行kerberos认证,认证通过之后客户端才能提交作业到Flink集群运行002 Flink支持多租户吗? 如果要对客户端提交作业到flink进行访问控制,你们有类似的这种使用场景吗? flink可以同时读取多个topic的数据吗? Flink能够做实时ETL(oracle端到oracle端或者多端)么? Flink是否适合普通的关系型数据库呢? Flink是否适合普通的关系型数据库呢? 流窗口关联mysql中的维度表大佬们都是怎么做的啊? 怎么保证整个链路的exactly one episode精准一次,从source 到flink到sink? 在SQL的TUMBLE窗口的统计中,如果没数据进来的,如何让他也定期执行,比如进行count计算,让他输出0? new FlinkKafkaConsumer010[String]("PREWARNING",new JSONKeyValueDeserializationSchema(true), kafkaProps).setStartFromGroupOffsets() ) 我这样new 它说要我传个KeyedDeserializationSchema接口进去 flink里面broadcast state想定时reload怎么做?我用kafka里的stream flink独立模式高可用搭建必需要hadoop吗? 有人用增量cleanupIncrementally的方式来清理状态的嘛,感觉性能很差。 flink sink to hbase继承 RichOutputFormat运行就报错 kafka 只有低级 api 才拿得到 offset 吗? 有个问题咨询下大家,我的flinksql中有一些参数是要从mysql中获取的,比如我flink的sql是select * from aa where cc=?,这个问号的参数需要从mysql中获取,我用普通的jdbc进行连接可以获的,但是有一个问题,就是我mysql的数据改了之后必须重启flink程序才能解决这个问题,但这肯定不符合要求,请问大家有什么好的办法吗? flink里怎样实现多表关联制作宽表 flink写es,因为半夜es集群做路由,导致写入容易失败,会引起source的反压,然后导致checkpoint超时任务卡死,请问有没有办法在下游es处理慢的时候暂停上游的导入来缓解反压? flink 写parquet 文件,使用StreamingFileSink streamingFileSink = StreamingFileSink.forBulkFormat( new Path(path), ParquetAvroWriters.forReflectRecord(BuyerviewcarListLog.class)). withBucketAssigner(bucketAssigner).build(); 报错 java.lang.UnsupportedOperationException: Recoverable writers on Hadoop are only supported for HDFS and for Hadoop version 2.7 or newer 1.7.2 NoWindowInnerJoin这个实现,我看实现了CleanupState可更新过期时间删除当前key状态的接口,是不是这个1.7.2版本即使有个流的key一直没有被匹配到他的状态也会被清理掉,就不会存在内存泄漏的问题了? flink1.7.2 想在Table的UDAF中使用State,但是发现UDAF的open函数的FunctionContext中对于RuntimeContext是一个private,无法使用,大佬,如何在Table的UDAF中使用State啊? Flink有什么性能测试工具吗? 项目里用到了了KafkaTableSourceSinkFactory和JDBCTableSourceSinkFactory。maven打包后,META-INF里只会保留第一个 标签的org.apache.flink.table.factories.TableFactory内容。然后执行时就会有找不到合适factory的报错,请问有什么解决办法吗? 为什么这个这段逻辑 debug的时候 是直接跳过的 各位大佬,以天为单位的窗口有没有遇到过在八点钟的时候会生成一条昨天的记录? 想问一下,我要做一个规则引擎,需要动态改变规则,如何在flink里面执行? flink-1.9.1/bin/yarn-session.sh: line 32: construc 我要用sql做一个规则引擎,需要动态改变规则,如何在flink里面执行? 我要用sql做一个规则引擎,需要动态改变规则,如何在flink里面执行? 一般公司的flink job有没有进程进行守护?有专门的工具或者是自己写脚本?这种情况针对flink kafka能不能通过java获取topic的消息所占空间大小? Flink container was removed这个咋解决的。我有时候没有数据的时候也出现这 大家有没有这种场景,数据从binlog消费,这个信息是订单信息,同一个订单id,会有不同状态的变更 问大家个Hive问题,新建的hive外部分区表, 怎么把HDFS数据一次性全部导入hive里 ? flink里面的broadcast state值,会出现broad流的数据还没put进mapstat Flink SQL DDL 创建表时,如何定义字段的类型为proctime? 请问下窗口计算能对历史数据进行处理吗?比如kafka里的写数据没停,窗口计算的应用停掉一段时间再开起 请问下,想统计未退费的订单数量,如果一个订单退费了(发过来一个update流),flink能做到对结果进行-1吗,这样的需求sql支持吗? 使用Flink sql时,对table使用了group by操作。然后将结果转换为流时是不是只能使用的toRetractStream方法不能使用toAppendStream方法。 百亿数据实时去重,有哪位同学实践过吗? 你们的去重容许有误差?因为bloom filter其实只能给出【肯定不存在】和【可能存在】两种结果。对于可能存在这种结果,你们会认为是同一条记录? 我就运行了一个自带的示例,一运行就报错然后web页面就崩了 flink定时加载外部数据有人做过吗? NoSuchMethodError: org.apache.flink.api.java.Utils.resolveFactory(Ljava/lang/ThreadLocal;Ljava/lang/Object;)Ljava/util/Optional 各位知道这个是那个包吗? flink 可以把大量数据写入mysql吗?比如10g flink sql 解析复杂的json可以吗? 在页面上写规则,用flink执行,怎么传递给flink? 使用cep时,如何动态添加规则? 如何基于flink 实现两个很大的数据集的交集 并集 差集? flink的应用场景是?除了实时 各位好,请教一下,滑动窗口,每次滑动都全量输出结果,外部存储系统压力大,是否有办法,只输出变化的key? RichSinkFunction close只有任务结束时候才会去调用,但是数据库连接一直拿着,最后成了数据库连接超时了,大佬们有什么好的建议去处理吗?? 为啥我的自定义函数注册,然后sql中使用不了? 请问一下各位老师,flink flapmap 中的collector.collect经常出现Buffer pool is destroyed可能是什么原因呢? 用asyncIO比直接在map里实现读hbase还慢,在和hbase交互这块儿,每个算子都加了时间统计 请教一下,在yarn上运行,会找不到 org.apache.flink.streaming.util 请问下大佬,flink1.7.2对于sql的支持是不是不怎么好啊 ,跑的数据一大就会报错。 各位大佬,都用什么来监控flink集群? flink 有那种把多条消息聚合成一条的操作吗,比如说每五十条聚合成一条 如何可以让checkpoint 跳过对齐呢? 请问 阿里云实时计算(Blink)支持这4个源数据表吗?DataHub Kafka MQ MaxCompute? 为啥checkpoint时间会越来越长,请问哪位大佬知道是因为啥呢? 请问Flink的最大并行度跟kafka partition数量有关系吗? source的并行度应该最好是跟partition数量一致吧,那剩下的算子并行度呢? Flink有 MLIB库吗,为什么1.9中没有了啊? 请教一下,有没有flink ui的文章呢?在这块内存配置,我给 TM 配置的内存只有 4096 M,但是这里为什么对不上呢?请问哪里可以看 TM 内存使用了多少呢? 请教个问题,fink RichSinkFunction的invoke方法是什么时候被调用的? 请教一下,flink的window的触发条件 watermark 小于 window 的 end_time。这个 watermark 为什么是针对所有数据的呢?没有设计为一个 key 一个 watermark 呢? 就比如说有 key1、key2、key3,有3个 watermark,有 3个 window interval不支持left join那怎么可以实现把窗口内左表的数据也写到下游呢? 各位 1、sink如何只得到最终的结果而不是也输出过程结果 ;2、不同的运算如何不借助外部系统的存储作为另外一个运算的source 请教各位一个问题,flink中设置什么配置可以取消Generic这个泛型,如图报错: 有大佬在吗,线上遇到个问题,但是明明内存还有200多G,然后呢任务cancel不了,台也取消不了程序 flink遇到The assigned slot container_1540803405745_0094_01_000008_1 was removed. 有木有大佬遇到过。在flink on yarn上跑 这个报错是什么意思呢?我使用滑动窗口的时候出现报错 flink 双流union状态过期不清理有遇到的吗? 大家有没有这种场景,数据从binlog消费,这个信息是订单信息,同一个订单id,会有不同状态的变更,如果订单表与商品明细join查询,就会出现n条重复数据,这样数据就不准了,flink 这块有没有比较好的实战经验的。 大佬们、有没有人遇到过使用一分钟的TumblingEventTimeWindows,但是没有按时触发窗口、而是一直等到下一条消息进来之后才会把这个窗口的数据发送出去的? flink 有办法 读取 pytorch的 模型文件吗? 大佬们、有没有人遇到过使用一分钟的TumblingEventTimeWindows,但是没有按时触发窗口、而是一直等到下一条消息进来之后才会把这个窗口的数据发送出去的? flink timestamp转换为date类型,有什么函数吗 flink 写入mysql 很长一段时间没有写入,报错怎么解决呢? flink 有办法 读取 pytorch的 模型文件吗? 有没有大佬知道实时报表怎么做?就是统计的结果要实时更新,热数据。 刚接触flink 1.9 求问flink run脚本中怎么没有相关提交到yarn的命令了 请教一下,flink里怎么实现batch sink的操作而不导致数据丢失

问问小秘 2019-12-02 03:19:17 0 浏览量 回答数 0

问题

ES 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?【Java问答学堂】28期

剑曼红尘 2020-05-28 09:45:28 15 浏览量 回答数 1

问题

我也想写点什么

猥琐屯公爵 2019-12-01 21:55:06 6158 浏览量 回答数 2

问题

MaxCompute百问集锦(持续更新20171011)

隐林 2019-12-01 20:19:23 38430 浏览量 回答数 18

回答

分布式事务的解决方案有如下几种: 全局消息基于可靠消息服务的分布式事务TCC最大努力通知方案1:全局事务(DTP模型)全局事务基于DTP模型实现。DTP是由X/Open组织提出的一种分布式事务模型——X/Open Distributed Transaction Processing Reference Model。它规定了要实现分布式事务,需要三种角色: AP:Application 应用系统 它就是我们开发的业务系统,在我们开发的过程中,可以使用资源管理器提供的事务接口来实现分布式事务。 TM:Transaction Manager 事务管理器 分布式事务的实现由事务管理器来完成,它会提供分布式事务的操作接口供我们的业务系统调用。这些接口称为TX接口。事务管理器还管理着所有的资源管理器,通过它们提供的XA接口来同一调度这些资源管理器,以实现分布式事务。DTP只是一套实现分布式事务的规范,并没有定义具体如何实现分布式事务,TM可以采用2PC、3PC、Paxos等协议实现分布式事务。RM:Resource Manager 资源管理器 能够提供数据服务的对象都可以是资源管理器,比如:数据库、消息中间件、缓存等。大部分场景下,数据库即为分布式事务中的资源管理器。资源管理器能够提供单数据库的事务能力,它们通过XA接口,将本数据库的提交、回滚等能力提供给事务管理器调用,以帮助事务管理器实现分布式的事务管理。XA是DTP模型定义的接口,用于向事务管理器提供该资源管理器(该数据库)的提交、回滚等能力。DTP只是一套实现分布式事务的规范,RM具体的实现是由数据库厂商来完成的。有没有基于DTP模型的分布式事务中间件?DTP模型有啥优缺点?方案2:基于可靠消息服务的分布式事务这种实现分布式事务的方式需要通过消息中间件来实现。假设有A和B两个系统,分别可以处理任务A和任务B。此时系统A中存在一个业务流程,需要将任务A和任务B在同一个事务中处理。下面来介绍基于消息中间件来实现这种分布式事务。 title 在系统A处理任务A前,首先向消息中间件发送一条消息消息中间件收到后将该条消息持久化,但并不投递。此时下游系统B仍然不知道该条消息的存在。消息中间件持久化成功后,便向系统A返回一个确认应答;系统A收到确认应答后,则可以开始处理任务A;任务A处理完成后,向消息中间件发送Commit请求。该请求发送完成后,对系统A而言,该事务的处理过程就结束了,此时它可以处理别的任务了。 但commit消息可能会在传输途中丢失,从而消息中间件并不会向系统B投递这条消息,从而系统就会出现不一致性。这个问题由消息中间件的事务回查机制完成,下文会介绍。消息中间件收到Commit指令后,便向系统B投递该消息,从而触发任务B的执行;当任务B执行完成后,系统B向消息中间件返回一个确认应答,告诉消息中间件该消息已经成功消费,此时,这个分布式事务完成。上述过程可以得出如下几个结论: 消息中间件扮演者分布式事务协调者的角色。 系统A完成任务A后,到任务B执行完成之间,会存在一定的时间差。在这个时间差内,整个系统处于数据不一致的状态,但这短暂的不一致性是可以接受的,因为经过短暂的时间后,系统又可以保持数据一致性,满足BASE理论。 上述过程中,如果任务A处理失败,那么需要进入回滚流程,如下图所示: title 若系统A在处理任务A时失败,那么就会向消息中间件发送Rollback请求。和发送Commit请求一样,系统A发完之后便可以认为回滚已经完成,它便可以去做其他的事情。消息中间件收到回滚请求后,直接将该消息丢弃,而不投递给系统B,从而不会触发系统B的任务B。此时系统又处于一致性状态,因为任务A和任务B都没有执行。 上面所介绍的Commit和Rollback都属于理想情况,但在实际系统中,Commit和Rollback指令都有可能在传输途中丢失。那么当出现这种情况的时候,消息中间件是如何保证数据一致性呢?——答案就是超时询问机制。 title 系统A除了实现正常的业务流程外,还需提供一个事务询问的接口,供消息中间件调用。当消息中间件收到一条事务型消息后便开始计时,如果到了超时时间也没收到系统A发来的Commit或Rollback指令的话,就会主动调用系统A提供的事务询问接口询问该系统目前的状态。该接口会返回三种结果: 提交 若获得的状态是“提交”,则将该消息投递给系统B。回滚 若获得的状态是“回滚”,则直接将条消息丢弃。处理中 若获得的状态是“处理中”,则继续等待。消息中间件的超时询问机制能够防止上游系统因在传输过程中丢失Commit/Rollback指令而导致的系统不一致情况,而且能降低上游系统的阻塞时间,上游系统只要发出Commit/Rollback指令后便可以处理其他任务,无需等待确认应答。而Commit/Rollback指令丢失的情况通过超时询问机制来弥补,这样大大降低上游系统的阻塞时间,提升系统的并发度。 下面来说一说消息投递过程的可靠性保证。 当上游系统执行完任务并向消息中间件提交了Commit指令后,便可以处理其他任务了,此时它可以认为事务已经完成,接下来消息中间件一定会保证消息被下游系统成功消费掉!那么这是怎么做到的呢?这由消息中间件的投递流程来保证。 消息中间件向下游系统投递完消息后便进入阻塞等待状态,下游系统便立即进行任务的处理,任务处理完成后便向消息中间件返回应答。消息中间件收到确认应答后便认为该事务处理完毕! 如果消息在投递过程中丢失,或消息的确认应答在返回途中丢失,那么消息中间件在等待确认应答超时之后就会重新投递,直到下游消费者返回消费成功响应为止。当然,一般消息中间件可以设置消息重试的次数和时间间隔,比如:当第一次投递失败后,每隔五分钟重试一次,一共重试3次。如果重试3次之后仍然投递失败,那么这条消息就需要人工干预。 title title 有的同学可能要问:消息投递失败后为什么不回滚消息,而是不断尝试重新投递? 这就涉及到整套分布式事务系统的实现成本问题。 我们知道,当系统A将向消息中间件发送Commit指令后,它便去做别的事情了。如果此时消息投递失败,需要回滚的话,就需要让系统A事先提供回滚接口,这无疑增加了额外的开发成本,业务系统的复杂度也将提高。对于一个业务系统的设计目标是,在保证性能的前提下,最大限度地降低系统复杂度,从而能够降低系统的运维成本。 不知大家是否发现,上游系统A向消息中间件提交Commit/Rollback消息采用的是异步方式,也就是当上游系统提交完消息后便可以去做别的事情,接下来提交、回滚就完全交给消息中间件来完成,并且完全信任消息中间件,认为它一定能正确地完成事务的提交或回滚。然而,消息中间件向下游系统投递消息的过程是同步的。也就是消息中间件将消息投递给下游系统后,它会阻塞等待,等下游系统成功处理完任务返回确认应答后才取消阻塞等待。为什么这两者在设计上是不一致的呢? 首先,上游系统和消息中间件之间采用异步通信是为了提高系统并发度。业务系统直接和用户打交道,用户体验尤为重要,因此这种异步通信方式能够极大程度地降低用户等待时间。此外,异步通信相对于同步通信而言,没有了长时间的阻塞等待,因此系统的并发性也大大增加。但异步通信可能会引起Commit/Rollback指令丢失的问题,这就由消息中间件的超时询问机制来弥补。 那么,消息中间件和下游系统之间为什么要采用同步通信呢? 异步能提升系统性能,但随之会增加系统复杂度;而同步虽然降低系统并发度,但实现成本较低。因此,在对并发度要求不是很高的情况下,或者服务器资源较为充裕的情况下,我们可以选择同步来降低系统的复杂度。 我们知道,消息中间件是一个独立于业务系统的第三方中间件,它不和任何业务系统产生直接的耦合,它也不和用户产生直接的关联,它一般部署在独立的服务器集群上,具有良好的可扩展性,所以不必太过于担心它的性能,如果处理速度无法满足我们的要求,可以增加机器来解决。而且,即使消息中间件处理速度有一定的延迟那也是可以接受的,因为前面所介绍的BASE理论就告诉我们了,我们追求的是最终一致性,而非实时一致性,因此消息中间件产生的时延导致事务短暂的不一致是可以接受的。 方案3:最大努力通知(定期校对)最大努力通知也被称为定期校对,其实在方案二中已经包含,这里再单独介绍,主要是为了知识体系的完整性。这种方案也需要消息中间件的参与,其过程如下: title 上游系统在完成任务后,向消息中间件同步地发送一条消息,确保消息中间件成功持久化这条消息,然后上游系统可以去做别的事情了;消息中间件收到消息后负责将该消息同步投递给相应的下游系统,并触发下游系统的任务执行;当下游系统处理成功后,向消息中间件反馈确认应答,消息中间件便可以将该条消息删除,从而该事务完成。上面是一个理想化的过程,但在实际场景中,往往会出现如下几种意外情况: 消息中间件向下游系统投递消息失败上游系统向消息中间件发送消息失败对于第一种情况,消息中间件具有重试机制,我们可以在消息中间件中设置消息的重试次数和重试时间间隔,对于网络不稳定导致的消息投递失败的情况,往往重试几次后消息便可以成功投递,如果超过了重试的上限仍然投递失败,那么消息中间件不再投递该消息,而是记录在失败消息表中,消息中间件需要提供失败消息的查询接口,下游系统会定期查询失败消息,并将其消费,这就是所谓的“定期校对”。 如果重复投递和定期校对都不能解决问题,往往是因为下游系统出现了严重的错误,此时就需要人工干预。 对于第二种情况,需要在上游系统中建立消息重发机制。可以在上游系统建立一张本地消息表,并将 任务处理过程 和 向本地消息表中插入消息 这两个步骤放在一个本地事务中完成。如果向本地消息表插入消息失败,那么就会触发回滚,之前的任务处理结果就会被取消。如果这量步都执行成功,那么该本地事务就完成了。接下来会有一个专门的消息发送者不断地发送本地消息表中的消息,如果发送失败它会返回重试。当然,也要给消息发送者设置重试的上限,一般而言,达到重试上限仍然发送失败,那就意味着消息中间件出现严重的问题,此时也只有人工干预才能解决问题。 对于不支持事务型消息的消息中间件,如果要实现分布式事务的话,就可以采用这种方式。它能够通过重试机制+定期校对实现分布式事务,但相比于第二种方案,它达到数据一致性的周期较长,而且还需要在上游系统中实现消息重试发布机制,以确保消息成功发布给消息中间件,这无疑增加了业务系统的开发成本,使得业务系统不够纯粹,并且这些额外的业务逻辑无疑会占用业务系统的硬件资源,从而影响性能。 因此,尽量选择支持事务型消息的消息中间件来实现分布式事务,如RocketMQ。 方案4:TCC(两阶段型、补偿型)TCC即为Try Confirm Cancel,它属于补偿型分布式事务。顾名思义,TCC实现分布式事务一共有三个步骤: Try:尝试待执行的业务 这个过程并未执行业务,只是完成所有业务的一致性检查,并预留好执行所需的全部资源Confirm:执行业务 这个过程真正开始执行业务,由于Try阶段已经完成了一致性检查,因此本过程直接执行,而不做任何检查。并且在执行的过程中,会使用到Try阶段预留的业务资源。Cancel:取消执行的业务 若业务执行失败,则进入Cancel阶段,它会释放所有占用的业务资源,并回滚Confirm阶段执行的操作。下面以一个转账的例子来解释下TCC实现分布式事务的过程。 假设用户A用他的账户余额给用户B发一个100元的红包,并且余额系统和红包系统是两个独立的系统。 Try 创建一条转账流水,并将流水的状态设为交易中将用户A的账户中扣除100元(预留业务资源)Try成功之后,便进入Confirm阶段Try过程发生任何异常,均进入Cancel阶段Confirm 向B用户的红包账户中增加100元将流水的状态设为交易已完成Confirm过程发生任何异常,均进入Cancel阶段Confirm过程执行成功,则该事务结束Cancel 将用户A的账户增加100元将流水的状态设为交易失败在传统事务机制中,业务逻辑的执行和事务的处理,是在不同的阶段由不同的部件来完成的:业务逻辑部分访问资源实现数据存储,其处理是由业务系统负责;事务处理部分通过协调资源管理器以实现事务管理,其处理由事务管理器来负责。二者没有太多交互的地方,所以,传统事务管理器的事务处理逻辑,仅需要着眼于事务完成(commit/rollback)阶段,而不必关注业务执行阶段。 TCC全局事务必须基于RM本地事务来实现全局事务TCC服务是由Try/Confirm/Cancel业务构成的, 其Try/Confirm/Cancel业务在执行时,会访问资源管理器(Resource Manager,下文简称RM)来存取数据。这些存取操作,必须要参与RM本地事务,以使其更改的数据要么都commit,要么都rollback。 这一点不难理解,考虑一下如下场景: title 假设图中的服务B没有基于RM本地事务(以RDBS为例,可通过设置auto-commit为true来模拟),那么一旦[B:Try]操作中途执行失败,TCC事务框架后续决定回滚全局事务时,该[B:Cancel]则需要判断[B:Try]中哪些操作已经写到DB、哪些操作还没有写到DB:假设[B:Try]业务有5个写库操作,[B:Cancel]业务则需要逐个判断这5个操作是否生效,并将生效的操作执行反向操作。 不幸的是,由于[B:Cancel]业务也有n(0<=n<=5)个反向的写库操作,此时一旦[B:Cancel]也中途出错,则后续的[B:Cancel]执行任务更加繁重。因为,相比第一次[B:Cancel]操作,后续的[B:Cancel]操作还需要判断先前的[B:Cancel]操作的n(0<=n<=5)个写库中哪几个已经执行、哪几个还没有执行,这就涉及到了幂等性问题。而对幂等性的保障,又很可能还需要涉及额外的写库操作,该写库操作又会因为没有RM本地事务的支持而存在类似问题。。。可想而知,如果不基于RM本地事务,TCC事务框架是无法有效的管理TCC全局事务的。 反之,基于RM本地事务的TCC事务,这种情况则会很容易处理:[B:Try]操作中途执行失败,TCC事务框架将其参与RM本地事务直接rollback即可。后续TCC事务框架决定回滚全局事务时,在知道“[B:Try]操作涉及的RM本地事务已经rollback”的情况下,根本无需执行[B:Cancel]操作。 换句话说,基于RM本地事务实现TCC事务框架时,一个TCC型服务的cancel业务要么执行,要么不执行,不需要考虑部分执行的情况。 TCC事务框架应该提供Confirm/Cancel服务的幂等性保障一般认为,服务的幂等性,是指针对同一个服务的多次(n>1)请求和对它的单次(n=1)请求,二者具有相同的副作用。 在TCC事务模型中,Confirm/Cancel业务可能会被重复调用,其原因很多。比如,全局事务在提交/回滚时会调用各TCC服务的Confirm/Cancel业务逻辑。执行这些Confirm/Cancel业务时,可能会出现如网络中断的故障而使得全局事务不能完成。因此,故障恢复机制后续仍然会重新提交/回滚这些未完成的全局事务,这样就会再次调用参与该全局事务的各TCC服务的Confirm/Cancel业务逻辑。 既然Confirm/Cancel业务可能会被多次调用,就需要保障其幂等性。 那么,应该由TCC事务框架来提供幂等性保障?还是应该由业务系统自行来保障幂等性呢? 个人认为,应该是由TCC事务框架来提供幂等性保障。如果仅仅只是极个别服务存在这个问题的话,那么由业务系统来负责也是可以的;然而,这是一类公共问题,毫无疑问,所有TCC服务的Confirm/Cancel业务存在幂等性问题。TCC服务的公共问题应该由TCC事务框架来解决;而且,考虑一下由业务系统来负责幂等性需要考虑的问题,就会发现,这无疑增大了业务系统的复杂度。

1210119897362579 2019-12-02 00:14:25 0 浏览量 回答数 0

问题

SaaS模式云数据仓库MaxCompute 百问百答合集(持续更新20200724)

亢海鹏 2020-05-29 15:10:00 9080 浏览量 回答数 2

问题

【精品问答】python技术1000问(2)

问问小秘 2019-12-01 22:03:02 68 浏览量 回答数 0

回答

在开始谈我对架构本质的理解之前,先谈谈对今天技术沙龙主题的个人见解,千万级规模的网站感觉数量级是非常大的,对这个数量级我们战略上 要重 视 它 , 战术上又 要 藐 视 它。先举个例子感受一下千万级到底是什么数量级?现在很流行的优步(Uber),从媒体公布的信息看,它每天接单量平均在百万左右, 假如每天有10个小时的服务时间,平均QPS只有30左右。对于一个后台服务器,单机的平均QPS可以到达800-1000,单独看写的业务量很简单 。为什么我们又不能说轻视它?第一,我们看它的数据存储,每天一百万的话,一年数据量的规模是多少?其次,刚才说的订单量,每一个订单要推送给附近的司机、司机要并发抢单,后面业务场景的访问量往往是前者的上百倍,轻松就超过上亿级别了。 今天我想从架构的本质谈起之后,希望大家理解在做一些建构设计的时候,它的出发点以及它解决的问题是什么。 架构,刚开始的解释是我从知乎上看到的。什么是架构?有人讲, 说架构并不是一 个很 悬 乎的 东西 , 实际 上就是一个架子 , 放一些 业务 和算法,跟我们的生活中的晾衣架很像。更抽象一点,说架构其 实 是 对 我 们 重复性业务 的抽象和我 们 未来 业务 拓展的前瞻,强调过去的经验和你对整个行业的预见。 我们要想做一个架构的话需要哪些能力?我觉得最重要的是架构师一个最重要的能力就是你要有 战 略分解能力。这个怎么来看呢: 第一,你必须要有抽象的能力,抽象的能力最基本就是去重,去重在整个架构中体现在方方面面,从定义一个函数,到定义一个类,到提供的一个服务,以及模板,背后都是要去重提高可复用率。 第二, 分类能力。做软件需要做对象的解耦,要定义对象的属性和方法,做分布式系统的时候要做服务的拆分和模块化,要定义服务的接口和规范。 第三, 算法(性能),它的价值体现在提升系统的性能,所有性能的提升,最终都会落到CPU,内存,IO和网络这4大块上。 这一页PPT举了一些例子来更深入的理解常见技术背后的架构理念。 第一个例子,在分布式系统我们会做 MySQL分 库 分表,我们要从不同的库和表中读取数据,这样的抽象最直观就是使用模板,因为绝大多数SQL语义是相同的,除了路由到哪个库哪个表,如果不使用Proxy中间件,模板就是性价比最高的方法。 第二看一下加速网络的CDN,它是做速度方面的性能提升,刚才我们也提到从CPU、内存、IO、网络四个方面来考虑,CDN本质上一个是做网络智能调度优化,另一个是多级缓存优化。 第三个看一下服务化,刚才已经提到了,各个大网站转型过程中一定会做服务化,其实它就是做抽象和做服务的拆分。第四个看一下消息队列,本质上还是做分类,只不过不是两个边际清晰的类,而是把两个边际不清晰的子系统通过队列解构并且异步化。新浪微博整体架构是什么样的 接下我们看一下微博整体架构,到一定量级的系统整个架构都会变成三层,客户端包括WEB、安卓和IOS,这里就不说了。接着还都会有一个接口层, 有三个主要作用: 第一个作用,要做 安全隔离,因为前端节点都是直接和用户交互,需要防范各种恶意攻击; 第二个还充当着一个 流量控制的作用,大家知道,在2014年春节的时候,微信红包,每分钟8亿多次的请求,其实真正到它后台的请求量,只有十万左右的数量级(这里的数据可能不准),剩余的流量在接口层就被挡住了; 第三,我们看对 PC 端和移 动 端的需求不一样的,所以我们可以进行拆分。接口层之后是后台,可以看到微博后台有三大块: 一个是 平台服 务, 第二, 搜索, 第三, 大数据。到了后台的各种服务其实都是处理的数据。 像平台的业务部门,做的就是 数据存储和读 取,对搜索来说做的是 数据的 检 索,对大数据来说是做的数据的 挖掘。微博其实和淘宝是很类似 微博其实和淘宝是很类似的。一般来说,第一代架构,基本上能支撑到用户到 百万 级别,到第二代架构基本能支撑到 千万 级别都没什么问题,当业务规模到 亿级别时,需要第三代的架构。 从 LAMP 的架构到面向服 务 的架构,有几个地方是非常难的,首先不可能在第一代基础上通过简单的修修补补满足用户量快速增长的,同时线上业务又不能停, 这是我们常说的 在 飞 机上 换 引擎的 问题。前两天我有一个朋友问我,说他在内部推行服务化的时候,把一个模块服务化做完了,其他部门就是不接。我建议在做服务化的时候,首先更多是偏向业务的梳理,同时要找准一个很好的切入点,既有架构和服务化上的提升,业务方也要有收益,比如提升性能或者降低维护成本同时升级过程要平滑,建议开始从原子化服务切入,比如基础的用户服务, 基础的短消息服务,基础的推送服务。 第二,就是可 以做无状 态 服 务,后面会详细讲,还有数据量大了后需要做数据Sharding,后面会将。 第三代 架构 要解决的 问题,就是用户量和业务趋于稳步增加(相对爆发期的指数级增长),更多考虑技术框架的稳定性, 提升系统整体的性能,降低成本,还有对整个系统监控的完善和升级。 大型网站的系统架构是如何演变的 我们通过通过数据看一下它的挑战,PV是在10亿级别,QPS在百万,数据量在千亿级别。我们可用性,就是SLA要求4个9,接口响应最多不能超过150毫秒,线上所有的故障必须得在5分钟内解决完。如果说5分钟没处理呢?那会影响你年终的绩效考核。2015年微博DAU已经过亿。我们系统有上百个微服务,每周会有两次的常规上线和不限次数的紧急上线。我们的挑战都一样,就是数据量,bigger and bigger,用户体验是faster and faster,业务是more and more。互联网业务更多是产品体验驱动, 技 术 在 产 品 体验上最有效的贡献 , 就是你的性能 越来越好 。 每次降低加载一个页面的时间,都可以间接的降低这个页面上用户的流失率。微博的技术挑战和正交分解法解析架构 下面看一下 第三代的 架构 图 以及 我 们 怎么用正交分解法 阐 述。 我们可以看到我们从两个维度,横轴和纵轴可以看到。 一个 维 度 是 水平的 分层 拆分,第二从垂直的维度会做拆分。水平的维度从接口层、到服务层到数据存储层。垂直怎么拆分,会用业务架构、技术架构、监控平台、服务治理等等来处理。我相信到第二代的时候很多架构已经有了业务架构和技术架构的拆分。我们看一下, 接口层有feed、用户关系、通讯接口;服务层,SOA里有基层服务、原子服务和组合服务,在微博我们只有原子服务和组合服务。原子服务不依赖于任何其他服务,组合服务由几个原子服务和自己的业务逻辑构建而成 ,资源层负责海量数据的存储(后面例子会详细讲)。技 术框架解决 独立于 业务 的海量高并发场景下的技术难题,由众多的技术组件共同构建而成 。在接口层,微博使用JERSY框架,帮助你做参数的解析,参数的验证,序列化和反序列化;资源层,主要是缓存、DB相关的各类组件,比如Cache组件和对象库组件。监 控平台和服 务 治理 , 完成系统服务的像素级监控,对分布式系统做提前诊断、预警以及治理。包含了SLA规则的制定、服务监控、服务调用链监控、流量监控、错误异常监控、线上灰度发布上线系统、线上扩容缩容调度系统等。 下面我们讲一下常见的设计原则。 第一个,首先是系统架构三个利器: 一个, 我 们 RPC 服 务组 件 (这里不讲了), 第二个,我们 消息中 间 件 。消息中间件起的作用:可以把两个模块之间的交互异步化,其次可以把不均匀请求流量输出为匀速的输出流量,所以说消息中间件 异步化 解耦 和流量削峰的利器。 第三个是配置管理,它是 代码级灰度发布以及 保障系统降级的利器。 第二个 , 无状态 , 接口 层 最重要的就是无状 态。我们在电商网站购物,在这个过程中很多情况下是有状态的,比如我浏览了哪些商品,为什么大家又常说接口层是无状态的,其实我们把状态从接口层剥离到了数据层。像用户在电商网站购物,选了几件商品,到了哪一步,接口无状态后,状态要么放在缓存中,要么放在数据库中, 其 实 它并不是没有状 态 , 只是在 这 个 过 程中我 们 要把一些有状 态 的 东 西抽离出来 到了数据层。 第三个, 数据 层 比服 务层 更需要 设计,这是一条非常重要的经验。对于服务层来说,可以拿PHP写,明天你可以拿JAVA来写,但是如果你的数据结构开始设计不合理,将来数据结构的改变会花费你数倍的代价,老的数据格式向新的数据格式迁移会让你痛不欲生,既有工作量上的,又有数据迁移跨越的时间周期,有一些甚至需要半年以上。 第四,物理结构与逻辑结构的映射,上一张图看到两个维度切成十二个区间,每个区间代表一个技术领域,这个可以看做我们的逻辑结构。另外,不论后台还是应用层的开发团队,一般都会分几个垂直的业务组加上一个基础技术架构组,这就是从物理组织架构到逻辑的技术架构的完美的映射,精细化团队分工,有利于提高沟通协作的效率 。 第五, www .sanhao.com 的访问过程,我们这个架构图里没有涉及到的,举个例子,比如当你在浏览器输入www.sanhao网址的时候,这个请求在接口层之前发生了什么?首先会查看你本机DNS以及DNS服务,查找域名对应的IP地址,然后发送HTTP请求过去。这个请求首先会到前端的VIP地址(公网服务IP地址),VIP之后还要经过负载均衡器(Nginx服务器),之后才到你的应用接口层。在接口层之前发生了这么多事,可能有用户报一个问题的时候,你通过在接口层查日志根本发现不了问题,原因就是问题可能发生在到达接口层之前了。 第六,我们说分布式系统,它最终的瓶颈会落在哪里呢?前端时间有一个网友跟我讨论的时候,说他们的系统遇到了一个瓶颈, 查遍了CPU,内存,网络,存储,都没有问题。我说你再查一遍,因为最终你不论用上千台服务器还是上万台服务器,最终系统出瓶颈的一定会落在某一台机(可能是叶子节点也可能是核心的节点),一定落在CPU、内存、存储和网络上,最后查出来问题出在一台服务器的网卡带宽上。微博多级双机房缓存架构 接下来我们看一下微博的Feed多级缓存。我们做业务的时候,经常很少做业务分析,技术大会上的分享又都偏向技术架构。其实大家更多的日常工作是需要花费更多时间在业务优化上。这张图是统计微博的信息流前几页的访问比例,像前三页占了97%,在做缓存设计的时候,我们最多只存最近的M条数据。 这里强调的就是做系统设计 要基于用 户 的 场 景 , 越细致越好 。举了一个例子,大家都会用电商,电商在双十一会做全国范围内的活动,他们做设计的时候也会考虑场景的,一个就是购物车,我曾经跟相关开发讨论过,购物车是在双十一之前用户的访问量非常大,就是不停地往里加商品。在真正到双十一那天他不会往购物车加东西了,但是他会频繁的浏览购物车。针对这个场景,活动之前重点设计优化购物车的写场景, 活动开始后优化购物车的读场景。 你看到的微博是由哪些部分聚合而成的呢?最右边的是Feed,就是微博所有关注的人,他们的微博所组成的。微博我们会按照时间顺序把所有关注人的顺序做一个排序。随着业务的发展,除了跟时间序相关的微博还有非时间序的微博,就是会有广告的要求,增加一些广告,还有粉丝头条,就是拿钱买的,热门微博,都会插在其中。分发控制,就是说和一些推荐相关的,我推荐一些相关的好友的微博,我推荐一些你可能没有读过的微博,我推荐一些其他类型的微博。 当然对非时序的微博和分发控制微博,实际会起多个并行的程序来读取,最后同步做统一的聚合。这里稍微分享一下, 从SNS社交领域来看,国内现在做的比较好的三个信息流: 微博 是 基于弱关系的媒体信息流 ; 朋友圈是基于 强 关系的信息流 ; 另外一个做的比 较 好的就是今日 头 条 , 它并不是基于关系来构建信息流 , 而是基于 兴趣和相关性的个性化推荐 信息流 。 信息流的聚合,体现在很多很多的产品之中,除了SNS,电商里也有信息流的聚合的影子。比如搜索一个商品后出来的列表页,它的信息流基本由几部分组成:第一,打广告的;第二个,做一些推荐,热门的商品,其次,才是关键字相关的搜索结果。 信息流 开始的时候 很 简单 , 但是到后期会 发现 , 你的 这 个流 如何做控制分发 , 非常复杂, 微博在最近一两年一直在做 这样 的工作。刚才我们是从业务上分析,那么技术上怎么解决高并发,高性能的问题?微博访问量很大的时候,底层存储是用MySQL数据库,当然也会有其他的。对于查询请求量大的时候,大家知道一定有缓存,可以复用可重用的计算结果。可以看到,发一条微博,我有很多粉丝,他们都会来看我发的内容,所以 微博是最适合使用 缓 存 的系统,微博的读写比例基本在几十比一。微博使用了 双 层缓 存,上面是L1,每个L1上都是一组(包含4-6台机器),左边的框相当于一个机房,右边又是一个机房。在这个系统中L1缓存所起的作用是什么? 首先,L1 缓 存增加整个系 统 的 QPS, 其次 以低成本灵活扩容的方式 增加 系统 的 带宽 。想象一个极端场景,只有一篇博文,但是它的访问量无限增长,其实我们不需要影响L2缓存,因为它的内容存储的量小,但它就是访问量大。这种场景下,你就需要使用L1来扩容提升QPS和带宽瓶颈。另外一个场景,就是L2级缓存发生作用,比如我有一千万个用户,去访问的是一百万个用户的微博 ,这个时候,他不只是说你的吞吐量和访问带宽,就是你要缓存的博文的内容也很多了,这个时候你要考虑缓存的容量, 第二 级缓 存更多的是从容量上来 规划,保证请求以较小的比例 穿透到 后端的 数据 库 中 ,根据你的用户模型你可以估出来,到底有百分之多少的请求不能穿透到DB, 评估这个容量之后,才能更好的评估DB需要多少库,需要承担多大的访问的压力。另外,我们看双机房的话,左边一个,右边一个。 两个机房是互 为 主 备 , 或者互 为热备 。如果两个用户在不同地域,他们访问两个不同机房的时候,假设用户从IDC1过来,因为就近原理,他会访问L1,没有的话才会跑到Master,当在IDC1没找到的时候才会跑到IDC2来找。同时有用户从IDC2访问,也会有请求从L1和Master返回或者到IDC1去查找。 IDC1 和 IDC2 ,两个机房都有全量的用户数据,同时在线提供服务,但是缓存查询又遵循最近访问原理。还有哪些多级缓存的例子呢?CDN是典型的多级缓存。CDN在国内各个地区做了很多节点,比如在杭州市部署一个节点时,在机房里肯定不止一台机器,那么对于一个地区来说,只有几台服务器到源站回源,其他节点都到这几台服务器回源即可,这么看CDN至少也有两级。Local Cache+ 分布式 缓 存,这也是常见的一种策略。有一种场景,分布式缓存并不适用, 比如 单 点 资 源 的爆发性峰值流量,这个时候使用Local Cache + 分布式缓存,Local Cache 在 应用 服 务 器 上用很小的 内存资源 挡住少量的 极端峰值流量,长尾的流量仍然访问分布式缓存,这样的Hybrid缓存架构通过复用众多的应用服务器节点,降低了系统的整体成本。 我们来看一下 Feed 的存 储 架构,微博的博文主要存在MySQL中。首先来看内容表,这个比较简单,每条内容一个索引,每天建一张表,其次看索引表,一共建了两级索引。首先想象一下用户场景,大部分用户刷微博的时候,看的是他关注所有人的微博,然后按时间来排序。仔细分析发现在这个场景下, 跟一个用户的自己的相关性很小了。所以在一级索引的时候会先根据关注的用户,取他们的前条微博ID,然后聚合排序。我们在做哈希(分库分表)的时候,同时考虑了按照UID哈希和按照时间维度。很业务和时间相关性很高的,今天的热点新闻,明天就没热度了,数据的冷热非常明显,这种场景就需要按照时间维度做分表,首先冷热数据做了分离(可以对冷热数据采用不同的存储方案来降低成本),其次, 很容止控制我数据库表的爆炸。像微博如果只按照用户维度区分,那么这个用户所有数据都在一张表里,这张表就是无限增长的,时间长了查询会越来越慢。二级索引,是我们里面一个比较特殊的场景,就是我要快速找到这个人所要发布的某一时段的微博时,通过二级索引快速定位。 分布式服务追踪系统 分布式追踪服务系统,当系统到千万级以后的时候,越来越庞杂,所解决的问题更偏向稳定性,性能和监控。刚才说用户只要有一个请求过来,你可以依赖你的服务RPC1、RPC2,你会发现RPC2又依赖RPC3、RPC4。分布式服务的时候一个痛点,就是说一个请求从用户过来之后,在后台不同的机器之间不停的调用并返回。 当你发现一个问题的时候,这些日志落在不同的机器上,你也不知道问题到底出在哪儿,各个服务之间互相隔离,互相之间没有建立关联。所以导致排查问题基本没有任何手段,就是出了问题没法儿解决。 我们要解决的问题,我们刚才说日志互相隔离,我们就要把它建立联系。建立联系我们就有一个请求ID,然后结合RPC框架, 服务治理功能。假设请求从客户端过来,其中包含一个ID 101,到服务A时仍然带有ID 101,然后调用RPC1的时候也会标识这是101 ,所以需要 一个唯一的 请求 ID 标识 递归迭代的传递到每一个 相关 节点。第二个,你做的时候,你不能说每个地方都加,对业务系统来说需要一个框架来完成这个工作, 这 个框架要 对业务 系 统 是最低侵入原 则 , 用 JAVA 的 话 就可以用 AOP,要做到零侵入的原则,就是对所有相关的中间件打点,从接口层组件(HTTP Client、HTTP Server)至到服务层组件(RPC Client、RPC Server),还有数据访问中间件的,这样业务系统只需要少量的配置信息就可以实现全链路监控 。为什么要用日志?服务化以后,每个服务可以用不同的开发语言, 考虑多种开发语言的兼容性 , 内部定 义标 准化的日志 是唯一且有效的办法。最后,如何构建基于GPS导航的路况监控?我们刚才讲分布式服务追踪。分布式服务追踪能解决的问题, 如果 单一用 户发现问题 后 , 可以通 过请 求 ID 快速找到 发 生 问题 的 节 点在什么,但是并没有解决如何发现问题。我们看现实中比较容易理解的道路监控,每辆车有GPS定位,我想看北京哪儿拥堵的时候,怎么做? 第一个 , 你肯定要知道每个 车 在什么位置,它走到哪儿了。其实可以说每个车上只要有一个标识,加上每一次流动的信息,就可以看到每个车流的位置和方向。 其次如何做 监 控和 报 警,我们怎么能了解道路的流量状况和负载,并及时报警。我们要定义这条街道多宽多高,单位时间可以通行多少辆车,这就是道路的容量。有了道路容量,再有道路的实时流量,我们就可以基于实习路况做预警? 对应于 分布式系 统 的话如何构建? 第一 , 你要 定义 每个服 务节 点它的 SLA A 是多少 ?SLA可以从系统的CPU占用率、内存占用率、磁盘占用率、QPS请求数等来定义,相当于定义系统的容量。 第二个 , 统计 线 上 动态 的流量,你要知道服务的平均QPS、最低QPS和最大QPS,有了流量和容量,就可以对系统做全面的监控和报警。 刚才讲的是理论,实际情况肯定比这个复杂。微博在春节的时候做许多活动,必须保障系统稳定,理论上你只要定义容量和流量就可以。但实际远远不行,为什么?有技术的因素,有人为的因素,因为不同的开发定义的流量和容量指标有主观性,很难全局量化标准,所以真正流量来了以后,你预先评估的系统瓶颈往往不正确。实际中我们在春节前主要采取了三个措施:第一,最简单的就是有降 级 的 预 案,流量超过系统容量后,先把哪些功能砍掉,需要有明确的优先级 。第二个, 线上全链路压测,就是把现在的流量放大到我们平常流量的五倍甚至十倍(比如下线一半的服务器,缩容而不是扩容),看看系统瓶颈最先发生在哪里。我们之前有一些例子,推测系统数据库会先出现瓶颈,但是实测发现是前端的程序先遇到瓶颈。第三,搭建在线 Docker 集群 , 所有业务共享备用的 Docker集群资源,这样可以极大的避免每个业务都预留资源,但是实际上流量没有增长造成的浪费。 总结 接下来说的是如何不停的学习和提升,这里以Java语言为例,首先, 一定要 理解 JAVA;第二步,JAVA完了以后,一定要 理 解 JVM;其次,还要 理解 操作系统;再次还是要了解一下 Design Pattern,这将告诉你怎么把过去的经验抽象沉淀供将来借鉴;还要学习 TCP/IP、 分布式系 统、数据结构和算法。

hiekay 2019-12-02 01:39:25 0 浏览量 回答数 0

回答

如何掌握牢靠Go语言的容器? 容器相对来说更偏重细节一些,如果想掌握的更牢靠的话呢,还是要多看一下代码,重点给大家几个提示 Go语言的并发初步有哪两个特别重要的特点? **GO语言的协程并发操作或者说协程的资源池,其调度策略有两个: ** 1、没有优先级,没有API能设置优先级,正是因为它一切都是靠Go语言自身的一个调度器来听调度,才能保证它的高效率,这点非常重要。 2、调度的策略是可抢占的,假如说一个任务它长时间的占用CPU,那么它是有可能被购入天的这个调度器给其抢占过来,让其其的任务来做运行,这是两个最重要的特点。 GO语言调度的单元goroutine的应用场景是什么? 使用JAVA或者C编写网络程序时,一个线程来处理一个http请求, 但是对于资源的利用率不高。而Go语言实现了轻量级线程的机制,GO语言在底层封装了所有的系统调用,自己实现了一个调度器,这种设计在操作系统的代码中非常多见。比如现代的操作系统基本都会封装一个软件的Timer,同时可以提供上万个软Timer同时工作,而这只是基于数量很少的硬件timer实现的,而GO语言中的并发也是如此,他是基于线程的调度池,这种调度的单元在Go语言中被称为goroutine。 GO语言与其它并发模型最大的区别是什么? 宏观GO语言与其它并发模型最大的不同,就是其推荐使用通信的这种方式来替代共享内存。当资源需要在goroutine之间进行共享的时候,实际上就是这个资源,或者说这个信息通过通道在goroutine之间进行通信的过程。因为这个锁,一般来说都是用在这个共享内存当中的,因为如果说大家阅读GO语言的相关代码,就可以看到这个channel,它实际上是基于锁来保证并发安全。 然而,这也不代表GO语言当中只能使用channel来进行一些操作,其也具备锁这方面的知识。因为现实当中,这个锁还是有一定它现实的意义和现实的要求,因为这个锁它最关键的一个意义就是它能保证资源能在并发的操作当中有一个合理的调度情况和调度策略。其中跟这个最重要,或者说最关联性最强的一个概念就是原子操作。 GO语言中的原子操作具体实现过程是怎样的? 对于原子操作,在其逻辑下,按照它书面的定义上来讲,是指不会被调度器打断的操作。对原子操作实际上就是不存在中间状态的一种操作,要不就全成功,要不全失败,这个在我们在用并发方式来调动某任务,或者说来设计某种并发系统的情况下,这种名字操作我发现是非常重要的设计理念之一。 并发与并行具体概念及实际区分是怎样的? 有一个比较重要的一个概念,就是并发与并行,其实并发与并行,它实际上具体的含义是不一样的,并发实际上是把任务在不同的时间点交给同样一个处理器来进行处理,在同一个时间点,任务不会同时进行,只是任务感觉自己正在执行,因为其那会儿可能正在堵塞状态或者说是就绪状态,其不知道自己被暂停了,以为已经被调度走了,可能自己没有感知,但是实际上CPU所有权已经不在这个任务身上了。 并行比并发更高级一些,它实际上是把每个任务都交给独立的处理器去进行完成,但同一时间点,任务在一定程度上实际上是同时在执行的。一般来说,并发的性能是要比并行更重要一些,在1.5版本之前,我们需要人工去设置GO调度器最多能运行在多少个CPU上,但是在最新的GO版本当中,已经不需要这个相关的操作。 详细介绍一下并发程序中的竞争态? 并发系统设计最初始的这一个概念就是并发程序设计当中一个竞合的概念,或者也叫竞争态。假如说我要记录一个文件的阅读量,但是这个文件或者说这个网页,可能它的阅读渠道有非常多,有可能通过引擎通过微信通过APP等等这些渠道,这些渠道的话呢,它的阅读也都是并发的,这就会涉及到同样一个变量,被多个协程的所共同访问的情况。具体代码如下: 对于GO语言并发体系中的主推的通信机制是什么? channel是GO语言并发体系中的主推的通信机制,它可以让一个 goroutine 通过它给另一个 goroutine 发送值信息。每个 channel 都有一个特殊的类型,也就是 channels 可发送数据的类型。一个可以发送 int 类型数据的 channel 一般写为 chan int。 GO语言当中,它实际上是大家协同的机制,通过这种方式让几个goroutine之间做达到一个协调的效果,那么每个goroutine当中,实际上channel都是一个特殊的类型,它实际上是可以发送数据。比如现在想发送一个int类型的数据,那么channel就要定义一个发送int数据的一个管道。 那么GO语言当中,提倡使用通讯的方式来代替共享内存的方式来做goroutine,或者说并发之间的一个协同。channel如果我们后续阅读它的代码就会知道,它是保证协程安全,并且它遵循这个先入先出的原则来让这个储蓄方读取获得数据,而且它能保证顺序,正是这两个特性,可以让这个channel替代共享内存,因为它的如果顺序有所改变的话,它实际上也是有会有问题。 详细介绍GO语言中关于通道的声明涉及哪些方面? 1.经典方式声明 通过使用chan类型,其声明方式如下: var name chan type 其中type表示通道内的数据类型;name:通道的变量名称,不过这样创建的通道只是空值 nil,一般来说都是通道都是通过make函数创建的。 2.make方式 make函数可以创建通道格式如下: name := make(chan type) 3.创建带有缓冲的通道 后面会讲到缓冲通道的概念,这里先说他的定义方式 name := make(chan type, size) 其中type表示通道内的数据类型;name:通道的变量名称,size代表缓冲的长度。 具体介绍通道数据收发的详细过程有哪些? 通道的数据发送 通道当中发送数据的操作服务是这样的这样的一个大于号加上一个减号。 chan <- value 注意,如果是发送给一个没有缓冲的一个通道。假如说数据没有被接收的话,那么这个发送操作将持续被注册,也就是说就是channel这个语句就直接被注册到这,假如说没有任何的协程去读到他或者其他语句去读到这个产品,那么这个语句就被注册掉了。但GO语言是能发现的,如果其一直在堵塞的话,那实际上就造成死锁,GO语言的编译器实际上能发现的有点错误。 假如说,首先创建一个int型的通道,然后直接尝试发送一个数据给它,编译会报错,然后呢,数据的这个数据的接收的话,实际上就是把这个点号的位置跟那个大于号的位置做了一个调换。其实把这个双方的位置做了一个调换之后,是实际上就是都做了一个允许的操作。这其中的话呢,还有一种比较特殊的一个读取操作是其可以忽略到接收到的数据,因为不管管道中发出的数据,如果没读的话就堵塞到这,那么如果你觉得这个语句你也不需要,那么你可以把那个变量给它忽略掉。 2.通道的数据接收 通道接收数据的操作符也是<-,具体有以下几种方式 - 1) 阻塞接收数据 阻塞模式接收数据时,将接收变量作为<-操作符的左值,格式如下: data := <-ch 执行该语句时将会阻塞,直到接收到数据并赋值给 data 变量。 如需要忽略接收的数据,则将data变量省略,具体格式如下: <-ch - 2) 非阻塞接收数据 使用非阻塞方式从通道接收数据时,语句不会发生阻塞,格式如下: data, ok := <-ch 非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少。一般只配合select语句配合定时器做超时检测时使用。 关于通道数据收发有哪些需要注意的事项? 通道数据在进行输入收发的时候,必须要在两个不同的goroutine当中进行,因在同一个goroutine当中,收发的这些语句实际上都是堵塞的,你可能在同一个goroutine当中,它的这个函数已经在那边阻塞住了,或者说程序已经在那边阻塞住了,它已经停在那了,你后面有一句你能执行不到,所以说通道的收发必须在两个不同的goroutine之间来进行,在同一个goroutine之间的这个收发操作的话,实际上是没有意义的。 接收将持续堵塞,直到发送方发送出去,如果接收方接收,然后通道中没有发送方数据时,接收方也会发送,直到发送方到发送数据为止。就是刚才说的这个一体两面,这个发送方假如说没有人读的话,发送方会堵塞,假如说没有人写的话,那么接收方也会发生堵塞,这两边实际上都会有一个堵塞的情况。那么这个通道的收发的话呢,一般来说一次只能收一一个元素,假如说这个是一个有缓冲的一个通道,我通过一次不操作的话,实际上也只不过读出一个元素。不能把它一些缓冲区所有元素都读出来。 聊一下生产者消费者模式具体内容有哪些? 介绍一下生产者消费者模式,从GO语言的这个并发模型来看,也就是说假如说咱们站在一个比较高的一个高度来看,其实利用channel的确能达到共享内存的目的。这个channel的性质与在读写状态且保证顺序的共享内存并无不同。甚至我们可以说这个是基于消息队列的封装程度可以比共享内存来的更安全,所以说呢,这个在这个GO语言当中,或者说在GO语言的这个设计风格当中的话呢,其这个生产者消费者模式实现起来会相对来说比较简单一些。我们先介绍一下什么是生产者消费者。 就这个这这张图当中的话呢,就是一个典型的那种消费的问题, 就是说我是生产者的话我会生产一些产品,然后放到这个仓库当中,消费者的话会从那个仓库当中去取商品,这个可以说是消息队列,还有包括卡夫卡那些比较经典的相应队列当中,都会用到的这么一个设计模式,或者说其们从本质上来说的话,都是基于这样一个设计模式,交易的生产者是谁?消费者是谁?这个消息队列的话是。这个生产者消费者模式的话呢,实际上也成为有缓冲有限缓冲问题,它是一个并发的一个经典的案例,因为我们知道这个商品仓库的库房大小是有限的,也就是说生产者不能无限的去生产商品,一旦这个库房爆掉的话,它是它是必须要中止自己的生产,消费者也是不能无限地获取消息。 假如仓库是空的话,那这个消费者的这个相关的情况也需要被阻塞。那么怎么在这个生产者跟消费者之间保证商品不丢失。这就是生产者与消费者之间最核心的内容。先来看一下这个Java当中生产者消费者的这种实现到底是什么样的。这个可以说是一个最经典的这么样一个实现。这个Java当中是没有channel,那么它只能通过什么呢,只能通过信号量和一个一个log,也就是说一个忽视服务态度,这两个这两个配合信号量和所配合才能共同完成,这样一个生产者消费者这么一个相关的工作。 GO语言并发实战详细过程梳理 在现在这个远程办公的这一个大的背景下,积累了大量重复的文件,因为很可能大家都不断的在不同的群里发相同的文件,发相同的这个报表,以及一些相同的视频等等这些需要学习的材料,那么怎么把这些文件都找出来,然后把这些相同文件都给删掉了,这实际上是并发课的一个实践的一个内容,因为这个创业型的这个方案的话,它的代码相对来说比较长。 如何使用GO语言清理PC机中的文件,详细代码及注释如下: package main import ( // "fmt" // fmt 包使用函数实现 I/O 格式化(类似于 C 的 printf 和 scanf 的函数), 格式化参数源自C,但更简单 "io/ioutil" //"sync" //"time" ) func PrintRepreatFile(path string, fileNameSizeMap map[string]int64, exFileList []string) { fs, _ := ioutil.ReadDir(path) for _, file := range fs { if file.IsDir() { PrintRepreatFile(path+"/"+file.Name(), fileNameSizeMap, exFileList)//遍历整个文件系统,如果是目录则递归调用 } else { if file.Size() > 1000000 {//设定文件清理阈值,如果大于一定大小再进行清理 fileSize := fileNameSizeMap[file.Name()]//通过查哈希表的方式来确定,有无重名且大小相同的文件。 if fileSize == file.Size() { fmt.Println(path + "/" + file.Name())//如果有则打印出来 exFileList = append(exFileList, path+file.Name())//将结果记入切片当中 } else { fileNameSizeMap[file.Name()] = file.Size() } } } } } func main() { //方式一 fileNameSizeMap := make(map[string]int64, 10000) exFileList := make([]string, 100, 1000) PrintRepreatFile("E:/test", fileNameSizeMap, exFileList) } 这个程序在GO语言的环境下可以直接运行使用,其中有几个知识点,也是咱们前文提到过的,首先是切片的大小一定要设定的相对合适一些,如果容量不够大造成频繁扩容非常浪费资源。二是哈希表也就是map没有并发安全的属于,在我们这个未引入并发的程序中可以使用,如果有并发操作,那么map不再适用了。 可能很多人被GO语言的在并发性能所吸引入坑的,GO语言之父也就是UNIX之父Ken Thompson明显给出了很多建议,根据笔者在操作系统方面的相关经验来看,GO语言设计中经常参考UNIX内核的设计思路。比如硬定时器的数量有限,无法满足系统实际运行需要,所以在内核代码中就会看到基于硬件定时器的软件定时器的方案,而软件定时器的数量可以比硬件定时器多几百倍。 这样的理念明显融合到了 goroutine之中,由于其它编程语言往往直接通过系统级别的线程来实现并发功能,但是这样的方式往往会是大马拉小车,造成系统资源的浪费。因此GO语言封装了所有的系统操作,实现了更加轻量级的协程-goroutine。只要使用关键字(go)就可以启动协程,对比C++、JAVA的多线程并发模型,GO的协程更简单明了。 当然协程之间的消息通信与并发控制也是非常重要的一环。在GO语言借鉴了Message Queue的消息队列机制替代共享内存的方式进行协程间通信,其中管道channel作为基本的数据类型,保证并发时的操作安全。而且管道的引入还带来很多实践中非常实用的功能,比如可以方便实现生产者、消费者等并发设计模式,而这些设计模式在其它使用共享存内存的并发模型中实现起相关功能来非常的繁锁。 在GO语言中在调用函数前加入go 关键字,就能启动一个协程,也就是一个并发,但是我们上面的程序如果把调用方式改为: go PrintRepreatFile("E:/test", fileNameSizeMap, exFileList) 你会发现程序会直接退出,什么都没做,所以GO语言的并发对于初学者来说还是有一定门槛的,比如上例中如果想设计成一个并行的程序,如何让多个协程共同来帮忙找出重复的文件其实还是要费一番周折的。

剑曼红尘 2020-04-13 11:06:46 0 浏览量 回答数 0

问题

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

问问小秘 2020-06-02 14:27:10 42 浏览量 回答数 1

问题

一个老码农的技术理想

技术小菜鸟 2019-12-01 21:17:10 3067 浏览量 回答数 1
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 云栖号物联网 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 云栖号弹性计算 阿里云云栖号 云栖号案例 云栖号直播