做了 876. Middle of the Linked List,找出链表中间的节点,挺简单的题目,但是解题方法挺典型的,最简单的方式是通过双指针的形式进行迭代,当迭代较快的指针迭代到链表尾部时,慢指针就到了中间节点了,代码如下:
class Solution {
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
在链表相关的题目中,遍历、反转链表与双指针是用的比较多的方式,比如链表是否有环的判断也可以通过双指针的方法实现。
Nginx 微服务系列文章第五篇:Event-Driven Data Management for Microservices,主要讲了微服务的事件驱动数据管理,探讨了在微服务系统架构中因为服务拆分带来的数据存储相关的问题。
对于传统的单体应用,一般来说也会有一个单一的数据库进行数据存储,这样有两个好处:
- 数据的存储满足 ACID 的要求,可以很方便的进行事务性操作
- 数据可以通过 join 联结进行查询
而在微服务中,每个服务都会有自己专门的数据存储媒介,可以带来如下几个优点:
- 数据全部以 API 的形式对外暴露,实现了服务之间的松耦合,服务之前的通信不受其他服务影响
- 可以根据需要灵活的选择合适的存储媒介,比如缓存服务可以用 Redis,搜索服务可以用 ElasticSearch,提高了性能和可扩展性
当然也带来了如下挑战:
- 对于事务性操作,如何保证数据的一致性
- 对于需要查询多个服务数据的操作,如何保证查询的有效性
- 存储组件的增多带来的开发和运维成本的上升
在微服务中,每个服务的数据更新都会产生一个事件,发送到消息中间件中,然后由后续服务订阅消息在前一个事件的基础之上继续执行相关的操作。下面展示了一个在创建订单时更新用户信用的事件驱动实现的执行过程:
这样,通过事件驱动的方式,我们在多服务之间完成了一个事务性操作,此时我们无法像传统数据库采用的 ACID 那样保证数据的强一致性,而是保证数据的最终一致性。
在事件驱动架构中,我们依然需要保证操作的原子性,比如创建订单和发布订单创建事件这两个操作,必须保证其原子性。此时有如下几种方式:
在本地创建事件表,当某个表的数据有更新和新建时,创建一个本地事务,更新数据表后同时在事件表新增一条数据,最后提交事务,这样保证了数据的更新和事件的生成是一致的,然后由另一个发布事件线程不断轮询事件表,一旦有新的事件生成则往消息队列中发送时间。
下面是一个示例图,创建订单和创建事件为一个事务,发布服务不断查询事件表然后向消息队列中发送事件:
本地事务的好处
- 在单个服务中保证了原子性
- 可以随时发送业务性的事件
本地事务的缺点
- 每次更新数据必须要记住其对应的事件,增加了复杂度
- 对于某些存储媒介为 NoSQL 数据库的可能无法实现本地事务
除了本地事务外,还可以通过事务日志的方式实现,示例如图,每次数据更新都会产生事务日志,然后通过日志解析服务,将日志转为事件对外进行发布
优点
- 实现了数据更新和事件发布的解耦
- 保证了每次数据更新都会有事件发布
缺点
- 日志的格式随着存储媒介的种类和版本不同可能会有变化,不易维护
- 与上层业务解耦,导致无法通过事件反向推出是何种业务导致的,使得逻辑不够清晰
事件源以事件为中心,而不是以业务实体为中心。数据库不在存储业务实体的当前状态,而是存储业务实体的一系列更新事件,通过事件来重构出业务实体的当前状态。
下面是一个订单的存储,有一个 EventStore 存储事件的中心,订单服务只管发布订单创建、更新等事件,此时 Customer 服务只负责订阅事件,通过事件就知道当前某条订单的状态是怎样的。因为单个事件的存储仅仅是一个操作,因此必定的原子性的。
好处
- 全部依赖于事件而不是业务实体,而事件的发布是原子性的,解决了数据的一致性问题
- 事件源提供了对业务实体 100% 可靠的审查日志,并且可以提供任何时间点的时态查询
- 面向事件而不是面向业务实体,避免了 Object-relational impedance mismatch
- 因为全部面向事件,因此实现了业务实体之间的松耦合,有利于单体服务向微服务架构进行迁移
弊端
- 面向事件的编程方式与以往不同,因此有一定的学习曲线
- 事件存储仅支持按主键查询,必须使用 CQRS 来实现查询,因此应用必须自行保证换数据的一致性
以上就是本篇文章的主要内容,简单介绍了微服务架构中数据存储的实现方式,即不同的微服务有其单独的、适合其服务特性的存储媒介,同时服务之间的信息传输通过事件进行异步通信。然后为了保证事件发布的原子性,有本地事务、事务日志、事件源等几种处理方式,有兴趣的同学可以在进行相关深入的学习。
读了 《Linux 性能与优化》中 《38 | 案例篇:怎么使用 tcpdump 和 Wireshark 分析网络流量?》,于是看了下 wireshark 相关的文章,分享下学到的几个技巧吧,原文链接: 10 Tips On How to Use Wireshark to Analyze Packets in Your Network
!(ip.addr == 192.168.0.10)
WireShark 支持逻辑运算符的操作,可以通过 ! 来做非的过滤。
右击某个请求可以选择查看其 TCP 流,HTTP 请求的话还可以查看其 HTTP 的内容,如图:
这是在极客时间专栏中看到的,可以查看 TCP 协议的传输过程,下面一个 TCP 握手过程的分析,示例如图:
可以看到出来的分析图非常像网上看到的演示 TCP/IP 握手的图,可以很好的拿来学习 TCP 协议。
WireShark 官网提供了相应的文件供我们练习网络请求的分析,网址在这 SampleCaptures。里面有各种类型协议的捕获文件,需要的同学可以拿来好好练习一波。
聊下习惯吧,之前看《习惯的力量》,习惯的形成是暗示 - 行为 - 奖赏的机制。结合之前在得到看的 《精力管理》的课程,为了保证早起后因为琐事被打断或者昏昏欲睡动力不高的情况,给自己定了几个习惯:
前一天晚上无论如何都要对第二天的事列出一个大概的 TODO List,并且列出最高优先级的 3 件事,保证第二天起床后就知道自己应该干什么
醒来穿衣、叠被、洗漱、喝水、早餐;过程中不能被任何事情打断,比如刷个朋友圈,突然想起要下个软件啥的,在这期间一律不准进行,因为一旦进行,就会中断上面顺序中的某一个环节,换来的结果要么是不吃早餐损害健康,要么就是有点邋遢,边幅不整,都不划算。
九点半出门上班前手机断网,不刷朋友圈等任何社交网络, 之前也聊过一次关于碎片化时间的问题,简单来说就是不是时间碎片化了,而是我们自控力不足导致经常性的触碰各种软件,导致自己时间被碎片化了,因此为了保证早上难得的大块时间,屏蔽网络是非常有用的事情。
现在在早上我一般会学习一些重要但是不紧急的事情,比如耗子叔在练级攻略中推荐的那些大部头书和知识点的学习,以 1 到 2 周为单位,每周一到周五每天 1.5 到 2 个小时的学习,然后加上周末两天的总结学习,一般来说一到两周大致掌握一个知识点是足够的。
上面的具体的行为,也就是 暗示-行动-奖赏中的第二步,暗示的话这个全靠自己了,比如我会有如下暗示:
- 认真学习后的踏实感;哈哈 甭管有没有真学到东西,但是认真学习一段时间之后那种心情上的满足感和整天玩游戏刷剧后的焦虑感、负罪感真的不是一回事
- 技能上的储备,或者和同事聊天、面试时对于很多知识点如数家珍的装逼感,
有了暗示和行动,接下来就是奖赏了,对于长期的奖赏,因为知识的滞后性,可能无法体现出来,尤其是面对那些枯燥的知识,当长期投入没有实际回报时,人是会变消沉的,因此还是有必要整一些短期的激励,对于我而言有两点:
- 吃吃吃,晚上不控制饮食,因为现在会健身,因此中午吃饭尽量保证吃健身餐,当然吃完非常没有幸福感,早上早起学习,中午吃健康餐,晚上必须得对自己好点了。。。
- 咖啡无限量供应,想喝就喝吧,喝了咖啡可不能再偷懒了。
以上是自己在调整生活学习习惯中的部分做法,希望对有需要的同学有帮助,欢迎互相交流,一起进步。