ZhongZiChang’s Dao

September 20, 2006

9.7-9.12

Filed under: DBLu Project, 工作 — 钟 子昌 @ 4:57 pm

// dblu 提供即时更新的接口
// 有空试用 ecshop2

o 为 discuz 的posts 表(16,100,000条记录,6个字段, 分别是fid tid invisible message subject,其中 message 和 subject 需要全文检索)创建索引的时间 65789064ms => 18.27474 个小时

o 检查分段 rebuild 是否生效

o dblu , 分段索引时,使用的sql语句,要加上 order by [primary key] ,按照 primary key 来分段和排序 ———– (取消)

o 等 posts 表的数据创建完毕,在远程服务器上再做测试修改后的DBLu

o 下午2点,讨论 cbdb 的需求

o 商品搜索项目需要接手,相关的资料需要阅读

o discuz 的 posts表需要索引的字段:
fid tid invisible message subject

o 分段搜索下的返回结果

o 当 按照beginPercent=”90″ 和 endPercent=”100″ 来更新的时候 , db.getIndex 方法取回的 resultSet 为空,需要看代码检查原因。目前怀疑是根据百分比取到的 primary key 的值所在的记录可能不存在

o 调整架构

o 取消对 schedule 中 对 limit 的处理

o 按百分比分段检索

configListFilePath=/var/DBLu/list
dataDirectory=/mnt/ramfs/DBLu/data

/home/zczhong/var/DBLu/f/localhost.wiki.page.xml

threads 表,5个字段(tid, closed, fid, displayorder, subject),其中subject做全文检索,100w条记录,用时39分钟,如果1000w的表,10%就是100w,也差不多是么长的时间

9.13 关于购物搜索的想法

Filed under: 工作 — 钟 子昌 @ 4:57 pm

+ 不做太多的分类搜索,比如分开商品、折扣、商店这样的分类来让用户选择性搜索,这样的选择让人迷惑,”选择”可以作为高级功能来提供给用户。不能把“商品”和“折扣”作为分类分开,因为这样选择太多,太麻烦。要求智能,自动计算和猜测用户想搜索什么,想得到的是什么样的搜索结果。建议搜索框只有一个,根据用户在搜索框中输入的内容,猜测用户最想得到的是什么样的结果,根据这个猜想来进行搜索。比如用户输入“手机 折扣”或者“手机 打折”,那么就说明这个用户想搜索的是关于手机打折方面的信息,我们的后台程序对“折扣”这样的典型或者高频的词应该进行优化,目的是让用户搜索到的是折扣类的信息,而不是仅仅包含“折扣”这个词的信息。又例如用户输入“ipod 重庆”,这样用户想搜索的是什么呢?用户想搜的是在重庆卖ipod的商店,而不是仅仅包含“手机”和“重庆”两个关键词的信息。

