【转】足记火了,难掩创业者技术之殇

【声明】本文为转载文章,原文链接为 http://luochao.baijia.baidu.com/article/51078

第一次在朋友圈看到分享自足记的图片,是3月10日,这也是我第一次听说这款应用。现在朋友圈已满是足记,这款上架超过半年的App借助“大片”这个小功能,一夜爆红。足记没有时间去回答外界提出的“是否会成为下一个脸萌”“爆红之后如何保持用户粘性”这样的问题,它有更现实的问题要解决:技术问题随着海量用户的涌入浮出水面。正在面对或者即将面对技术问题的,却不只是足记。

突如其来的幸福,足记的技术短板浮出水面

百度指数显示足记关注度已有所下降,不过它依然坚挺在App Store免费榜,截止目前已拥有超过1千万累积下载,上周末DAU(日活跃)达到300万。足记面对着突如其来的幸福,用措手不及来形容并不过分:App出现了卡死、闪退、服务器忙、数据丢失诸多问题,足记一边通过微博、微信、通告等方式向用户致歉,一边求助外部技术高手。

足记办公室周末临时增加了一个由金山云、青云、阳光云三家云服务商组建的攻坚团队,如果没有这个团队恐怕足记早已宕机。金山云VP、技术负责人朱桦带着团队从北京飞到上海,被足记创始人杨柳委托为代理CTO,负责技术攻坚。在朱桦看来,300万DAU这个数据并不算太高,

“压力其实没有大到夸张,不过原来的技术架构确实是太脆弱”
足记一直只有3个研发,两个负责App,负责服务端的半个人,还要负责数据库、运维,没有CTO,足记甚至没有测试环境。

用户基数庞大的中国市场,一款App要日DAU超过1亿,才算一线应用,现在有微信、手Q和UC;5000万是一个坎,手机百度、新浪微博、手机淘宝、猎豹移动入围;1000万是一个坎,能进入的用户数大都已过亿。

足记300万DAU确实不算高,但这个数据还在不断膨胀。与脸萌等工具型应用不同,足记是内容压力都在云端的社交应用。寻找技术合伙人,组建能够驾驭DAU千万级的技术团队,是杨柳的当务之急。在朱桦离开上海前,帮助足记梳理架构、制定研发技术,还有一个临时任务便是帮着足记物色合适技术。

一夜爆红,能够拥有足记式幸福的烦恼的创业者并不多。不过,技术却是创业团队面临的普遍问题。

技术是创业拦路虎,技术合伙人重要性越来越高

“我有一个改变世界的想法,就差一个帮我实现的程序员了”,这句话描述了互联网创业圈的现状,创业启动最大的难题不是钱,而是人,尤其是技术。创业团队需要的不是战略型人才,而是能够干活,能够将产品实现的执行者,至关重要的便是技术合伙人,没有技术合伙人的团队,不是完整的创业团队。

因为资源所限,普通创业公司很难搭建一个齐备的技术团队,需要的是独当一面的多面手,最好还有技术团队管理经验、有猎取优秀技术人才的能力。

这样的人才本来就很稀缺,大都已被BAT的优厚待遇所吸引,BAT们人才争抢激烈,不断抬升技术人员价值,猎头服务商甚至已将电话打到明星创业团队的技术。创业公司如何跟大公司抢人?钱、福利、平台都拼不过,期权?项目必须有足够的前景,期权才有价值。而且,还有一些堪当技术合伙人的已经自己走上创业之路。

如果在北京、深圳、广州和杭州几个城市还好点,因为中国互联网产业集中在这里。如果在别处,更不容易。负责帮助足记物色技术人才的金山云VP朱桦表示,

相比北京,上海招聘难很多,社交业务有着更高的架构要求,要具备一定经验的架构师才能扛下来。
上海是中国移动互联网的荒漠,具备大规模WEB架构经验的技术人才凤毛麟角。

不少有想法的“准创业者”,都卡在找不到技术合伙人这一关。通过外包来解决这个问题?迄今为止都没看到过一个通过外包技术取得成功的互联网创业项目。更多创业者是像足记这样,找到App开发或者网站开发,走出第一步再说,产品是做出来的,而且还可能天上掉馅饼一夜爆红,但技术上的问题却依旧存在,“重要的事情不做,终有一天会成为紧急”。

有野心的团队,都会按照自己某天会“一夜爆红”去做技术上的规划和投入。

技术投入是互联网公司的长远投资,最后1美元留点给技术

对于一个创业团队而言,技术投入除了人才之外,还有IT资源投入。云计算这几年已经走向成熟,IaaS平台越来越多,创业者不再需要购买服务器等昂贵的基础设施,而是按需扩容云计算资源。金山云、阿里云们财大气粗,为了圈地投入资源扶持创业者,导致云计算成本更低、服务更好、内容更多。

脸萌爆红之后曾有报道指出,这个团队每个月花在IT基础设施上的成本只有79元。脸萌只是一款工具,上传、社交这些功能很少,并没有太大的计算和存储资源需求。在线游戏App、足记这样的围绕图片的社交App,却不是一回事。足记日PV高达2亿,海量图片需要存储在云端,服务器、存储以及带宽的资源需求日益壮大。总之云计算降低了成本,但整体支出绝对值巨大,在没有规模营收时,会成为团队巨大的压力。

朱桦认为,创业团队要节省IT成本又要有扩展性,必须选择IaaS。不少创业团队已经有这个意识,不过却只使用虚拟主机,没有用到CDN、Redis、负载均衡这些上层服务。IaaS不等于基础设施租用,服务商还可提供上层服务和技术支持。其建议创业团队务必重视服务端,技术架构的弹性程度,优雅程度,决定着产品的迭代效率和运营活动的支撑力度。技术上的投入不能省,如果足记在海量用户涌入还可保持稳定流畅,留存的用户可能更多。

互联网公司不论大小都会权衡着技术的投入产出。百度是其中的激进者,2014年投入70亿元,占营收比例14.2%,Google和苹果对应的数字是13.3%和2.6%。不一定是投入越多越好,而是结合自身业务属性权衡。技术投入不会马上见效,可能还会成为负担,不过如果技术投入不足,问题迟早会暴露。携程等网站出现用户数据泄露、电商网站遇到促销活动频繁宕机,根源都可归结到技术。阿里巴巴在技术上大规模投入,不只是可以支撑双十一这等规模的活动,还可以将资源腾挪出来通过云业务利用起来。

