A(算法) :
题目: 239. 滑动窗口最大值
解法思路: 这道题目需要的代码量不大, 但是思路比较绕. 用暴力法去做很简单,时间复杂度是O(m*k).引入了window 作为队列后, 队首元素保持为window 最大值, 只有当i >= i -k 的情况下才淘汰队首元素. 优化后的算法复杂度是O(n)
class Solution(object):def maxSlidingWindow(self, nums, k):""":type nums: List[int]:type k: int:rtype: List[int]"""if not nums:return []window, res = [],[]#核心要义, 先清理 window, 后加入#继续拆分步骤就是 1. 保持队列头部的值是window的最大值# 2. 清理的时候,先清理头部的元素# 3. 然后清理window 队尾更小的数for i, x in enumerate(nums):if i >=k and window[0] <= i - k:window.pop(0)while window and nums[window[-1]] < x:window.pop()window.append(x)if i >= k - 1:res.append(nums[window[0]])return res
R(Review):
文章: 链接 Notes on Distributed Systems for Young Bloods
总结: 这是”左耳听风” 在分布式经典材料中介绍的一篇比较简单文章, 但我觉得受益不少, 可以在日后的设计有不错的知道意义
Distributed systems are different because they fail often"分布式系统跟传统系统不一样, 因为他们会经常故障": 分布式系统引入了网络因素, 这也是故障频发的最根本原因解决的办法就是"将处理故障的代码当做正确代码的一部分" 设计系统的时候要 "design for failure"Writing robust distributed systems costs more than writing robust single-machine systems"实现一个健壮的分布式系统的代价要比单机系统高" : 如前所述, 引入了网络这个因素后, 机器之间交互的复杂性, 成本都要比单机系统要高Robust, open source distributed systems are much less common than robust, single-machine systems."健壮的开源分布式系统通常比开源的单机系统少见" : 我认同作者这个观点, 因为分布式系统的实现本来就比较困难, 但作者描述的情况更侧重于"开源贡献者无法持续投入", 这个理由我就觉得比较牵强, 因为无论是什么样的开源软件, 都会有这种情况出现, 跟是否分布式无直接关系.Coordination is very hard. Avoid coordinating machines wherever possible."机器之间的协作是非常困难的, 要尽量避免" : 分布式系统会存在"两个将军", "拜占庭" 等等经典问题, 都是机器协作需要解决的问题, 然而, paxo 算法可以却解决, 但要实现这个算法也不是一件容易的事情If you can fit your problem in memory, it’s probably trivial"如果能通过单机内存就解决的问题, 通常是个比较简单的问题": 跟之前作者的观点类似.“It’s slow” is the hardest problem you’ll ever debug..""这太慢了" 是最难定位原因的问题": 很好理解, 网络因素令到排查问题更复杂, 如果不使用全链路监控, 基本就是费时费力Implement backpressure throughout your system"在你的分布式实现 backpressure" : 我的理解是: backpressure 更像一种机制, 可以让系统感知自己所处理的流量是否已经到达上限. 从实践层面上看,就是使用限流机制来.Find ways to be partially available"保持部分可用" : 本质上就是外部资源不可控, 要有降级机制Metrics are the only way to get your job done"指标是衡量你工作是否完成的唯一标准" : 这个观点很有意思, 在单机系统, 我们通常是"输入", 然后"验证输出" 这种流程来衡量自己的代码是否已经生效但在分布式系统中 , 必须要有指标输出, 才能判断代码是否符合自己的预期Use percentiles, not averages."使用百分比而不是平均数来衡量系统指标" : 这算是一个常识, 平均值会淡化尖刺指标, 如一个tps 1000 的服务, 95%的 RT 是5ms, 剩下的5% 是2000ms, 那么这5%的尖刺就会被平均掉了.Learn to estimate your capacity."学会评估系统的容量" : 要随时评估系统的容量是否能满足业务需求, 做好扩容计划Feature flags are how infrastructure is rolled out."功能标记就是基础设施推进的方法" : 这个我翻译得有点别扭, 不过理解起来就是 : 在功能迭代的过程, 最好使用功能标记来小步迭代发布, 避免上线Choose id spaces wisely."要明智地选在id 空间策略" : id 的空间策略, 其实就是要充分考虑它的扩充成本, 如果id 的生成规则没有业务含义, 那就需要引入外部系统来解决路由问题, 这样才能实现系统扩展, 如果id本身自带路由规则, 那就需要考虑这个规则会不会被破解,也就是安全性问题Exploit data-locality."充分利用 数据本地性优势" : 很好理解, 数据能本地处理, 既可以节省带宽, 又可以降低复杂度Writing cached data back to persistent storage is bad."将被缓存的数据回写到存储是一种不好的实践" : 其实就是要解决"数据一致性"带来的麻烦成本很高Computers can do more than you think they can."现在的计算机能做的已经超过你想象" : 要关注硬件发展, 有时候单机的处理性能已经足够解决问题了.Use the CAP theorem to critique systems."使用CAP 理论来评价系统" : CAP 理论虽然不能知道你如何设计系统, 但它能用来随时去评价你所做的系统. 去让你更清晰的认识到究竟在哪个部分做了trade off.Extract services."要尽量服务化" : 作者认为, 共享逻辑通常有两个办法: 1."代码库" ,2,"服务化". 但后者是更有优势, 其原因就是可以集中式升级, 如果通过代码库共性逻辑, 就会导致这些逻辑散落到客户端, 升级起来就会比较痛苦.
S(分享): GraphQL vs REST
.GraphQL 是FB 公司开源的一个项目, 它主要解决以下问题.
.传统的REST 接口只能获取单一资源, 如果要获取其关联的资源, 就需要多次去读取不同的接口.
.比如: 想获取用户的图像和他的粉丝, 那么就需要两个步骤: 1 .获取用户信息, 2. 根据用户id 获取粉丝列表.
.REST 接口无法灵活定制查询条件, 造成接口的冗余
.比如: 有些页端请求需要根据查询日期来查询用户流水, 那么就需要传开始时间和结束时间作为参数(start, end). 然后它又需要根据流水状态和用户id 去查询, 那么就需要有另外一个接口需要传status , userid 参数. 如果想组合里面的参数, 可能就会需要实现更多的接口. 这样就会导致接口过度冗余.
.GraphQL 可以通过统一的接口来满足这种需求. 网上已经有很丰富的教材, 可以直接参考 链接
最后, GraphQL 也不是没有缺点, 他主要的缺点其实是将所有复杂逻辑移动到后端, 由于REST 接口是很简单的, 服务器很容易对其做优化(比如加缓存) , 但graphql 就比较麻烦了 ,需要定制一堆resolver 来解决这个问题, 增加了不少的复杂度. 所以在项目实施的时候要充分平衡两者的优缺点.
T(Tips): 最近在使用maven 的时候发现了个问题, 当前我开发的是snapshot 版本的代码, 每次修改后, 即便发布了二方包 后, 本地的开发环境 intellij 也有可能无法获取最近的更), 无论”reimport” 多少次, 后来我发现不一定是intellij 的问题, 因为直接用
mvn clean package 也是没法获取最新的包, 最简单的解决办法是直接升级版本号, 我身边的同事也是这样认为, 但我觉得这没道理啊, snapshot 本来就应该可以随时更新内容
后来我发现解决的方法就是直接用maven 强制更新:
使用: mvn clean package -U
这应该是跟mvn 的代码缓存策略有关, 先记下问题, 后续再去看下它的实现原理.