举一个我前段时间想找买颗小螺丝和小螺丝刀的例子作为过度。前几天我有个数码产品上面的小螺丝掉地上,不知道滚到哪里去了,找不着,怎么办?没有那颗螺丝可不行,盖子盖不好,我想去买一颗。去哪里买?我不知道:( 然后我在家里找有没有其他的东西上有这么小的螺丝,最后在一个废充电器上面发现有,但是螺丝很小,那个孔也很小,我想要个小起子,把那颗螺丝起起来。我也不知道在北京这里哪里能买到小的起子,去电脑城问?太麻烦了,要是在网上能查到我附近哪些商铺有的卖就好了。最后我把充电器砸了才拿到那颗小螺丝,才发现那颗螺丝小了一点,不合适。

+ 不仅仅能对网上商店的搜索。用户进行购物搜索的目的,我自己估计(当然不能代表全部,只是说明我有这样的想法,我也曾问三个朋友,一个技术人员、一个摄影师、一个是家庭主妇),很多时候不是为了在网上的商店上买东西,而是,一、看看关于某种商品的介绍和网友的评论,能找到商品的价格范围,不用担心被骗;二,希望找到自己周围有哪些商店出售这种商品,方便自己去购买,最好能在地图上显示。我相信大部分用户存在这样的需求。

+ 关于一些周边的附加功能,如“相关产品、用户可以在地图上添加某种商品可以在哪些地方买到、积分问题”等。目前我不想考虑,等第二期或者第三期的开发。我觉得目前考虑的重点是商品搜索,尽最大的努力让用户得到他最想得到的结果,这样这个服务才能让更多的用户使用。让用户想买东西的时候,必先用我们的服务,才是第一期的目标。

+ 不推荐这个项目太过着重于价格的比较,因为我觉得单纯的竞价搜索会破坏良性的商业环境。商家的利益受到损害,就不能给用户提供更好的服务。我担心破坏我们和这些网上商城的关系,不方便于以后的合作。或者我们可以利用这点,和网上商城沟通,尽量达成一致来打击其他的竞价搜索引擎。所以这个项目的重点是“导购”,是帮助用户轻松买到他想要的商品。价格的比较只能作为其中的一项服务,并且只适合于网上商城。这个需要进一步权衡利益。

为了满足上面用户的需求,我们的系统应该怎么做?要求聪明、表达清晰、功能强大(绝大部分功能并非面向用户,而是面向我们的聪明程序,聪明的程序主要是负责在猜测用户在想什么,需要得到怎样的结果)

9.13

Filed under: 工作 — 钟 子昌 @ 4:52 pm

阅读相关的资料后,对前段时间购物搜索项目的想法。

重点:

通过对商品所在商家等级,商品价格,商品评价等的综合考虑来确定某一款性价比最高的商品做为购买对象。
——————– 如果综合考虑?商家等级如何定?商品价格怎样才算合适?商品评价(某个还是某种)?
网店的注册用户数,交易量,交易的成功率,交易的地域范围。

其次:

打折\活动信息如何取得,如何优化?

September 2, 2006

Tomcat 的集群和负载均衡 - 第一部分

Filed under: 配置 — 钟 子昌 @ 11:03 pm

英文原版,由钟子昌翻译整理

最新版的 Tomcat servlet 容器提供集群和负载均衡的能力,对于部署可升级、健壮的Web应用来说,这是必不可少的。这篇文章的第一部分描述集群与负载均衡的特性和要点。第二部分举出一个如何配置 Tomcat 集群的实例,同时介绍在集群环境中使用内存复制的方式来实现 session 的持久化 。

Tomcat 5 自带一个基于规则的负载均衡应用。根据两种负载均衡策略(扩展自规则API,分别是 round-robin 和 random 算法)来重定向进入的请求。讲述运行在集群环境中的样例Web应用的性能评测。通过负载测试工具 JMeter 模拟多个Web用户的方式来研究负载均衡机制。

+ 大型系统的设计

企业级的 Web 门户应用必须提供可升级能力(scalability)和高可用性(HA),在同一个网站下为数以百万计的用户提供服务。可升级是系统可以通过增加服务器来支持更多的数量的用户。高可靠性是系统提供基本的冗余能力。在集群中的某个成员失效时,其他成员能透明的接替处理对 Web 服务的请求。在集群的环境中部署一个 Web 门户应用能提供门户网站需要的可升级和高可用性的能力。基本上,集群的主要目的是防止某些站点出现当机的问题,应付系统的单点失效。

大型系统的设计目的是在企业应用环境中提供稳定的服务,确保最少的当机时间和最大的可升级能力。运行的不是单一的服务器,有多个协作服务器也同时在运行。为了达到可升级的能力,集群能任意增加机器数量,而为了最少的当机时间,集群中每一个组件都是可冗余的。大型系统的主要因素就是集群,包含负载均衡、容错、session 状态持久化等特性。在集群中,通常负载均衡器(硬件或软件)布置在应用服务器的前面。这些负载均衡器通过使用重定向 Web 交易到相应的集群成员来在集群的节点内分发负载,并且在同时检查集群内是否有服务器失效。

+ 集群

集群的定义好比一组应用服务器透明的运行J2EE应用,就象在一台机器上执行一样。有两种方式的集群:垂直缩放和水平缩放。垂直缩放可以通过提高单台机器上的运行服务的数量来达到,水平缩放就要提高集群内机器的数量。水平缩放比垂直缩放更可靠。使用垂直缩放,机器的处理能力、CPU的使用情况和JVM堆内存配置都是决定应该在这台机器上运行多少的服务器实例的主要因素(众所周知的 server-to-cpu 比率)。

J2EE集群内的服务器一般使用三种配置选项的一种:
独立(independent),每个服务都有属于自己的一份应用程序文件的拷贝;
共享文件系统(shared file system),集群内所有的服务器拥有一个共同的存储设备,所有服务器的应用文件都是从该设备取得;
第三方的配置方法(managed),有一台管理服务器控制对应用内容的访问,通过”pushing“相应的应用内容到管理服务器作为响应。管理服务器能保证集群中所有的成员的应用有效。当部署应用时,所有的服务器都会更新,而反部署时,所有的服务器都会将应用删除。

集群可以在J2EE应用的各个层次使用,包括数据层。一些数据库提供商提供集群数据库,支持多个数据库服务器中的数据复制、客户透明访问( servlet 容器或者应用服务器无须知道从那个数据库服务器中取的数据)。JDBC集群的例子是 Oracle9i’s Real Application Clusters(RAC) 和集群 JDBC(C-JDBC)。RAC 支持数据库连接的失败重启、透明变更JDBC连接、请求到一台恢复后的数据库节点。C-JDBC是一个开放源的数据库集群,允许 Web 应用通过 JDBC 透明的访问数据库集群。实现数据库节点内的负载均衡和失败重启。

++ Tomcat 的集群

在 Tomcat 先前的版本中(4.1)可以通过第三方的jar文件来实现集群。在一个集群内安装和配置多个 Tomcat 实例不是一件容易的事情。将集群的能力增加到开放源的 servlet 容器(Tomcat)和应用服务(JBoss)中,JavaGroups 是一个不错的选择。在最新版本的 Tomcat,集群已经成为主要安装包的一部分。将第三方的集群实现对 Tomcat 服务器的影响减少到最低。

在典型的集群环境中,为了让成员之间相互协作和复制状态,它们之间需要互相通信。
组的通信可以使用 point-to-point RMI(TCP-IP)或者IP多播两种方式。
大部分的J2EE应用服务器(如JBoss、Oracle、WebLogic和Borland) 都是使用IP多播让集群成员进行通信,在集群内发送 state/update/heartbeat 数据给其他成员。
Tomcat 集群成员的通信是如下进行的:所有的集群成员用多播 ping 消息来对话。每一个 Tomcat 实例将发送一个消息,广播其 IP 地址和 TCP 监听端口(为session replication)。如果在给定的时间帧内,某个实例没有接收到这些信息,那么该实例就会被认为是当机。

另一个比较流行的概念是 farming,提供集群范围内的 Web 应用的热部署。在服务器 farm内,一个 Web 应用通过拷贝 war 文件到集群内的一个节点上进行部署,farming将会把这个 Web 应用部署到整个集群中。类似的,从一个集群节点上删除 war 文件,farming 将会在集群内所有的节点上反部署这个 Web 应用。Tomcat的集群文档中讲到在接下来的版本中将会支持 farming 能力。

+ 负载均衡

一种机制,能将服务器的负载被分发到集群的不同节点上。基于负载均衡策略,应用不再在单一的服务器上执行,而是在动态选择的服务器上。当客户请求服务,一个或多个协作服务器处理这个请求。负载均衡为集群提供单一的入口,就如直接和独立的 Web 或者应用服务器交互一样,这对客户来说是透明的。

两种比较流行的负载均衡方法分别是 DNS 轮循 和 硬件负载均衡。 DNS 轮循提供单个逻辑名称,返回集群内某台机器的ip地址。这种方式是廉价、简单并且容易配置,但它并没有提供服务器之间的联系和高可靠性的能力。相对来说,硬件负载均衡通过虚拟 ip 地址来解决 DNS 轮循存在的问题。负载均衡器有一个单独的ip地址,映射到集群内的每一个节点上。负载均衡器接收到请求,然后重写头部来指向集群内的其他机器。如果我们从集群内移出一些机器,那么这个改变马上生效。硬件负载均衡的好处是服务器的联系性和高效。缺点是昂贵并且设置复杂。(作者在这里没有提到这种硬件的负载均衡方式可以用软件实现,这种方式称为 Vitrual Server )。

对于负载的分发有多种算法,下面是一些较为常用的算法:
* round-robin 轮循
* random 随机
* weight-based 权重
* minimum load 最小负载
* last access time 最后访问时间
* programmatic parameter-based 负载均衡器根据方法中的参数来选择服务器

负载均衡算法涉及统计上的差异,速度和简单性。举个例子,weight-based算法比其他的算法需要更长的计算时间。想得到对负载均衡的更详细的解释,参考ONJava的文章 “Load Balancing Web Applications

++ Tomcat的负载均衡

先前版本的tomcat并没有提供负载均衡的能力。集成 apache web server 和 tomcat servlet container 就是一个不错的处理 web 请求的负载均衡集群。在Apache+Tomcat 中,被称为 Tomcat Worker 的 Tomcat 实例被配置来实现负载均衡。

Tomcat 5 提供三种方法来实现负载均衡:
分别是用JK本地连接器,用 Apache2 的 mod_proxy 和 mod_rewrite,或者用 balancer web app。
在这篇文章中,我们重点使用第三种,使用 balancer web application 来重定向web请求到集群内的各个节点。这个负载均衡的应用是基于规则的。使用servlet filter机制重定向进入的web请求到下一个有效的集群成员上。servlet filter在servlet 2.3 规范中有详细的介绍。过滤器(servlet filter)可以在 web 应用中负责多种不同的任务。例如JAAS认证,加密,记录日志和审核,数据压缩,XSLT 过滤器转换 XML 内容等等。就如 Tomcat 均衡器网站讲述的那样,这个均衡器应用并非设计用来替代其他的强大的负载均衡机制。它用简单并且易于扩展的方法来重定向交易(traffic)到其他的服务器上。检查均衡器应用所提供的样例Java类,了解均衡器如何用不同的规则标准来完成各种不同的任务。

负载均衡配置文件(rules.xml)包含不同的规则和重定向的URLs。balancer filter 检查RuleChain来决定将请求重定向到那里,按照rules.xml中指定的顺序来检查规则。当一条规则匹配时,过滤器停止评估,并且重定向请求到规则指定的URL上。

+ 容错

容错是系统的一种能力,能够做到系统中的一个服务器失效时,另一个有效的服务器能够接管,这对最终用户来讲是透明的。理想的情况是集群服务监测到集群内其中的一个服务器失效而不能处理请求时,停止发送请求到该服务器。然后周期性的检查集群中的该成员是否再次生效,如果生效,将再次将其添加到活动服务器节点池中。

++ Tomcat 的容错

Tomcat 5 并没有提供一个内建的失败重启机制来检查集群成员的崩溃。希望,未来的版本能提供这个功能,用来发现集群内有效的机器,确定那些成员能处理进来的请求。

集群解决方案一般提供两种层次的失败重启能力:

* 请求层次的失败重启
如果集群中的一台服务器挂起,所有接下来的请求将会被重定向到集群中的其他服务器。这包含一种 heartbeat 机制来保持跟踪服务状态和避免发送请求到没有回应的服务器上。在我们的集群设置中,一个 Tomcat 实例扮演着负载均衡器的角色,处理请求层次上的失败重启,并转发 web 请求到集群中的其他节点。
* session 层次的失败重启
一个 web 客户可以拥有一个由HTTP服务器维持的 session。如果集群中的其中一台服务器挂起,集群中的另一台服务器能接手前一台服务器的session,保持连续性。这需要在集群内复制 session 数据。拥有 session 复制能力的 Tomcat 集群能处理 session 层次的失败重启。

+ session 状态的持久化

失败重启和负载均衡都需要集群内不同的服务器之间能进行 session 状态的复制。当原来的服务器失败时,session 状态复制允许客户无缝的从集群中的另外一台服务器上取得 session 信息。这个状态可以包括系统状态和/或应用状态(应用状态包含存储在 HTTP session中的对象和数据)。session复制的主要目的是当集群成员崩溃、为应用升级或者系统维护停止工作时能够不丢失任何 session 的内容。

谈到session的持续化,有一个简单的集群方案,集群成员不知道其他成员的session状态。在这个方案中,用户session完全在一台服务器上,由负载均衡器来选择。这叫做粘性session(或者叫session affinity)。因此seesion数据保存在接收web请求的集群成员上。

从另外一方面来将,集群可以以这样的一种方式实现,每一个集群成员完全明白其他成员的 session 状态,通过 session 状态的周期性传播到其他备用集群成员。这种session 被称为复制 session。

有三种方法实现session的持久化:
* 内存对内存的复制;
* 文件系统 session 持久化, session 信息从一个中央文件系统读写;
* 数据库 session 持久化, session 数据存储在一个JDBC数据存储器。

在内存 session 持久化中,当 HTTP session 中的独立的对象改变,这个对象将会被序列化到其他的备用机器上,而在数据库session持续化中,当 session 中的任何对象改变时,session 中的所有对象将被一起序列化。

数据库/文件系统session持续化的缺点是限制了当在 HttpSession 存储大型或大量对象时的可伸缩性。每一次用户增加一个对象到 HttpSession 中,session中所有的对象都会被序列化并被写到数据库或者共享文件系统中。

++ tomcat 中的 session 复制

当前 Tomcat 版本的 session 复制是一种 all-to-all 的复制,即在任何时,session 中的属性被传播到集群的所有成员。当集群小的情况下,这个算法是高效的,为应付大型集群的情况,Tomcat 的下一个版本将提供主-从复制,session 将仅仅被保存在一个或者两个备份服务器上。

在tomcat中,有三种类型的session复制机制:
* 内存中复制,使用Tomcat 5自带的SimpleTcpCluster(在org.apache.catalina.cluster.tcp包中,文件为server/lib/catalina-cluster.jar);
* session持久化,保存session在一个共享数据库上(org.apache.catalina.session.JDBCStore);
* 在共享的文件系统上保存session的状态 (org.apache.catalina.session.FileStore, part of catalina-optional.jar)。

+ 实现一个J2EE集群需要考虑的因素

设计J2EE集群需要考虑很多因素。下面这些问题都是在一个大型的J2EE系统需要考虑的(这个列表取自EJB基本训练文档-“用J2EE创建高可用性和可扩展的应用)。

++集群

* 那种类型的集群适用:垂直还是水平扩展?
* 在那个层次实现集群:web服务器或者,servlet,JSP容器还是HTTP session对象;或者EJB,应用服务JMS和JNDI对象还是数据库集群?

++ 负载均衡

* 选中一个服务器的时间(也就是affinity,姻亲关系):每次请求,每个事务或者每次会话?
* 如何选择服务器(也就是负载均衡策略):randomly, round-robin, weight-baesd, least loaded server,或者由应用决定?
* 负载均衡在哪个位置上实现,客户端还是服务器?

++ 容错

* 服务器如何进行失败重启检测?
* 什么时候适合失效重启和尝试使用其他的服务器?
* 失败节点上的系统和应用的状态?

++ session 状态持久化

* 状态如何传播?
* 传播的频率?
* 对象状态如何持久化?
* 状态持久化机制的效率如何?
* 复制的状态是否粘性?
* 网络环境对session状态的复制有限制吗?

+ 建议的集群设置

下面列出在推荐的集群环境中,我要达到的目标:
* 可升级能力高
* 容错
* 动态配置,易于管理
* 自动发现新成员
* 失败重启和负载均衡,session数据内存复制
* 可插拔/配置的负载均衡策略
* 当一个成员加入或离开时,能通知组成员
* 通过多播的方式,无掉包的信息传输
* 集群对 web 应用和服务器来说都是无缝的。对客户端和服务端都是透明的。客户透明是指客户端无须知道集群服务或者集群的设置。集群的识别和访问和单机一样,而不是各自独立的服务。服务器透明是指服务器上的应用程序代码不需要知道是在一个集群之内。应用程序代码不能和其他的集群成员通信。

+ 总结

在这篇文章的第二部分,我们看看如何部署一个集群(运行多个Tomcat服务实例)来达到上面提交的目标。我们将讨论在Tomcat 5 中实现 session 复制的集群架构和配置细节。

待续 …

关于:
Srini Penchikala 是Flagstar Bank的信息系统问题的专家。

September 1, 2006

我开始需要更多的信息了

Filed under: 随笔 — 钟 子昌 @ 10:49 pm

忽然之间觉得经常去的那几个网站的信息满足不了我的阅读需求。想发掘和阅读一些来自blog的内容,却又不想化那么多时间去收集新的信息源。

我需要系统做到如下几点:

1. 自动收集信息源,自动将信息源分等级,将低等的信息源定期排出,维持信息源的数量在一定数量(如1w)之内;

2. 提供搜索功能,让我可以在这1w个精品信息源内找我想要的信息;

3. 自动将我最感兴趣的内容聚合到一个页面上,在我没什么时间的时候,浏览一下这个页面就可以了;

4. 信息更新的频度,当然是越快越好:)