创业公司的钱就像子弹,打出去就不会回来了,都是一分钱当两分花。因此虽然都知道技术投入的重要性,很多时候却有心无力。不过,有的技术投入却是怎么也不能省的。投资人徐小平前段时间说,创业公司要把最后1美元花在PR上,恐怕还得腾出一半,花在技术上。

留下评论

CSDN专栏文章

应CSDN云计算专栏邀请发表了文章。文章链接:http://www.csdn.net/article/2015-03-16/2824218

best online casino

发表在 Gleasy团队 | 留下评论

Cloudfs一致性问题分析及解决

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

问题产生的背景
格子云自有的分布式文件系统(参见文章分布式文件系统Cloudfs)线上运行2年时间,经受住了各种使用场景的考验。但也暴露出了一些问题,问题之一为,同一group内的结点数据存在少量不同步情况(100万文件中,大概有1个文件,错误率为1:100万),当服务器结点故障时,该问题就会出现,该问题的本质原因是由于cloudfs的同步机制为基于操作序列的异步同步,当服务器异常时,可能会出现同步故障而不会通知,参见文章基于操作序列的一致性机制对分布式系统设计的意义

问题解决
每个结点都记录当天生成的物理文件(并写入LOG).
引入dfs-cron工具,每天凌晨运行一次,向group内其它结点前一天产生的新文件做一次主动的全量检测,遇到未同步的文件,则强制同步一次。如果强制同步失败,则产生报警(通知nagios,并以邮件和短信通知运维人员)。
通过被动同步 主动检测 人工干预三种方式结合,有效避免了文件不同步的情况,使cloudfs的一致性无限接近100%。但又不会丧失自身高性能的优势。

online casino

发表在 Java技术, 分布式技术, 数据库技术, 运维 | 标签为 , , | 留下评论

一种redis主主解决方案及其实现

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

问题的提出
redis(特指2.8.14及以下)replication仅支持主从复制。在实际生产环境中,这种单向主从复制,没有办法做高可用(当然,如果允许数据丢失的话,可以采用keepalived,采用其notify_master/notify_slave机制,强制实现主从的角色互换,这种方式对主从强行互换的过程中,如果存在未同步的数据,将会彻底丢失,是一种极其危险的方案,用于生产环境是不可取的)。
所谓他山之石,可以攻玉。mysql提供成熟的主主复制,结合keepalived动态IP,可以做到两个结点同时准备(ready)提供服务,任何一台挂掉的时候,另一台立刻无缝接管。当挂掉的那台启动之后,未同步的数据还会继续同步过来,最大限度保证数据不丢失。当然这种方案也并非100%一致,因为当挂掉结点起来之后可能存在操作续列的先后顺序问题从而造成数据少量不一致,未同步的数据越多,不一致的可能性越大,但在生产应用中,这种方案已经可以最大限度保证高可用性,而且对一致性影响并非特别严重,因此该方案被广泛采用。
借鉴MYSQL的经验,要实现redis的高可用,首先要解决主主复制问题。Gleasy最初实现了一种基于代理机制的redis集群方案,用于解决这个问题,可以参考这篇文章《Gleasy的NOSQL数据库集群Cloudredis》。这个集群方案在生产环境中工作一段时间,就暴露出了一个问题,集群内的结点,无法做到数据完全一致,不一致的地方存在于那些已经过期的key(设置了expire,并且到期)。redis的key失效机制分为主动失效和被动失效,而主动失效每次仅随机失效很小一部分,当过期的KEY数量庞大时,在相当长的时间内,这些过期的KEY会一直存在,而集群内所有结点都会随机失效一部分,从而导致这些结点失效的KEY不一样,最终反映出来的结果就是数据不一致,而这种不一致,会对运维工作造成极大的困惑,因为不知道到底是由于同步机制异常还是由于KEY失效引起,从而令到运维人员时时如履薄冰,坐立不安。最终决定,另外提供一种机制实现真正的redis主主复制。

实现原理
1. 概述
在每个redis结点上安装一个模块(我们称之为集群模块),它可以获取该redis结点所有的写操作命令序列;
集群模块获取redis结点的所有写操作序列,并将之写入binlog文件;
从结点的集群模块定时向主结点的集群模块请求binlog块,并记录上次请求的位置,下次请求的时候,接着上次的位置获取;
从结点的集群模块拿到binglog块,分析出写操作序列命令,在从结点redis中执行。
下面是单向复制的结构图(双向复制其实就是两对单向复制a->b,b->a):

2. 具体实现
集群模块以一个独立的应用存在,取名为rediscluster(之所以做成独立的进程,一是为了性能更好,避免加入redis的单线程事件机制中,二是避免过多修改redis源码从而导致升级不便);
rediscluster监听独立的端口,rediscluster之间通过访问互相之间的独立端口进行通信;
每个redis结点对应一个rediscluster,rediscluster启动后,作为redis的slave,实时接收所有写操作命令序列;
rediscluster启动一个独立的线程,定期访问主结点rediscluster的端口,获取binlog数据;

3. 一些技术关键点
3.1 一致性保证及技术实现
通过以下约束来保证一致性:
a. rediscluster未准备就绪的情况下(即未能正确接收操作命令并写入binlog),redis不能接受写操作.即binlog写不成功,就不提供写操作服务。
实现 :设置redis的min-slaves-to-write参数为1,将保证了至少有一个slave工作良好情况下才允许写入
b.从结点的redis不开启过期key的主动失效功能,只有主结点才开启过期key的主动失效功能
实现:rediscluster接收到binlog,则关闭redis的主动失效功能;rediscluster接收到来自redis的写命令,则开启redis的主动失效功能;
c. 主结点和从结点不允许同时写(一方写,另一方自动变成只读)
实现: rediscluster接收到binlog,则屏蔽redis的写操作;
d. slave收到的主结点的写命令,不再发送给rediscluter。
实现:rediscluster发送binlog off命令给redis,之后接收到binlog,写入redis,redis将不会发送给slave。
e. 所有命令加上服务器唯一标识,避免死循环。
实现:rediscluster写入binlog文件时,加上本服务器的唯一标识。当形成主从环时,根据该唯一标识,忽略自己生成的binlog,只消费别人生成的binlog.

