项目二三事
1.在项目中使用Set<String>实例,在使用Set的contains方法时,在方法内部其实用到对象的hashcode和equals方法进行查找Set内部的数据结构,contains方法的参数是Object类型,在项目中误传入Long型数据,结构导致方法返回false,内部原因是String和Long的hashcode的计算方法不对所导致。这个地方的contains方法JDK可以泛型成contains(String str)就不会有这个问题了。
2.timeline的性能非常的低下,底层的架构采用了推和拉结合的模式,当用户的粉丝数大于500时使用拉模式,成为明星用户;结果在当前用户规模下有成百上千的明星用户;明星用户自己有自己的发送队列,当一个用户关注很多的明星用户时,在取到他的timeline的时候需要从多个明星队列和自己的推送队列中获取数据并且进行合并;当关注的明星用户过多的时候,这个归并排序非常的慢。
3.取得某人timeline的count的时候,也是因为需要进行第2点中的合并,所以性能非常的低
4.对于前面的性能问题,在不进行架构调整的情况下我们做了几点:1)多个单个信息的获取修改成批量获取,这个过程当中,可以减少N-1的网络传输,虽然说批量取数据返回的数据量非常的大,但是测试发现一次大数据量的传输时间远小于多次小数据量传输时间(当然这个数据量的传输还没有到达宽带的上限),此点修改性能提高了20%左右。2)对外部系统的调用,项目会调用外部系统的服务,一定要把外部系统看成是不稳定的因素,减少对外部系统的调用,特别是减少对外部系统的无畏调用,timeline中发现对一个外部系统的相同服务调用了3次,之所以发生这个问题,是因为项目经过多次升级,多个人员经手过,再去掉重复调用后,性能又提高了15%左右。3)不要写愚蠢的代码。第1点就是愚蠢的代码,其他的比如死循环;两次的单层循环写成了一个双层循环等待。
5.对于第2点和第3点,第2点如果是个千万级用户+上万明星用户+有超级明星用户(几万粉丝?几十万粉丝?),那么推+拉的架构过于复杂,如果关注的明星用户数过多的话,归并会非常慢,第3点中,count数应该单独设计成计数器,免去计算的开销,对于计数器和真正timeline条数间数据差异可以通过异步进行更新订正。所以后续应该会进行架构上面的调整。
后续架构猜想
后续可能继续使用推+拉模式,也许会抛弃推+拉的模式,这个模式还有改进的空间,比如:
1)将拉的门槛提高,这个明星用户数会减少,不过到最后还是会有很多的明星用户
2)将明星用户按照发送feed的时间从最近到最远放在优先队列里面,这样一个用户关注的明星用户列表和此队列进行对比,将能去除掉很多不需要归并的明星feed队列(因为这些明星用户在上次查询之后没有新的feed产生),在feed最后归并完成以后放入缓存,不过当用户再次查询的时候,缓存就失效了
待续。。。。