• 你附近的人都有谁,这个功能是怎么实现的?

    手机上很多软件都有附近的人的功能,比如微信的“附近的人”,美团的“附近的餐厅”等等,那么这些功能可以怎么实现呢?

    Redis中的Geo命令

    在Redis在3.2版本新增了一个功能,就是GEO(地理位置),这个GEO功能总共有6个函数,分别为:

    GEOADD:添加指定的地理位置坐标值到指定的key中,可以同时添加多个。

    语法:GEOADD location-set longitude latitude name [longitude latitude name ...]

    GEODIST:计算两个给定位置之间的距离,可指定距离的单位,默认是米。

    语法:GEODIST location-set location-x location-y [unit]

    Read more...
  • 你真的知道什么是线程安全吗?

    如果面试官问你,线程安全的类有哪些,究竟什么是线程安全?你怎么回答呢?我们整天说线程安全,但你真的知道什么是线程安全吗?

    什么是进程

    从学术上理解,进程就是包含上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文

    Read more...
  • Java项目如何分层

    在现在的Java项目中的项目分层,大多数都是简单的Controller、Service、Dao三层,看起来非常简单。

    但是,随着代码越写越多,写久了以后,渐渐发现其实并没有把他们真正的职责区分开来,大多数情况下,Controller只是简单的调用Service中的方法,然后就返回;Service之间组合起来处理业务逻辑,甚至有时候Service页只是Dao层的一次简单透传转发。在项目庞大,追求快速发展的情况下,往往不会过于在乎这些细节,所以大部分人都觉得无所谓了,能用就行,久而久之,层级关系逐渐混乱,维护起来就会觉得挺头疼,而且后续如果要扩展业务功能的时候也无法复用。

    在很多人眼里,分层这个都无所谓的,新建一个项目的时候都是从一个项目拷过来,反正能运行就行,大家都是这么写,我也这么写就好了,先跑起来再说。

    然而每个人的习惯都不一样,有的人习惯在Controller中写一大堆业务逻辑,有的人习惯在Controller里返回Service层的调用,去改别人代码的时候就会很纠结,究竟使用什么风格好呢?特别是一些其他语言转过来的新手往往会疑惑,究竟Controller、Service、Dao这些的区别是什么?应该怎么布局代码呢?当看到代码里的Service大部分都是Dao的封装,就会觉得在Controller里面调用各个Service的方法来处理业务逻辑也是没毛病的。

    Read more...
  • Raft探索历程--Part2

    声明:本系列文章面向的读者需要看过Raft论文或者对Raft有一定的了解,如果没有看过论文或者不了解Raft,建议先去学习后再来看,否则会比较难懂。

    紧接着上一篇的内容,继续探索Raft的leader选举、日志复制、安全性等等实现细节。

    Raft基础

    一个Raft集群通常包含多个机器,比较普遍的Raft集群组成是2F+1,F代表的是可以发生失败的机器数量。比如集群有5台机器,那么Raft只能容忍两台服务失败,如果三台服务不能工作了,那么整个集群也就失败了。大多数Raft集群的机器数量都是5个。

    每台机器都有三个状态:leader、follower、candidate,如下图所示,就是三种状态之间的转换图。

    Read more...
  • Raft探索历程--Part1

    前言

    Raft是一个保证分布式系统数据一致性的共识算法,诞生的目的就是为了探索一种更容易理解的共识算法,原因是上一个描述这个算法的协议–Paxos较难理解和在生产环境上使用。(注:笔者没有掌握Paxos算法,所以这里不会去作比较,后续如果学习到的话会做一个比较)

    笔者主要是通过阅读Raft论文和观看MIT 6.824的教程视频学习的。

    论文原文是英文版的,里面的一些专用名词笔者打算尽量保留英文的描述,因为这些关键名词对于理解概念十分重要,但是翻译过来会比较拗口,也找不到合适的中文名词代替,所以打算保留英文的描述,当然,名词的含义还是有必要先解释一下。

    Read more...
  • 使用拦截器统一处理异常

    作为一个业务仔,在业务接口代码中肯定会遇到处理异常的情况,比如有代码逻辑的异常,业务逻辑的异常等等。这些异常场景是非常非常多的,这么多异常逻辑要处理,就意味着要写很多重复的代码,作为一个有点追求的业务仔,不能只是懂得CURD,当然希望代码看起来简洁、舒服一点。

    本文打算分享笔者处理异常情况的演进过程,然后给出统一异常处理的示例。

    一开始的方法是定义一个业务异常类,当捕获到业务异常时,使用异常的错误码和错误信息,构造错误提示返回。

    Read more...
  • 为什么需要分布式系统

    前言

    最近在学习MIT6.824的分布式系统课程,正在看Raft的论文,Raft是一种共识算法(Consensus algorithms),共识算法是用来保证分布式系统里数据的一致性的算法,所以也可以说是一个一致性算法。

    在学习这个课程的过程中,发现其实对分布式系统这个概念很模糊,好像知道是什么却又好像说不出来,不禁思考起来,究竟什么是分布式系统?为什么我们需要分布式系统?这个问题也许很简单,但是还是想通过自己的语言去表达,加深印象,希望我能阐述清楚。

    单机系统遇到的问题

    为什么我们需要分布式系统而不是单机系统呢?一个概念或者理论的出现,都是为了解决问题,单机系统遇到的问题是什么呢?分布式系统要解决的问题主要是单机系统中系统容量不足及提高系统可用性。

    Read more...
  • Mockito-提高单元测试效率利器

    前言

    之前在开发进行到写单元测试阶段的时候,发现要测试的方法里面是包含依赖的:外部接口RPC调用、DB调用。在某些情况下,部分依赖不稳定或者无法在测试环境调用时,会导致用例偶尔执行失败。

    另外一点,很多用例都是在测试用例的开头写了@SpringRunTest的注解,导致跑用例的时候会启动整个Spring容器,这样一来,运行测试用例就非常慢了。当在一些比较大的项目运行用例时,甚至达到了每次启动容器需要5-6分钟的时长,渐渐就有点受不了这种操作,每改一行代码心里都焦急,因为如果错了的话又要再等5-6分钟才能看到效果了。后来请教同事和上网搜索,找到了一种比较快且安全的方案,使用Mock框架–Mockito,学习并实践了一段时间,总结一下使用方法。

    Read more...
  • 理解Java8中的时间API

    在Java8之前,在Java开发过程中,如果要操作时间,是使用Date这个类,在Java8中新增了LocalTime、LocalDate和LocalDateTime,日期和时间的处理变得更加方便和容易。用了一段时间,刚开始每次用的时候都要上网查一波才能找到要的答案,后来认真看一下官网的API,发现也不是那么难理解,现在能够通过自己的理解找到自己想要的表达式,在这里做个小小的学习总结。

    为什么要有新的时间API

    既然Date类已经存在了那么多年,为什么要花那么大的精力去做这个改动?收益是什么呢?

    首先,因为Date类真的很难用,有很多过于Geek的设计,比如月份是从0开始,0是一月,11是十二月。好吧,我已经知道程序员是从0开始计数了,但是每次用的时候都要做各种转换,特别是跟其他输出端有交互的时候,改错一个地方就凌乱了。在新的APIjava.time里,这些都用常量表示了,不会用错,代码看起来也更加清晰。

    Read more...
  • 【总结】从0到1的项目经历

    去年7月底,接到公司安排,需要在一个半月内完成全新app的上线,需求文档与开发并行,由于时间紧迫,以及人力有限,当然就是享受了一次996,经历了之后,发现真是的是一次痛并快乐着的体验。这段时间加班稍微少了一点,趁假期写下这段经历的收获。

    经历了这么一波疯狂加班后,我总结了一些经验,希望能对自己以后的快速且稳定的开发节奏起到辅助作用,也希望能够帮到正在读这篇文章的你。

    注意,以下的所有建议,都是针对于没有按照正常流程走的创新性项目,不一定适用于已经稳定下来,需要按照正常流程开发的项目,当然有一些是可以借鉴的。

    Read more...