3.2 对redis的改造
a. 开启/关闭主动失效功能
引入命令 online casino backup on/off来关闭/开启该功能

b. 屏蔽写操作
引入命令 lock on/off来屏蔽/解除屏蔽写操作

c. 开启/关闭该连接的binlog功能
引入命令binlog on/off来开启/关闭当前连接的binlog功能(关闭后,由该连接发出的所有写操作,将不会发给slave)

c. 特殊连接无视lock功能
引入命令cluster来开启当前连接的无视lock功能(开启后,由该连接发出的所有写操作,将无视lock,即不管lock=on还是off,都可写)

问题的解决
此方案真正实现了redis的主-主复制,配合keepalived,可以很好地实现高可用。
此方案由于采用binlog的方式进行数据同步,断线后,或者重启后,都可以从上次的位置继续同步,完全规避了redis主从首次全量同步的方式,从而也规避了海量数据时,redis主从同步导致IO,CPU,带宽狂升的问题。
经笔者实测,此方案开启主主复制情况下,对redis性能无明显影响(10次对比性能差异几乎可以忽略不计【差异小于3%,考虑到测试的精确度,几乎可以忽略】);
rediscluster为单独应用,自主升级;源码暂不开放。
redis源码修改不超过20行,日后redis升级无障碍;源码在此redis-2.8.14; 也可以通过github下载,地址为redis-2.8.14 gleasy master-master

运行截图

binlogs示例


rediscluster配置文件


rediscluster运行时信息
联系作者
对本文有兴趣,有想法的,不解不满等。。欢迎赐教交流。
邮箱:xueke@gleasy.net
qq:99103622

发表在 Java技术, 分布式技术, 数据库技术, 运维 | 标签为 , , , , , | 留下评论

大型WEB应用性能调优总结

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

问题初级定位方法: 一感三看
一感,凭个人感觉,操作不流畅,有挫折感肯定有问题。
三看:
一看ajax请求的执行时间,网络条件好的情况下,超过400MS的肯定有问题;
二看静态内容(html,图片,js,css)等是否cache,没有cache肯定有问题;
三看同一个ajax请求的数量,如果连续有N个(N>3)以上同一个AJAX请求,肯定有问题;

问题深入定位方法
方法一:使用stopwatch,在程序中植入log记录执行时间,通过查看执行时间以定位出问题的代码段;
方法二:间隔重复可疑操作,观察记录CPU变化情况。用以观察是否有死循环或者大规模遍历。
方法三:恶意快速重复点击同一个功能按键20次,观察是否会重复发起后端请求20次,如果是,那么,也是有问题的。
方法四:使用SQL监控(druid)来观察每一个SQL执行次数,执行时间,从而发现热点问题

应用技巧
NO1. 弱化数据库
1.将数据库弱化为“存储”,避免使用数据库查询能力,尽量使用主键或唯一键进行精确读取动作,数据量不太大的表可以使用普通索引进行精确读取,避免使用范围查询(> < != between in),禁止使用like,禁止使用子查询,联合查询,exists查询;
2.范围查询和like查询,一律使用索引平台CloudIndex替代;
3.子查询,联合查询,exists查询:一律在应用层进行逻辑拼装(如果数据量太大,可以使用Map-Reduce进行多线程计算,如果再大可以使用cloudjob进行分布式调度)

NO2. 善用缓存
1.提高缓存命中率为终极目标;
2.容易忽视的缓存问题:大量访问己被删除数据,由于数据不存在,缓存肯定不命中,导致频频访问数据库;解决方法是对己删除的数据做特殊缓存标记;
3.对写入性能要求极为苛刻的场景可以使用redis缓存-存储切换的方式进行异步写入:写入redis(标记为存储),立刻返回,另起独立线程将写入数据同步至数据库,同步成功之后,将redis中相应数据标记为缓存。

NO3. 用好中间件
1. 对于写入性能要求苛刻(或写入并发量特别大的)且允许写入延迟的情况,使用CloudMQ中间件;比如发邮件,发微博,发留言等;
2. 定时任务(比如定时发送邮件,定时提醒),特别适合使用CloudJob中间件
3. 对于消耗性任务(比如执行时间长且任务量大,消耗CPU资源),可以使用CloudJob进行分布式任务调度,将众多大任务放到N台后台机器上执行;

NO4. 批量操作(从前端到后端)
1. 前端批量,针对大量重复调用某一接口的情况,由于AJAX的异步性,可以将N个请求合并成一个请求,串行执行AJAX,策略如下(伪代码):

var getDepartmentLinkByUid = function(uid,callback){
  if(loading){cache.push({uid:uid,callbackup:callback}); return;}
  loading = true;
  realGet();
}

var realGet = function(){
 var tmp = cache.splice(0);
 $.ajax({
    data:由tmp的uid拼接而成,
    success:function(dt){
      for(var i=0;i<tmp.length;i++){
        var uid = tmp[i].uid;
        var rdata = dd[tt];
        tmp[i].callback(rdata); 
      }
      if(cache.length>0)  realGet();
    }
  });
}

 

2. 缓存批量(承接上面的例子)

 objects = mget(uids);
 notcached = new ArrayList();
 for(uid:uids){
  if(objects 不包含uid) notcached.add(uid);
 } 

 

3. 数据库批量查询(承接上面的例子),批量更新缓存

 notcachedData = select * from department where uid in (notcached列表);
 mset(notcachedData 生成的 map);

 

发表在 Java技术, 分布式技术, 前端技术, 数据库技术 | 标签为 , , , | 留下评论

DELL R410 R310服务器在CENTOS6系统下网卡问题

一。问题引出
GLEASY网站流量大的时候,每隔几天,网卡就会自动DOWN掉,必须手工去启动。
网卡DOWN掉,立刻引发虚拟IP漂移;
最悲剧的是内部网卡DOWN掉,外部网卡还在,虚拟IP漂移的结果是两台服务器同时配上了外网IP,必须手工重启KEEPALIVED。
在这个过程中,就存在着服务中止。非常影响用户使用。

二。问题解决
由于服务器采用的是R410 CENTOS6.0,上网一搜,很多人反映有此问题,原因是CENTOS的网卡驱动对R410网卡支持不好,解决方法就是更新驱动。
1. 从QLOGIC下载最新网卡驱动
地址为:http://driverdownloads.qlogic.com/QLogicDriverDownloads_UI/SearchByProduct.aspx?ProductCategory=336&Product=1245&Os=175