在考虑是否把 blog search engine 重新安装上,专门做这方面的事。

如何按时段和百分比更新数据

Filed under: DBLu Project — 钟 子昌 @ 2:54 pm

举例:

1. 每小时更新10%
<schedule time="0 * * *" percent="10" key="tid">

2. 每天(系统忙)7点到22点,每小时更新10%,(系统闲)1点和5点更新30%
<schedule time="0 7-22 * *" percent="10" key="tid"/>
<schedule time="0 1,5 * *" percent="30" key="tid"/>

* 请在设定时先检查更新的耗时,以便设计合适的更新计划。

随手记-DBLu试用

Filed under: DBLu Project — 钟 子昌 @ 10:50 am

// 由于在做索引工作的时间较长,mysql会将连接断掉,下面的数据不正确。这个 bug 已经改正。- 2006.9.3
create index:

cast time:5316584 - [host:192.168.0.42] [database:discuz] [table:threads]

update index:

18020983 [Timer-3] INFO com.zhongzichang.lucene.IndexSchedulerTask -
cast time:606630 - [host:192.168.0.42][database:discuz][table:threads]
[where:null][orderBy:null][limit:null][key:tid][url:null]
[rebuild:false][analyzerName:cjk][percent:10]

21621416 [Timer-3] INFO com.zhongzichang.lucene.IndexSchedulerTask -
cast time:607053 - [host:192.168.0.42][database:discuz][table:threads]
[where:null][orderBy:null][limit:null][key:tid][url:null]
[rebuild:false][analyzerName:cjk][percent:10]

25223611 [Timer-3] INFO com.zhongzichang.lucene.IndexSchedulerTask -
cast time:609248 - [host:192.168.0.42][database:discuz][table:threads]
[where:null][orderBy:null][limit:null][key:tid][url:null]
[rebuild:false][analyzerName:cjk][percent:10]

Powered by WordPress