Kafka Streams In Action part 1

Part 1 Getting started with Kafka Streams

1.Welcome to Kafka Streams

1. The PageRank algorithm

2. Introducing stream processing

3. When to use stream processing, and when not to use it

If you need to report on or take action immediately as data arrives, stream processing is a good approach. If you need to perform in-depth analysis or are compiling a large repository of data for later analysis, a stream-processing approach may not be a good fit.

4. Deconstructing the requirements into a graph

5. Applying Kafka Streams to the purchase transaction flow

2. Kafka quickly

1. Using Kafka to handle data


ZMart’s original data platform


A Kafka sales transaction data hub

2. Kafka architecture

Kafka is a message broker


Kafka and partitions

The distributed log


Replication


Controller responsibilities


Deleting logs

Compacting logs

Sending messages with producers

Reading messages with consumers


是什么促成了你成为一名“厉害的”开发者?

当看到“厉害的”这个词的时候,我希望你知道我指的是“令人倾佩”,“令人欣赏”的意思。同时我也觉得你一定是见过这样的人。

那么我们到底欣赏他(她)的是什么呢?

肯定是他(她)一定是解决问题能力很强的人。在实际编程问题中,我们都是在解决问题,我曾向我母亲解释我的职业,或者说我的工作——有点像小学的时候解决数学应用题。编程很多的时候都是在解决问题。只不过我们不是用数学的语言,而是用编程语言。

解决一个问题,如果你知道的知识比较多,比如你现在已经是中学毕业了,假设你学业成绩还不错,你再去看小学的数学应用题,我想应该不是很难,你可以比较轻松地解题。高出那个级别,你就很容易,因为你掌握足够的知识。所以不断让自己级别提高就是掌握更多的知识。

解决问题,尤其是相应的知识掌握的比较多,你解决问题的能力自然不会很低。知识一定只是解决问题的一个方面,有时候尽管你掌握了很多的知识,包括解决相应问题方面的,你一定会那是那个令人倾佩,令人欣赏的开发者吗?

我看不一定是。知识只是一个方面。解决问题,除了拥有知识,还需要拥有解决问题的动力。你知道该怎么做,但是不一定说你一定会去及时做。你没有及时做的原因,可能是你懒了,也可能是你没有排好事情的优先级,你可能觉得自己不懒,现在你可能觉得我说“懒”是一个贬义词,其实懒是让你蜕变的一个内在因素,相反如果你一直那么忙碌,一直那么勤劳,有时并不是表面上看到的。懒一定程度上触发了思考,触发了创新。懒是惰性导致的,你有时都没有感觉到自己懒。但不管怎样,我说这么多,就是让你认识到,我说懒,并不是说你怎么不好,请一定要理解。

我们经常没有意识到一个问题,那就是客观的时间和自己的精力都是有限的,至少是今天有限。有时候我们在解决一个问题,在思考一个bug怎么解决,我们就会投入进入,然后时间就在默默流逝,当然你的精力也是在以不易察觉的形式流逝。有点像手机里的电池一样,你每天早上醒来,经过一夜的充电,活力满满,元气十足,那是你休息了一晚,睡了个好觉。然后经过一天的工作,思考一些问题,写一些代码,你的电池就会慢慢放电,直到电量90%,80%,70%,下午的时候甚至就只有40%,接近下班的时候就或许只剩下15%。关于时间和精力的问题,我以前只认为是程序员乐观导致错误地估计,后来有一天我突然认识到,乐观不仅仅程序员的“特权”,很多人都拥有着,并使用着。

我上面提到有时候没有解决问题,可能是你动力不足,也可能是你安排不当。如果我们深刻地意识到时间和精力是有限的,我们一定要懂得合理安排事情,解决工作的问题也是一样,这里可能就是指编程中问题,你一定要认识到那些事情是你可以及时解决的,那些问题需要你及时解决的,不是别人怀疑你的能力,而是工作的方式,需要为自己的工作事项,合理安排时间和顺序,这样你才能提高解决问题的能力,这种能力和知识无关,可以叫做工作方法。如果工作方法也叫知识的话,是的。它也是知识,你现在掌握了,以后应用的时候,你如果没有及时解决问题,不要怪罪于不知道怎么做的知识层面,而应该更多的时候,想想你工作方法有问题。

我们再深入一点,我上面“普及”的知识是你第一次听到吗?如果真的是,你真应该好好庆幸,你get到了这块知识。我们在上学的时候,可能就听说过,“事情要分清楚轻重缓急”。我想上面的工作方法也是由它进化而来的。工作中给各种事情排个号,在什么时间做什么事,重要的事情,需要优先完成。所以说这块知识,你可能已经掌握了。那你为什么没有做呢?因为做这项事情是需要思考的,思考是件需要克服惯性的,如果你的惯性就是不给事情排优先级,按照事情进行的顺序,或者说事情来到的顺序来做,那么你很有可能是没有很好地提高解决问题地能力。

我大学的时候曾经一度认为,我是一个分不清事情轻重缓急的人,我那个时候经常会遇到很多的事情并发地发生,需要我去处理。然后有时候,我没有做好一些事情,比如我当时在学生会中的一些工作,在比如学习上的一些事情。

我今年看了一些书籍,那些书籍竟然是理财方面的,我认识到了,在行动的内部,是由思想控制的,但很多时候行为却是由惯性控制的,它有点跳过思想,它的喜好更多的时候就是不喜欢思考。如果你养成了这个习惯,可能还自己都没有认识到,它伪装的如此完美,就像隐身术一样,你看不到它,但是它却在暗中“左右”着你的行为。