比如我下载的为:linux-7.10.12.zip

2. 安装
#yum -y install gcc mack kernel-headers kernel-devel rpm-build
#unzip linux-7.10.12.zip
#cd Server/Linux/Driver
#rpm -ivh netxtreme2-7.10.12-1.src.rpm #解压出包源码
#rpmbuild -bb /root/rpmbuild/SPECS/netxtreme2.spec
#rpm -ivh nbso online casino reviews /root/rpmbuild/RPMS/x86_64/netxtreme2-7.10.12-1.i386.rpm

3. 切换驱动
vi change_driver.sh
rmmod bnx2
modprobe bnx2
#chmod 755 change_driver.sh
./change_driver.sh & #执行脚本(用SSH,一定要用后台执行)

4.核实更新后当前驱动版本:
modinfo bnx2 #或直接ethtool -i eth0 可以查看到固件版本

发表在 运维 | 标签为 , | 留下评论

开源之殇

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

问题的提出
最近被一些非专业的朋友问及关于使用开源快速建立产品的问题,因此开此文全面阐述一下我个人的理解。

使用开源有风险
前提:这里的开源产品,特指业务关联度高的中间件产品(比如分布式文件系统,消息队列中间件,即时通讯服务器,任务调度中间件,检索系统等)。
最大的风险来自两方面:1. 使用过程中发现后续需求不满足 2.线上遇到BUG或者问题
1. 使用过程中发现后续需求不满足
新项目来了,需求方又把时间期望压缩得厉害(这是所有需求提出人的共同特质),于是在技术选型时,自然而然就会有“不要重复开发轮子”这种朴实的想法,于是在开源世界是寻找解决方案。毕竟开源的东西看上去真的很美,现成可用,节省开发时间,节省人力成本。。。
好吧,仓促之下,决定选择某间公司的开源解决方案。
下载,打包,学习教程,配置集成;
研发过程中不断发现开源的中间件产品过多保留了开源厂商的影子(比如一些特定的使用习惯和使用场景),这些功能本身与自己所需要的一点关系都没有,但是没办法,多余的东西能不用就不用,忍忍吧;
基础功能满足了,项目上线了。。
使用一段时间,需求方或者用户提出一些新需求,分析之下,发现底层的开源中间件不提供这能力,于是悲催了。。。

2. 线上遇到BUG或者问题
需求不满足,倒是不紧急,毕竟可以对用户说我们还在计划中。
但是如果遇到系统故障,查明原因发现是来自底层中间件。。。该如何办呢?
更何况如果你的客户是企业用户,他们每天都在使用你的系统进行工作相关的内容,十万火。。。感觉更加悲催了!

3. 遇上以上问题怎么办呢?
向开源提供者发邮件,请求加入开发计划,然后就是漫长的等待。。。。。。
一周两周,一个月两个月。。。。需求就这么被无限地搁置?
实在受不了了,开始研究源码,自力更生!
于是开始读代码,可恨的是开源的产品多数没有清晰的注释,更不提设计思想指引了。。
艰难地进行中,一天两天,一周两周,复杂的中间件如分布式文件系统,几万行甚至十几万行代码。。。
终于搞清楚了代码结构,准备开始着手修改!
改一点东西,发现牵一发而动全身,于是越改越多。。。。
终于有一天,突然发现,已经改得面目全非,完全不是之前开源产品的样子了,
霍然回首,醒悟过来,当初为何不借鉴其思想而自行定制研发,我研发出来只适合自己的中间件也不需要这么多时间和精力啊!搞到现在天翻地覆,自己的需求也没能完美满足,还有一堆自己不需要的东西去维护,欲哭无泪啊!
于是痛下狠心,决定推倒重来,按照自己产品的思路重新研发最适合自己的特有中间件。。。

选择开源要谨慎
基本使用开源中间件的公司在产品做到一定规模一定会遇到上面提到的风险和问题,大多数公司的选择也是一样,推倒重来,重新开发适合自己的中间件。比如淘宝,比如新浪,比如TWITER。相同的功能大家做了又做,不是炫耀自己有多牛,而是逼不得己。
但并不是所有的开源都是洪水猛兽似的,通用性工具类的,特别是经过了大公司长时间验证过的通用性工具,是可以选用的,比如MYSQL,ZOOKEEPER,NGINX,HAPROXY,OPENFIRE,SOLR,KEEPALIVED,LIBEVENT,MINA,NETTY,TOMCAT,APACHE,LUCENE,REDIS,MONGODB,MEMCACHED等等等等,是可以放心去选用的,前提是要对这些产品的配置和优化有充分的理解。

best online casino

发表在 C/C++, Java技术, 分布式技术, 数据库技术, 运维 | 留下评论

Gleasy高性能服务器c开发库-minac

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

背景
Gleasy部分高性能中间件(比如分布式nosql集群cloudRedis,使用JAVA),经过线上一段时间的验证,发现在CPU占用方面始终偏高,而且nosql集群本身并无复杂的业务逻辑,多数情况下都是直接PROXY到后端的redis。出于对性能的的严苛要求,决定使用C对cloudRedis进行重构。在重构的过程中,由于cloudRedis的java版基于mina2,特别是codec环节大量依赖于IoBuffer和IoSession这两个类,确实十分好用。因此衍生出来使用c语言实现完整的mina2接口的想法,借鉴MINA2本身的优秀设计,避免了很多弯路,最终实现了一套完整的开发库,为了对mina2致敬,取名为minac。

minac介绍
minac基于epoll,使用event-loop-per-thread结构,IO thread个数默认为Cpu的核数。
熟悉mina2的同学基本上拿过来就可以直接使用,没有任何学习成本。
以下是提供的一些基本类库
1. iobuffer
完整实现了java的IoBuffer类,所有方法跟java版兼容(所有写入buf的基本类型会被被转换为big endian的,读出时会转换回系统支持的endian模式)提供了以下方法:

extern iobuffer_t *iobuffer_create(int32_t);
extern void iobuffer_destroy(iobuffer_t *);
extern void iobuffer_set_auto_expend(iobuffer_t *,int flag);
extern void iobuffer_set_auto_shrink(iobuffer_t *,int flag);
extern void iobuffer_set_increment(iobuffer_t *,int32_t);

