`
wbj0110
  • 浏览: 1585990 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

人人网中间层-系统架构(重要)

阅读更多

 

人人网中间层:问题篇

由开源软件组成的系统

与很多大型的网站一样,人人网的系统全部是由开源软件构建的。使用Nginx做前端接入,resin做容器,Memcached做通用cache,MySQL做数据库,使用Linux操作系统。
除了上述的部分外,人人网还有一个与众不同的中间层。中间层以服务的形式存在,位于MySQL和resin中间,提供高并发低成本的数据访问层。

数据库的压力

在上述结构系统中,数据库的性能往往成为系统瓶颈。人人网在发展的过程中不断重构,改变最大的就是数据库部分。大概的步骤是“优化SQL”,“业务拆分”,“垂直拆分”和“水平拆分”几个阶段,关于数据库优化的细节将来再引用到这里。
经过优化后的数据库,单台可以承担每秒3000次的主键查询。再提高性能的优化,我们采用的方案是使用中间层。

性能目标

增加中间层可以在不增加服务器数量的前提下,提高服务的整体性能,并且提高系统的可扩展性。这里简要列举一些使用中间层服务优化的效果。

实时更新的数据

用户的个人信息数据,目前的写操作500次/秒,读操作2万次/秒。这些数据分布在数十个数据表中,如果用数据库做10次主键查询,需要的时间将会非常可观。中间层的缓存服务把这个性能稳定在了99.9%的请求时间小于20ms。
判断好友关系,读操作900次/秒。这个操作现在使用6G内存存储了所有的好友关系,在2ms内返回任意两人的好友关系。
关联查询,仅好友列表就有1300次/秒。如果使用关联查询,数据库需要同步很多无用的字段。现在只需要两次内存请求,并且衍生出很多种类的排序。

大量聚合的访问

聚合的页面在SNS中是访问量最大的部分。首页集成的功能多达17个模块,这些模块之间的关系相对独立。为了快速的把这些数据集合在一起,就需要迅速获取数据。
我们对整体技术框架的要求是,关键页面执行时间要在100ms以内。

Session同步

众多的resin服务器之间,如何共享用户身份验证的结果,在各种session共享机制中,我们的方案是使用中间层服务来集中存储的。

待续

问题篇只是开端,接下来的“求解篇”将会分析人人网中间层的主要应用场景。“实践篇”将会举例一个典型的中间层服务。

人人网中间层:求解篇

为了提高性能,在人人网的技术结构中,在数据库和页面之间,有中间层。中间层高性能的基础是用内存代替磁盘。

用内存代替磁盘

数据库系统的最大瓶颈在磁盘IO,大量的小数据请求不是磁盘的强项。人人网中间层服务就是利用了内存代替硬盘的方法来提高整体性能。有了这层服务以后,以前的数据库关联查询被提前计算并缓存,需要访问时直接获取。
通用的Memcached缓存方案也有些不足,数据不能自己变化,也不能部分变化。于是人人网选择了自己实现缓存的方式。
在自己实现缓存的过程中,管理内存相对容易,通信协议是比较复杂的部分,我们在这方面选择了开源的Ice通信框架(http://www.zeroc.com)来完成繁琐的工作,至今它都工作的很好。
Ice 通信框架在人人网完成了两件事,通信和定位。客户端通过IceGrid组件定位到需要的服务地址,将请求发送到中间层服务,中间层服务将结果返回。客户端 只需要知道一个地址就可以找到所有的服务;同时,众多服务也可以在不同的服务器之间随意迁移。在现在的人人网有超过500个Ice写成的中间层服务在运 行。

定制的内存数据

用Ice解决了通信和部署的问题后,中间层服务就是核心的数据结构管理。概括的说,就是灵活变化,保证速度。下面列举若干使用了中间层服务的情况

一份数据 多种排序

在人人网的好友页,有很多排序方式可以显示好友列表。每种列表都是从一个按ID排序的服务中获取的,再经过排序,缓存在各个顺序的列表中。

随时间变化的数据

在很多列表页面,都会显示“在线标志”,这个标志是冗余在各个列表的缓存当中,定期刷新的。这些需要和cache一起实现的业务逻辑,在人人网中间层当中非常普遍。

特殊类型

我们用了一个bit保存用户的激活状态。200M内存可以保存全部int范围的状态。并且查询和更新速度飞快。
接下来的实践篇将会用这个为例子展示中间层的实现。

人人网中间层:实践篇

之前的问题篇和求解篇描述了人人网在发展过程中遇到的问题,并且介绍了我们采用中间层来提高性能的解决方案。今天的实践篇将通过一个例子来实现一个中间层服务。
这个服务要达到的目的是快速的查询用户是否有效,数据将要使用bitset保存在内存中,每个用户一位,仅保存正整数约21亿,占用内存256M。

开始编码

下面的代码都在这个位置保存:http://gitorious.org/renren/bitserver

接口定义

定义接口如下:

#include <Ice/BuiltinSequences.ice>
module renren {
struct BitSegment {
int begin;
int end;
Ice::ByteSeq data;
};
interface BitServer {
bool get(int offset);
Ice::BoolSeq gets(Ice::IntSeq offsets);
BitSegment getSegment(int begin, int end);
};
};

这个BitServer.ice文件,通过slice2cpp命令编译成为服务端的Skeleton文件:

slice2cpp -I/opt/Ice-3.3/slice BitServer.ice

服务端

有了上面生成的服务端文件后,就可以实现我们自己的业务功能了。
BitServerI.h和BitServerI.cpp,暂时只是实现了单个get的接口。

#ifndef __BitServerI_h__
#define __BitServerI_h__#include <BitServer.h>

#define SIZE_OF_BIT 2147483647
#include <bitset>

namespace renren
{

class BitServerI : virtual public BitServer
{
public:
void initialize();

virtual bool get(::Ice::Int,
const Ice::Current&);

virtual ::Ice::BoolSeq gets(const ::Ice::IntSeq&,
const Ice::Current&);

virtual ::renren::BitSegment getSegment(::Ice::Int,
::Ice::Int,
const Ice::Current&);
private:
std::bitset<SIZE_OF_BIT> bits_;
};

}

#endif

#include <BitServerI.h>
#include <Ice/Ice.h>int main(int argc, char** argv) {
int status = 0;
Ice::CommunicatorPtr ic;
try{
ic = Ice::initialize(argc, argv);
Ice::ObjectAdapterPtr adapter = ic->createObjectAdapter(“BitServer”);
renren::BitServerI* obj = new renren::BitServerI;
obj->initialize();
adapter->add(obj, ic->stringToIdentity(“BitServer”));
adapter->activate();
ic->waitForShutdown();
} catch (const Ice::Exception& e) {
std::cerr << e << std::endl;
status = 1;
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
status = 1;
} catch () {
std::cerr << “unknown exception” << std::endl;
status = 1;
}
if (ic) {
try {
ic->destroy();
} catch (const Ice::Exception& e) {
std::cerr << e << std::endl;
status = 1;
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
status = 1;
} catch () {
std::cerr << “unknown exception” << std::endl;
status = 1;
}
}
return status;
}

void
renren::BitServerI::initialize() {
for (int i=0; i<0xFFFFF;i=i+2) {
bits_[i]=true;
}
}

bool
renren::BitServerI::get(::Ice::Int offset,
const Ice::Current& current)
{
if(offset < 0) return false;
return bits_[offset];
}

::Ice::BoolSeq
renren::BitServerI::gets(const ::Ice::IntSeq& offsets,
const Ice::Current& current)
{
return ::Ice::BoolSeq();
}

::renren::BitSegment
renren::BitServerI::getSegment(::Ice::Int begin,
::Ice::Int end,
const Ice::Current& current)
{
return ::renren::BitSegment();
}

客户端

我们使用Java作为客户端,首先用slice2java工具生成Java的Proxy类。

slice2java -I/opt/Ice-3.3/slice BitServer.ice

然后自己实现客户端代码:

package renren;class BitServerAdapter {
private final String endpoints_;
private Ice.Communicator ic_;
private renren.BitServerPrx prx_;

public BitServerAdapter(String endpoints) {
this.endpoints_ = endpoints;
}

public void initialize() {
ic_ = Ice.Util.initialize();
prx_ = renren.BitServerPrxHelper.uncheckedCast(ic_.stringToProxy(endpoints_));
}

public boolean get(int id) {
return prx_.get(id);
}

public static void main(String[] args) {
BitServerAdapter adapter = new BitServerAdapter(args[0]);
adapter.initialize();
boolean ret = adapter.get(Integer.valueOf(args[1]));
System.out.println(ret);
System.exit(0);
}
}

性能测试

完成了代码,来测试一下性能吧。
首先启动服务器

target/bitserver –Ice.Config=config

再启动客户端

java -cp /opt/Ice-3.3/lib/Ice.jar:target/bitclient.jar \
renren.BitServerAdapter “BitServer:default -p 100001022

在客户端调用增加循环50000次,单线程平均每秒处理一万次。

在多线程的环境下,单个服务器每秒可处理的请求8万次左右,已经超过了目前的需要。

分享到:
评论

相关推荐

    大型系统架构 设计与优化 人人网网站架构-服务化与架构变迁 服务化的演进 共34页.pptx

    同时,他们也使用了开源的ICE框架,以实现完整的RPC架构和缓存等中间层功能,服务于如新鲜事儿等系统。\n\n**异构服务总线的挑战**\n\n在服务化过程中,人人网遇到了异构服务总线的问题。自建REST框架虽然灵活,但...

    人人网架构发展

    - 初始阶段,人人网可能采用的是传统的三层架构:表现层、业务逻辑层和数据访问层。这种架构简洁明了,适合小规模的系统。 - 随着用户量的增长,垂直扩展(增加服务器硬件)难以满足需求,于是转向水平扩展,通过...

    人人网技术架构介绍(人人网-黄晶)

    同时,开发了基于ICE的中间层,并对MySQL进行了垂直分区。2008年,人人网进一步采用开放API和SOA(面向服务架构),将MySQL集群进行水平分区,加强监控和安全性,并引入DFS和龙存架构,以提升存储能力。 到了2009年...

    新浪微博架构和FEED架构分析--人人架构1

    在第二版架构中,新浪微博进一步实现了模块化,将服务层拆分为多个独立模块,以提高系统的可扩展性和维护性。发布模块采用了异步处理,极大地提高了处理速度,而基础服务层则细化为独立的服务,便于优化和调整。 ...

    人人都是架构师+分布式系统架构落地与瓶颈突破+高清完整版

    人人都是架构师+分布式系统架构落地与瓶颈突破+高清完整版 本书并没有过多渲染系统架构的理论知识,而是切切实实站在开发一线角度,为各位读者诠释 了大型网站在架构演变过程中出现 系列技术难题时的解决方案。本书...

    人人都是架构师-分布式系统架构落地与瓶颈突破(高清完整版)

    本书适用于任何对分布式系统架构感兴趣的架构师、开发人员以及运维人员。 笔者尽量用通俗易懂的文字描绘本书的各个知识点,并引用了大量在实际工作中笔 者遇到的那些真实案例,相信阅读本书时你将会有知其然并知其...

    人人都是架构师+分布式系统架构落地与瓶颈突破.pdf

    《人人都是架构师:分布式系统架构落地与瓶颈突破》是一本深入探讨IT系统架构的书籍,旨在帮助读者理解和掌握分布式系统的设计与优化。书中详细阐述了如何从传统的单体架构过渡到分布式架构,并解决在这一过程中可能...

    物联网技术与应用-体系架构.ppt

    在物联网体系架构中,感知层、网络层和应用层三者之间的关系非常重要,三个层次的互相配合和融合,才能够实现物联网的智能化和自动化。物联网的发展和应用需要各个行业和领域的积极参与和推动,共同构建一个更加智能...

    人人开源框架renren-security-master(vue2版)

    人人开源框架renren-security-master(vue2版)

    飞行中换引擎--美团配送业务系统架构演化.27fd5270-7e52-11e6-9b91-73d05121ccd4.pdf

    文章作者阴永俊,具有丰富的IT行业经验,曾任职于海康威视、人人网,后加入新美大配送事业部,负责配送业务系统的建设和规划。 文章主要分为五个部分:目标与总原则、业务架构、系统架构演化、主数据架构演化以及...

    模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网

    模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网模仿人人网...

    .net经典书籍---人人都是架构师.rar

    《.NET经典书籍---人人都是架构师》这个压缩包文件主要涵盖了C#编程语言和软件架构设计的相关知识。其中包含了两个部分:一个是对C#版本EventBus事件总线的实例源码,另一个则是《人人都是架构师》这本书的电子版。 ...

    人人网工程师谈移动Web开发架构.pdf

    在人人网工程师的访谈中,我们可以提炼出以下几个关于移动Web开发架构的关键知识点: 1. 移动终端的发展趋势:移动终端经历了四个阶段的发展,从最初的功能终端,到智能化终端,再到互联网和平台化终端,直至目前向...

    人人可写微服务框架-SACC2021年中国系统架构师大会.pdf

    人人可写微服务框架-SACC2021年中国系统架构师大会

    人人网-2015-研发笔试卷A

    通过分析以上知识点,我们可以了解到人人网2015研发笔试卷A涉及了编程基础、数据结构、算法原理、系统设计等多个方面的知识。这对于评估应聘者是否具备软件开发工程师所需的基础知识和逻辑思维能力是非常有帮助的。...

    人人-Android客户端-高仿-源码

    【标题】:“人人-Android客户端-高仿-源码” 这个源码项目是对人人网Android客户端的高度仿制,旨在提供一个学习和参考的平台,帮助开发者深入理解移动应用的开发流程,尤其是社交应用的设计和实现。它包含了...

    分布式系统架构落地与瓶颈突破

    《人人都是架构师:分布式系统架构落地与瓶颈突破》适用于任何对分布式系统架构感兴趣的架构师、开发人员以及运维人员。相信阅读《人人都是架构师:分布式系统架构落地与瓶颈突破》你将会有知其然和知其所以然的畅快...

    Android 简单的人人网客户端源码-IT计算机-毕业设计.zip

    3. **网络请求**:为了与人人网服务器进行数据交换,项目可能使用了HttpURLConnection、OkHttp或Volley等网络库,了解这些网络请求库的工作原理和使用方法是Android开发中的重要技能。 4. **JSON解析**:服务器返回...

    人人网架构

    人人网架构发展 及人人网使用开源架构技术及特点。

Global site tag (gtag.js) - Google Analytics