如果你养成了把事情排个优先级的习惯,解决工作中的问题的时候也是如此,那么你解决问题的能力会有较大的提升。这就是习惯的力量。而且你发现这将是一个好的习惯,它会你把有限的时间和精力发挥地淋漓尽致。

习惯的养成,需要我们付出努力,因为你可能经常放弃,或者产生放弃的想法,但是你要知道,你要想提高解决问题的能力,在知识方面你也在积累,但是更多的时候,好的工作方法——这是习惯提供给你的,会让你事半功倍。

我现在分享到的“习惯”还只是知识层面,应该它只有落实到行动上,才会是属于自己的习惯。这个习惯需要时间的洗礼。

我还想起了一段话,这段话是——编程中,不要相信你的眼睛,而要相信你的Ctrl+C和Ctrl+V。这是我们写代码中经常出现的,有时候,我们经常去敲一些单词,可能是变量,但是最后程序的运行结果却不是我们期待的。

这表面上也是编程中的方法问题,其实也是习惯问题。当你养成了相信计算机而不是自己的时候,你犯错的概率也会大大下降,当然现在的IDE很多的时候都在帮你少犯一些“低级”错误。

回到主题上来——是什么促成了你成为一名“厉害的”开发者?

上面主要提到的是知识之外的——解决问题的能力养成,在有限的时间和精力中把事情习惯地排上优先级,然后再一一完成事情。

解决问题,还需要知识。我记得我在《HOW TO DEVELOP QUALITY SOFTWARE WITH A GOOD VELOCITY》中提到过知识是需要积累的,但你可以掌握快速地解决问题的最少知识,快速地获取知识也绝对是一门可以练习的技能。这个话题我想此时不在这篇文章中展开。

虽然文章大篇幅地在讲知识之外的能力——养成好的工作方法,形成习惯。但是我们在用好的工作方式的同时,我们一定也不会忘记知识的力量。

6-Prevent Brute Force Authentication Attempts

防止暴力破解,这个话题在上一篇末尾说到,当用户有了你的用户名,如果一直尝试用密码去登录,如果你的密码强度比较高的情况下,“破解”这种难度会比较高,密码强度很大程度上是用户为了安全做出的努力,那我们开发者有没有一个可以贡献的地方呢?

显然是有的,我们的常用到的手机,有手势密码,有数字密码,有FaceID,如果我们尝试了很多次都一直错误,可能账号会被锁定。锁定就是暂时不让用户“尝试破解”密码,这时锁定就是不管用户输入什么密码,我们直接拒绝认证请求(登录操作),不进行后面的密码验证、用户鉴权等等操作。甚至我们在苹果手机上还会看到,如果用户一直尝试解锁失败,锁定的时间也会越来越长,这个方案也会带来新的挑战,如果“坏人”就是要锁定你的账号,不让你登录——很长时间的锁定,这时候我们可能会有新的一些安全措施,比如常用的登录设置,常用的登录IP地址(账号使用范围,比如安徽省,而不是美国加州),甚至有些时候我们可以人工客服解锁账号。这一些都是常用的防止暴力破解的安全方案及后备方案,我们今天探讨的是在Spring Security中怎么实现防止用户暴力破解。下面我们看看具体的操作。

1.添加一个认证失败事件监听器AuthenticationFailureEventListener

2.添加一个认证成功事件监听器AuthenticationSuccessEventListener

3.上面两个事件监听器都用到了LoginAttemptService

再看看它的具体实现类LoginAttemptServiceImpl

上面用到了Google guava框架中的LoadingCache,CacheBuilder,CacheLoader.其实具体的实现不是很困难,上面的方便之处就是可以在写入一天后过期,这一点在数据维护方面,投入的成本就比较低,比如前面我们用到的用户激活token,忘记密码token,这些数据中都有过期信息,那些过期数据其实没有太多数据价值的话,为了节约数据库成本是可以删除掉的,当然可以交给dba去做,还有就是可以使用java中的定时任务完成过期数据的删除,这个在后面的文章中我们会使用到。

上面使用的是内存保存数据,在服务重启的情况下,可能不是最好的选择,我们就自然想到Redis,数据既在内存中,同时还可以持久化数据到硬盘,并不会丢失。所以在实践中可以使用Redis来替代上面的 LoadingCache 。

还有一小点,MAX_ATTEMPT = 10,这个如果经常变更可以写成可配置的。

4.修改一下MyUserDetailsServiceImpl,优先检查用户有没有被阻塞。

5.CustomAuthenticationFailureHandler添加相应的错误信息(这个之前已经写好了)

UNUSUAL_LOCATION 这个我们后面也会使用到,先可以不用关心。

最后我们一起看下所有新增及改动的代码

我们启动项目验证一下,我故意把wys2317@hotmail.com的密码输错3次,我修改了MAX_ATTEMPT=3. 第四次再输入错误时就会出现下面的信息,然后你可以再尝试都会出现下面的信息。

最后我们补充两点:(1)上面的错误信息是在messages.properties中定义的。auth.message.blocked=This ip is blocked for 24 hours
说到这个i18n,我们如果想让错误信息更“动态”,其实 messages.properties 中可以使用占位符的,这样如果我们构建的“锁定”时间是一次比一次长的情况下,我们就可以给出具体的锁定时间,而不是每次都是24 hours。这个感兴趣地可以自己搜索有关资料。(2)看一下这个获取客户端ip的方法

在获取ip的时候,可能你会使用工具类,因为有时候需要一些封装,上面的封装可能还不够, 想获取真实的用户ip有时候的确需要付出一些额外的努力,代码封装上面的,甚至如果你的nginx也需要做一些配置。这个也是需要我们根据真实情况做一些调整。

具体的代码可以参见github.