extern void iobuffer_flip(iobuffer_t *);
extern void iobuffer_compact(iobuffer_t *);
extern void iobuffer_clear(iobuffer_t *);
extern int32_t iobuffer_set_position(iobuffer_t *,int32_t);
extern int32_t iobuffer_get_position(iobuffer_t *);
extern int32_t iobuffer_set_limit(iobuffer_t *,int32_t);
extern int32_t iobuffer_get_limit(iobuffer_t *);
extern void iobuffer_skip(iobuffer_t *,int32_t);

extern int32_t iobuffer_remaining(iobuffer_t *);
extern int32_t iobuffer_put_int(iobuffer_t *,int32_t);
extern int32_t iobuffer_get_int(iobuffer_t *,int32_t *);
extern int32_t iobuffer_put_double(iobuffer_t *,double);
extern int32_t iobuffer_get_double(iobuffer_t *,double *);
extern int32_t iobuffer_put_long(iobuffer_t *,int64_t);
extern int32_t iobuffer_get_long(iobuffer_t *,int64_t *);
extern int32_t iobuffer_put(iobuffer_t *,char *,int32_t);
extern int32_t iobuffer_get(iobuffer_t *,char *,int32_t);
extern int32_t iobuffer_put_by_read(iobuffer_t *,int fd,int32_t);
extern int32_t iobuffer_get_and_write(iobuffer_t *,int fd,int32_t);
/**
 * 从src中获取内容写入另一个dest
 * 注意:此函数不支持src和dest为同一个iobuffer的情况
 */
extern int32_t iobuffer_put_iobuffer(iobuffer_t *dest,iobuffer_t *src);

 

2. iosession
实现了mina2的IoSession基本功能,主要接口如下:

extern iosession_t *iosession_create(int connfd, mina_session_config_t *sessionConfig);
extern void iosession_destroy(iosession_t *session);
extern int iosession_write(iosession_t *session, iobuffer_t *buf);
extern int iosession_write_wait(iosession_t *session, iobuffer_t *buf,int seconds);
extern int iosession_close(iosession_t *session);
extern int iosession_flush(iosession_t *session);

 

3. socket_acceptor
实现了mina2的IoSocketAcceptor类,主要接口如下:

extern mina_socket_acceptor_t* mina_socket_acceptor_create();
extern void mina_socket_acceptor_destroy(mina_socket_acceptor_t *acceptor);
extern int mina_socket_acceptor_bind(mina_socket_acceptor_t *acceptor,struct sockaddr_in *addr);
extern void mina_socket_acceptor_unbind(mina_socket_acceptor_t *acceptor);

 

4. socket_connector
实现了mina2的IoSockectConnector类,主要接口如下:

extern mina_socket_connector_t* mina_socket_connector_create();
extern void mina_socket_connector_destroy(mina_socket_connector_t *acceptor);
extern nbso online casino reviews  iosession_t *mina_socket_connector_connect(mina_socket_connector_t *acceptor,struct sockaddr *addr);
extern void mina_socket_connector_stop(mina_socket_connector_t *acceptor);

 

5. socket_handler
实现了mina2的IoSocketHandlerAdaptor,定义如下:

typedef void (*_messageReceived)(iosession_t *,iobuffer_t *);
typedef void (*_messageSent)(iosession_t *,iobuffer_t *);
typedef void (*_sessionCreated)(iosession_t *);
typedef void (*_sessionOpened)(iosession_t *);
typedef void (*_sessionClosed)(iosession_t *);
typedef void (*_exceptionCaught)(iosession_t *,mina_exception_t *);
typedef void (*_sessionIdle)(iosession_t *,mina_iosession_idle_t );

typedef struct mina_socket_handler_t{
	_messageReceived messageReceived;
	_messageSent messageSent;
	_sessionCreated sessionCreated;
	_sessionOpened sessionOpened;
	_sessionClosed sessionClosed;
	_exceptionCaught exceptionCaught;
	_sessionIdle sessionIdle;
}mina_socket_handler_t;

 

6. session_config
实现了mina2的SessionConfig,主要接口如下:

typedef struct mina_session_config_t{
	int readBufferSize;
	int minReadBufferSize;
	int maxReadBufferSize;
	int writeBufferSize;
	int minWriteBufferSize;
	int maxWriteBufferSize;

	int tcpNoDelay;
	int sendBufSize;
	int revBufSize;

	int readerIdleTime;//time in sec
	int writerIdleTime;//time in sec
}mina_session_config_t;

extern mina_session_config_t *mina_session_config_create();
extern void mina_session_config_destroy(mina_session_config_t *);

 

7. 使用例子:
用几句代码就轻松实现服务器程序:

#include "minac.h"
#include "common.h"
#include <zlog.h>

static void messageReceived(iosession_t *session,iobuffer_t *buf){
	//dzlog_info("接收到一行,size:%d",iobuffer_remaining(buf));
	int32_t remaining = iobuffer_remaining(buf);
	if(remaining>0){
		iobuffer_t *rbuf = iobuffer_create(remaining);
		iobuffer_compact(rbuf);
		iobuffer_put_iobuffer(rbuf,buf);
		iobuffer_flip(rbuf);
		iosession_write(session,rbuf);
		iobuffer_destroy(rbuf);
	}
}

static void messageSent(iosession_t *session,iobuffer_t *buf){
	//dzlog_info("写了数据,size:%d",iobuffer_remaining(buf));
}
static void sessionClosed(iosession_t *session){
	//dzlog_info("session is closed.%d",session->connfd);
}
static void sessionOpened(iosession_t *session){
	//dzlog_info("session is opened.%d",session->connfd);
}
static void exceptionCaught(iosession_t *session,mina_exception_t *exception){
	dzlog_info("exception met, code:%d, messag:%s",exception->errorCode,exception->errorMessage);
	iosession_close(session);
}
static void sessionIdle(iosession_t *session,mina_iosession_idle_t idleType){
	//dzlog_info("session idle, fd:%d, idleType:%d",session->connfd,idleType);
}
static void exit_handler(void *arg){
	mina_socket_acceptor_t *acceptor = (mina_socket_acceptor_t *)arg;
	mina_socket_acceptor_unbind(acceptor);
}
extern void test_acceptor(){
	mina_socket_acceptor_t *acceptor = mina_socket_acceptor_create();
	acceptor->sessionConfig->tcpNoDelay = 1;
	acceptor->sessionConfig->readerIdleTime = 2;
	acceptor->sessionConfig->writerIdleTime = 2;

	acceptor->socketHandler->messageReceived = messageReceived;
	acceptor->socketHandler->messageSent = messageSent;
	acceptor->socketHandler->sessionOpened = sessionOpened;
	acceptor->socketHandler->sessionClosed = sessionClosed;
	acceptor->socketHandler->exceptionCaught = exceptionCaught;
	acceptor->socketHandler->sessionIdle = sessionIdle;

	register_exit_handler(exit_handler,(void *)acceptor);

	struct sockaddr_in servaddr;
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(6666);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

	mina_socket_acceptor_bind(acceptor,&servaddr);
}

 

熟悉mina2的人,基本上对上面的代码极为熟悉了。

性能如何
功能上面是好用了,性能如何呢?以echo server为例,性能测试结果如下:
1. 实验1(400客户端)

400并发客户端,TPS最大41万,平均18万,CPU占用164%

2. 实验2(1000客户端)


1000并发客户端,TPS最大55万,平均30万,CPU占用169%

根据笔者对epll,libevent,mina2测试的结果,参见文章高性能网络服务器选型比较(EPOLL/Libevent/JAVA mina2),minac在性能上的表现基本上和epoll原生态持平,CPU占用低于libevent,远远低于mina2,说明我们并没有犯低级错误。

联系作者
对本文有兴趣,有想法的,不解不满等。。欢迎赐教交流。
邮箱:xueke@gleasy.net
qq:99103622

发表在 C/C++ | 标签为 , , , , , | 留下评论

高性能网络服务器选型比较(EPOLL/Libevent/JAVA mina2)

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

起因
网上很多关于高性服务器选型的观点,也有很多争议,比如C和JAVA的比较,EPOLL和Libevent的比较,争论不休。包括GLEASY自己提供的中间件,也经常受到不少批评和质疑,收到最多的就是关于使用语言的,GLEASY中间件多数使用JAVA语言,基于MINA2框架,而且我们内部经过大量的压力测试和验证也证明了是性能极高的。关于这一点,在本博客的其它文章中有大量介绍。
不过是否可以百尺杆头,更进一步呢?比如选用C语言和基于C语言的开发库,情况如何呢?
因此,Gleasy架构组做了一系列的实验,来验证当前一些主流的高性能网络服务器开发库的性能比较起来到底如何。

实验数据
实验1:EPOLL(leader-fllower,oneshot) C语言
实验2:Libevent N 1线程(N=CPU核数,one event-loop per thread) C语言
实验3:Mina2(JAVA语言)
实验结果在下面附件中:
Epoll与Mina与Libevent性能测试

结论
CPU占用对比图:
best online casino wp-image-543″ />

TPS对比图:

对两幅图的解释:
1. 从TPS(每秒处理的请求数据上来看),三者没有本质差异,基于JAVA语言的MINA2框架在TPS上绝对不输于C语言EPOLL和LIBEVENT。而且这三个家伙的性能表现都很牛很牛,从图上可以看出,当并发连接在1000左右时,TPS平均可达30万,高峰时可达50万。
2. EPOLL无论在TPS或者CPU占用率方面都占优势。这是预料之中,毕竟LIBEVENT也好,MINA2也好,在LINUX上面,最终使用也是EPOLL机制,所以只要不犯低级错误,原生的EPOLL在性能和CPU消耗方面必然会占优势。
3. LIBEVENT和MINA2都在EPOLL基础上做了大量的封装工作,比如LIBEVENT的buffer event,Mina2的codec,不可避免造成额外的CPU开销。其中基于java语言的mina2在CPU上开销明显大于C语言的其它方案。甚至有接近2倍的差异。
4. 我们在开发功能复杂的服务器应用之时,一些基本的工作必须要做,比如buffer,比如codec,这些工作我们自己做,或者交由libevent或者mina2来做,始终都要去做,是避免不了的,而且我们自己去实现,本身效率如何也未知。所以我们才会选择使用更上层的封闭,一方面减少工作量,另一方面,避免无关的错误发生。从这一点出发,在做技术选型之时,综合取舍,业务简单但对性能极端要求的场景,可以直接用C语言和EPOLL,业务复杂度高工程较大的需求,可以选用JAVA语言和MINA2。不要太纠结于选取的语言,该C时就C,该JAVA时就JAVA,没有谁比谁更优秀。还是那句千年不变的老话,永远没有最好的技术,只有用最适合的技术。别人说的永远只是别人的经验,自己动手尝试证明得到的才是最真实的!

发表在 C/C++, Java技术 | 一条评论

第一次接受CSDN专访

此次专访己发表,发表地址为:
http://www.csdn.net/article/2014-03-05/2818635-interview-with-Gleasy-CTO-xueke

还上了一会头条,哈哈

发表在 Gleasy团队 | 留下评论

ObjectC的GCD(Grand Central Dispatch)机制小析

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

GCD机制 vs JAVA线程池
1. GCD执行起来比JAVA真心方便
ObjectC GCD:可执行的为代码片段(code block)

dispatch_async(queue,^{
 NSLOG(@"hello,word");
});

 

JAVA: 必须是对象(可以用无名类)

pool.submit(new Runnable(){
 public best online casino  void run(){
 System.out.println("hello,world");
 }
});

 

2.GCD不用关心线程的建立和释放
GCD机制更为傻瓜式,不用关心线程何时建议,何时释放,只管用,建立和释放的问题交给运行环境解决。
JAVA得自己建立不同的线程池,还得关心最大线程数,须手工关闭线程池(否则会出现最大线程数超的问题)。

3.GCD的线程机制更为高效
GCD机制线程可以说与生俱来,与程序员打交道操作是一个个的queue,线程是躲在queue后面,执行queue里面的代码片段的,而且当线程不够用时,系统会自己调度,创新新的线程,而所有这一切,程序员都是不知道的。线程创建和销毁可以全局调度,减少无谓开销。
JAVA的多线程机制,线程池大概相当于GCD的queue,不同的是,每个线程池的线程都是独立的,相互之间不能互相挪用。这就要求程序员去规划每个池的线程规模及建立和销毁策略,当系统规模稍大时,在同一个JVM中,可能存在大量线程池,A线程池忙碌时,B线程池可能极为空闲,但A线程池由于无法挪用B线程池的线程,从而导致线程创建和销毁频率大大上升。

4.结论
无论从性能,简洁性,易用性方面,GCD机制都比JAVA的多线程机制要好;希望JAVA虚拟机可以在某个版本引入GCD特性。

发表在 IOS, Java技术 | 留下评论

排序算法总结

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

一。常用排序算法一览表
排序方法    平均情况     最好情况  最坏情况  辅助空间     稳定性
冒泡排序    O(n2)       O(n)                     O(n2)    O(1)            稳定
简单选择排序  O(n2)       O(n2)         O(n2)     O(1)    稳定
直接插入排序  O(n2)     O(n)           O(n2)      O(1)           稳定
希尔排序    O(nlogn)-O(n2)  O(n1.3)               O(n2)       O(1)    不稳定
堆排序     O(nlogn)      O(nlogn)            O(nlogn)   O(1)     不稳定
归并排序    O(nlogn)     O(nlogn)            O(nlogn)    O(n)     稳定
快速排序    O(nlogn)     O(nlogn)             O(n2)              O(logn)~O(n) 不稳定

二。性能实测
测试方法:随机生成1-100000内的数字,然后放到一个数组里接受排序。
硬件环境:I7 4核8线程,16G内存

测试结果如下:
算法\数量  100  1000 1万         10万 100万 1000万
冒泡排序   0.51   6.8     670         X        X         X
选择排序   0.47   3.31    286.5    X         X         X
插入排序   0.49   2.84    227.95  X         X         X
希尔排序   0.58   0.79    4.39      65.5   1414   18899
堆排序      1.48    1.82     6.3        70.5    1311   15382
归并排序  0.77    1.07     4.5        48.5    682   8064
快速排序  0.8     0.9        2.59      24       345   4562
HPC排序  56       55        56          58        79    734

说明: 时间的单位是MS(1s=1000MS)。HPC排序指并行排序(使用多线程排序)
从上表得出以下结论:
当被排序数据处于100以下时,简单排序用时最短;
当数据量超过1万时,简单排序开始不能胜任,时间呈几何增长;
当数据量超过10万时,简单排序已经失效,跑不出结果;
快速排序表现最为抢眼,是高级排序中用时最短的算法;

三。HPC排序算法介绍
1. 将待排序数据平均分为X个队列(X为CPU的核数)-(Map)
2. 开启X个线程,同时使用高级(快速/堆/归并)排序算法分别对这X个队列进行排序
3. 排序完成的队列进行两两合并,X->X/2->x/4—->1,最终得到1个有序队列 –(Reduce)
4. 排序完成

四。总结
对于大多数情况(不考虑内存占用,假设待排序的数据排列情况随机),在数据量非常小(1000以下时),选择插入排序即可;在数据量位于10万级别以下时,选择快速排序比较稳妥;当数据量超过10万,达到100万以上,HPC排序是不二选择;
对于懒人来说,保险起见,直接选择快速排序也未尝不可,至少在100万以下的数据,还是1S以内可以搞定的。超过1000万,就要HPC排序了(对稳定性有要求可以使用归并排序结合HPC)。

发表在 Java技术, 分布式技术, 数据库技术 | 留下评论

基于操作序列的一致性机制对分布式系统设计的意义

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

保证一致性的策略
原子事务:使用ACID策略保证强一致性,这是最粗暴也是最稳妥的一致性保证手段。这是标准的CP型系统设计,牺牲可用性和性能。系统规模不能太大。
二段式提交:分布式事务的经典实现,一致性强度基本与事务持平。优点是系统规模比原子事务要大,而且适用于跨平台,跨系统。缺点同样牺牲可用性。
PAXOS:强一致性保证,2n+1个结点,只需要n+1个结点达成一致,比上面两种方法在可用性方面有大幅提升,广泛应用于NO-SQL数据库的集群(比如MongoDB)。但它仍然是CP的,因为要达成一致至少需要一半以上结点同意,同样牺牲了可用性。
BASE:可用为主,软状态(状态不用时刻一致),最终一致。以可用性为主要考虑对象的系统设计思想。数据库的主-从同步当属范畴,允许主从延迟的存在,本身就是一种软状态,但随着主从同步完成,最终状态趋于一致。

基于操作序列的一致性保证
本文想重点聊的基于操作序列的一致性方法,可以算作BASE的范畴。它是指分布式系统在写入的时候,可以更新某个结点(或者干脆不直接更新任务结点),将操作序列存放在消息队列(MQ)中。写入MQ成功,则等同于写入成功。分布式系统结点通过按顺序消费MQ来实现最终一致性。使用该机制,可以有效地保证数据写入的速度,最大可能地提供高可用高性能。

Gleasy的分布式文件系统Cloudfs和分布式索引平台CloudIndex,就是使用了这种机制。Cloudfs某个结点上传了文件,会立刻往MQ里面生成一条写入记录,其它结点会即时消费该记录,从该结点同步文件,同样,当文件被删除,也会生成一条删除记录,其它结点做相应的删除动作。CloudIndex则是更新索引时,直接写入MQ,不更新结点,所有结点都通过MQ获取索引更新或者删除的操作指令去执行相应动作。当不一致发生时,可以从问题发出前的时间点重新消费MQ来完整重现问题发生后的所有操作,从而实现数据一致性恢复。使用这一机制,保证了Cloudfs和CloudIndex的高性能(具体可以参见博客相应文章),而且数据一致性也完全处于可以接受的级别。

这种方式是万能的么
任何技术都是双刃剑,使用基于序列的方式保证一致性来换取高性能的技术,同样有其固有的限制。
首先,操作序列必须是可以重复执行的。这一点是极为重要的。如果操作序列中有类似set a=a+1,这种动作,这种机制是完全失效的。Cloudfs只有add,del两个动作;CloudIndex只有add,remove两个动作。这两个动作在保证序列的情况可,完全可以多次执行。
其次,延迟是可以接受的,或者可以规避的。使用这种机制,在某一时刻,不同结点的数据是不一致的。Cloudfs通过保证相同的文件只会去到固定结点去读取来规避这种延迟;而CloudIndex本身是允许索引延迟的。
以上两个条件,缺一不可。

结论
在设计分布式系统的过程中,由于系统特性,需求的不同,供选择的方案可以千差万别。了解一种技术,最重要是了解技术背后的弱点的限制。没有最好的技术,只有最适合的技术。

发表在 Java技术, 分布式技术, 数据库技术, 运维 | 一条评论

Gleasy的分布式任务调度中间件CloudJob

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

一.CloudJob是什么
它是一个中间件,不能够独立运行。需要用它应用配置后使用它提供的API来解决某些特定的问题。
它提供jar包供JAVA应用使用。目前暂无提供其它语言的客户端。
它运行时需要使用redis和zookeeper,所以使用它的前提是必须同时使用redis和zookeeper。

二.它解决什么问题
CloudJob主要解决的问题是将大量小的或者定时执行的计算任务分配到若干服务器结点(或者称之为计算集群)去执行。它并不提供并行计算能力,超大型任务需要使用者自行分解提交并汇总。它不是MapReduce框架,不是Hadoop。它有些像Rpc,但不同之处它是自动负载均衡的,任务有进度有状态可中止,可异步,还可识别出相同任务,自动去重;它有些像Quartz,但它是分布式的;
这么一个四不像的中间件,在Gleasy众平台中起着至关重要的作用。
场景1:Gleasy的在线Office,涉及大量的文件类型转换工作(doc to html, xls to grid,html 2 doc,etc…)。在线Office平台接受到用户请求,直接把任务丢进CloudJob,后端的转换集群就开始有条不紊地处理(相同文件的转换任务只会执行一次,无论多少用户提交),并将结果反馈。
场景2:Gleasy的定时发送邮件(设定某个时间发送某封邮件到某个或者某些人),定时任务提醒,生日提醒,日程提醒,甚至是周提醒,月提醒。。。等等需要在将来做的一些具体的任务,就可以把任务和定时规则丢进CloudJob,CloudJob会在时间到达之时,正确地执行。

三.技术特性
集群结点个数可达数千;
支持结点动态增加;
任务自动负载均衡;
支持海量定时任务,任务数量可达亿级别;
完全支持Crontab定义任务触发规则;
严格保证任务处理的实时性和顺序性;
支持任务同步或异步执行
支持查询任务执行状态和结果
支持避免同一任务重复执行,可复用其结果

四.设计思想
1. 技术选型
Powered by Java
使用zookeeper作为集群状态维护和结点发现工具
使用redis shard作为存储

2. 主体架构图
online casino />

3. 任务处理示意图

五.单台服务器性能测试
硬件环境:CPU INTEL I5 4核,内存12G,硬盘7200转.

定时任务提交(tps=5000)
target/benchtest/bin/TestJobProducer /data/config/util/config_0_11.properties cron 200 20000
线程总时间:864684;平均:43.2342
实际总时间:4484; 平均:0.21685

普通任务提交(tps=14285)
target/benchtest/bin/TestJobProducer /data/config/util/config_0_11.properties fasyc 200 20000
线程总时间:282056;平均:14.1028
实际总时间:1540; 平均:0.077

 

发表在 Java技术, 分布式技术, 数据库技术, 运维 | 2 条评论

Gleasy的分布式实时索引平台CloudIndex

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

一。CloudIndex是什么
是一个独立运行的平台级后端系统,不会直接对用户提供服务,通过API方式对应用服务器提供服务。API全部采用HTTP接口。

二。它能干什么
CloudIndex,分布式实时索引平台。作为数据库的有效补充,它替代了关系数据库的复杂检索功能,完全替代了like语句,还提供基于分词的检索能力。除此之外,它使用分布式技术来解决数据库所短缺的海量存储问题,单点故障问题,写单点问题。Gleasy但凡涉及检索的功能,或多或少都要与之打交道,它是名副其实的核心系统。

三。技术特性
支持海量存储和检索;
准实时索引(索引延时在200MS以内);
多写多读,无单点故障,不存在写单点问题;
横向和纵向动态负载均衡(数据分片 请求负载);
性能优秀,写TPS>10000,读TPS介于2000-5000之间(i5,16G内存)

四。产生背景
条件检索在系统规模不大的时候,使用数据库的like基本上也够用。不过随着数据量的暴增,一个like语句可能会造成CPU 100%,更不用提大规模海量并发了。由于索引平台是核心系统,在选取何种技术来实现这个问题是我们十分谨慎。最初考虑Lucene,但完全自主研发,似乎工作量太大;后面有考虑ElasticSearch,从介绍上看还是极为强大的,甚至也涵盖了分布式的大部分特性,不过缺点是社区太冷清,文档和插件稀少,且也未见成熟;然后又对比了solr和solrCloud,solr4涵盖了solr cloud的特性,并且有效弥补了Lucene的工作量大的缺点,加上社区内容丰富文档齐全,最终还是考虑基于solr来实现,至于是否使用solr cloud,我们谨慎地反复实验solr cloud的特性,包括分布式,Shard,Replica等,最终还是放充使用,一个关键的原因不太认可solr cloud的Leader-replica机制,所有写操作都必须提交到leader,然后由leader分发,效率太低;另外就是它的维护复杂度太高,通常越是功能强大的系统维护成本就越高,solr cloud也是如此,由此带来的风险是当问题出现或者需求不被满足的时候,我们不得不从代码入手进行二次改造。综合考虑以上因素,最终我们选择solr4但放弃使用它的solr cloud功能,仅保留它的实时检索能力,相当于我们使用的是单机模式的纯solor。我们在它基础上做上层包装,所有分布式的特征全由自己来实现。

五。设计思路
沿袭solr cloud的概念,CloudIndex在物理架构上和solr cloud没有本质区别,最大的区别在于实现方法不同。
CloudIndex没有Leader和Replica的概念,写入索引时,将索引更新内容写入MQ,所有结果按顺序消费对应的MQ来写入数据,并数据保证一致性。
CloudIndex使用人工shard进行数据划分,最大程序保证分片的合理性。

1. Collection(完整索引示间图)
casino online alt=”Collection” src=”http://rdc.gleasy.com/wp-content/uploads/2014/01/Collection.png” width=”683″ height=”400″ />

2.Solr与索引对应关系图

3.建索引示意图

4.分布式查询示意图

六。其它
CloudIndex已经线上平稳运行2年,实时支撑起Gleasy全部项目的检索工作。无论在性能及功能,可维护性方面都经受住了检验。还是一句老话,没有最好,只有最合适。

发表在 Java技术, 分布式技术, 数据库技术, 运维 | 2 条评论