月度归档:2013年05月

FreeBSD建数据中心的问题 zt

原地址:https://www.freebsdchina.org/forum/viewtopic.php?t=58346

alphachi需求提出:

单位内部需要建自己的数据中心,初期规划数据量约1000TB,想用FreeBSD来做。
找了一圈资料,可参考的实在太少,只能发贴向各位求教。

1. 文件系统是应该跑ZFS吗?

2. 是否应该使用HAST?如果需要使用的话,手册上提到了HAST仅支持2个节点,那是不是说,必须要购买2台服务器,然后每台服务器再拖一台容量为1000TB的磁盘存储?

3. 如果不应该使用HAST,那是不是说需要购买多台服务器做成集群存储?假设每台满配能撑到32T,那就需要购买30多台服务器?那如何让这些服务器的存储连接成1000T的大池?FreeBSD集群如何实现也没找到参考资料。

4. 有没有什么型号的服务器或者存储设备推荐?

完全没有经验,自学成才未遂,请大家指教,谢谢!

delphij解答:

1000TB放到一台机器上需要至少挂4个盘柜,并且需要至少5张HBA卡。(假设:1:4冗余、每4组配一个热备盘)。

这么多块硬盘的系统我们实际做过,但容量没这么大。简单来说,内存必须很大,dedup基本不要想(我个人的忠告是把想在这种规模的系统上干这事的人直接砍死);这样的系统可以做到很好的吞吐量,但是响应时间不会很好。

放1000TB而不做冗余是非常糟糕的主意,事实上,多数应用中你根本没有时间从失败中恢复,300块以上硬盘的存储池导入是相当耗时的过程。

关于HAST:HAST的延迟不够理想(新的 memsync 模式对此有极大的改善),而且恐怕并不满足你的需求。假如你的需求是一台机器倒掉的情况下另一台机器可以立即接管服务,应用必须知道怎么实现,而不能仅仅依赖NFS或iSCSI,因为你的存储池导入在300块硬盘的情况下需要相当长的时间,这样做热备是不能满足需要的。

========

比较正常的、还算便宜的实现方案,仅供参考:

事实上,绝大多数应用需要的仅仅是单一的命名空间,而不在意是否是单一的文件系统。正确的做法是分而治之,而绝不是做一个超大规模的文件系统,更不是一个1PB的存储池。这种规模的存储池可以做,但很可能不会做到你想要的效果,并且发生灾难时无法迅速而有效地恢复。

如果用 NFS,可以配合 amd (automount)来实现单一命名空间(只要做一个简单的符号链接到amd控制的目录即可;amd在多数OS上都有实现,可以在需要时自动挂载文件系统),但运营人员需要根据系统的运行情况来适当做rebalance(将数据从一个节点挪到另一个节点)。这个命名空间是在客户端看到的,存储服务器之间只做热冗余,而不必做成集群。这套系统在需要的时候可以通过增加机器的方式来扩展(当然,不是无限的)。

新式的建立在普通文件系统之上的分布式文件系统在运营方面要比用amd+NFS简单一些,但客户机的OS必须支持这些分布式文件系统,并且配置会更为复杂。

以目前硬盘的尺寸来说,一个节点放大概100TB的存储(冗余之后;不超过1个JBOD)是没什么问题的,再大的话热恢复可能就比较慢了。每个节点应该有一个同样容量和配置的HA节点,随你的应用对数据损失和热恢复时间的容忍度不同,可以用快照复制,也可以用HAST。

任何时候,任何节点的剩余空间不应少于15%,因此你的冗余后容量至少需要1176TB(1000 / 85% = 1176.47TB)。

假定每套系统上放44块硬盘(4组8+2 RAID-Z2或8组4+1 RAID-Z,4块热备),每块硬盘容量为4TB,则每个系统的有效容量为32*4=128TB。总共应配置20套这样的系统,总有效容量为 1280TB(其中一半为热冗余系统)。

注意:44块硬盘必须合理规划使用HBA的接口,需要告诉装配工人如何正确接线。

两个一定要注意的问题:

1. LSI HBA、硬盘固件必须刷到最新,不刷会惨死。
2. 不要混用SATA和SAS硬盘,混用会惨死(事实上目前这一代的LSI HBA对SATA的出错处理还是有些问题);个人推荐SAS硬盘。

(其实还有一些其他的细节,通常做服务器的公司都有经验会告诉你,但这里特别提醒一下:不要把硬盘插在服务器上装箱运到机房,而要分别装箱,到机房再装硬盘,等等)。

这种规模的存储系统,实现起来要比第一眼看上去困难的多。另外,很多潜在的问题如果没有实际的经验,光靠自学是没法知道的,很多东西很碎,很杂,总结出来绝对可以写一本基本上卖不出去的书,而其中大半的内容会迅速过时。

最后,假如没有至少2年的维护挂24块以上硬盘的单一生产系统的实际经验,建议忽略以上全部,直接找个懂行的人来做。

Green Unicorn WSGI Server (gunicorn)

Pyramid的手册,在p64页看到介绍gunicorn 这个wsgi server。说它比Waitress更快,比mod_wsgi容易配置。

基本操作就是easy_install 安装gunicorn,然后再pyramid中,可以直接用

$ gunicorn_paste --workers=2 development.ini

也可以修改.ini配置文件:

[server:main]
use = egg:gunicorn#main

这样直接用以前的命令就ok了:

$ cd yourpasteproject
$ paster serve development.ini workers=2

目前暂不支持py3.

 

官网地址为:http://gunicorn.org/

gunicorn_paster

Yeah, for Paster-compatible frameworks (Pylons, TurboGears 2, …). We apologize for the lack of script name creativity. And some usage:

$ gunicorn_paster [OPTIONS] paste_config.ini

Simple example:

$ cd yourpasteproject
$ gunicorn_paste --workers=2 development.ini

paster serve

If you’re wanting to keep on keeping on with the usual paster serve command, you can specify the Gunicorn server settings in your configuration file:

[server:main]
use = egg:gunicorn#main
host = 127.0.0.1
port = 5000

And then as per usual:

$ cd yourpasteproject
$ paster serve development.ini workers=2

实验:FreeBSD 操作系统在无远程控制台下的远程安装

原文档在这里:
http://www.freebsd.org/doc/zh_CN.GB2312/articles/remote-install/article.html

看着不太复杂(第一眼我看着够复杂的),我认为不试验一下,是无法发现其中的问题的(因为我发现很多老外写的东西,国内比着做就是会出很多状况,也许文档也水土不服吧)。

结果做了一下实验,果然发现有问题:

主要是卡在这一步:

紧接着,构建可启动的 mfsBSD 映像:

# make BASE=/cdrom/7.0-RELEASE
我是无论如何都报错,类似:

ciias# make BASE=/cdrom
Cannot find directory “/cdrom/base”
*** Error code 1

Stop in /root/tmp/mfsbsd-2.0.
ciias# make BASE=/cdrom/
Cannot find directory “/cdrom//base”
*** Error code 1

Stop in /root/tmp/mfsbsd-2.0.
ciias# make BASE=/cdrom/base
Please set the environment variable BASE to a path
with FreeBSD distribution files (e.g. /cdrom/8.3-RELEASE)
Examples:
make BASE=/cdrom/8.3-RELEASE
make BASE=/cdrom/usr/freebsd-dist
*** Error code 1

Stop in /root/tmp/mfsbsd-2.0.
ciias# make BASE=/cdrom/usr
Cannot find directory “/cdrom/usr/base”
*** Error code 1

我直接到/cdrom里去看,压根就没有base…..

后来问题解决了,终于做出img镜像文件了:

ciias# make BASE=/cdrom/usr/freebsd-dist
Extracting base and kernel … done
Removing selected files from distribution … done
Installing configuration scripts and files … done
Generating SSH host keys … done
Configuring boot environment … done
100 % 11.2 MiB / 51.5 MiB = 0.218 1.2 MiB/s 0:43
done
Creating and compressing mfsroot … done
Creating image file … done
-rw-r–r– 1 root skywalk 32505856 May 24 15:13 mfsbsd-9.0-RELEASE-amd64.img
不过我用的是i386,咋弄出来是amd64的镜像啊?一会儿要测试一下这个能用不。

此次实验,问题解决的方法为:

1 要用FreeBSD的完整安装盘,比如 FreeBSD-9.1-RELEASE-i386-disc1.iso  ,而不能用纯boot盘

2 mfsbsd最新为2.0版本,而不是文档中的1.0版本

3 make那里,根据iso光盘中不能的结构,写法不同。比如我的9.1是用的

make BASE=/cdrom/usr/freebsd-dist

为什么要这么麻烦的远程安装呢?因为:

世界上有很多的服务器主机供应商, 但是他们中只有很少的一部分正式支持 FreeBSD, 他们通常为他们提供的服务器上安装 Linux® 发行版提供支持。

在某些情况下,如果你请求这些公司他们会安装一个你首选的 Linux® 发行版。有了这个选择,我们将试图安装 FreeBSD。

翻译成中文就是:只要提供linux的托管服务器,我们就能想办法安装上FreeBSD(而不在于是否有boot cd或者boot usb等)

5.27日补充:

经过测试,在virtualbox中,dd后,系统启动,最后报btx halt错.网上搜索了一下,发现报该问题的网页不多,有人通过更新bios解决.

又做了mfsbsd的iso光盘,经测试在virtualbox里是可以用的.这样可能就是用虚拟机的原因,有机会再在实际环境下测试.

从HTML文件中抽取正文的简单方案 zt

原帖:
http://www.pythonclub.org/python-files/html-body

英文原帖:
http://ai-depot.com/articles/the-easy-way-to-extract-useful-text-from-arbitrary-html/

 

译者导读:这篇文章主要介绍了从不同类型的HTML文件中抽取出真正有用的正文内容的一种有广泛适应性的方法。其功能类似于CSDN近期推出的“剪影”,能够去除页眉、页脚和侧边栏的无关内容,非常实用。其方法简单有效而又出乎意料,看完后难免大呼原来还可以这样!行文简明易懂,虽然应用了人工神经网络这样的算法,但因为FANN良好的封装性,并不要求读者需要懂得ANN。全文示例以Python代码写成,可读性更佳,具有科普气息,值得一读。

每个人手中都可能有一大堆讨论不同话题的HTML文档。但你真正感兴趣的内容可能隐藏于广告、布局表格或格式标记以及无数链接当中。甚至更糟的是,你希望那些来自菜单、页眉和页脚的文本能够被过滤掉。如果你不想为每种类型的HTML文件分别编写复杂的抽取程序的话,我这里有一个解决方案。

本文讲述如何编写与从大量HTML代码中获取正文内容的简单脚本,这一方法无需知道HTML文件的结构和使用的标签。它能够工作于含有文本内容的所有新闻文章和博客页面……

你想知道统计学和机器学习在挖掘文本方面能够让你省时省力的原因吗?

答案极其简单:使用文本和HTML代码的密度来决定一行文件是否应该输出。(这听起来有点离奇,但它的确有用!)基本的处理工作如下:

  • 一、解析HTML代码并记下处理的字节数。
  • 二、以行或段的形式保存解析输出的文本。
  • 三、统计每一行文本相应的HTML代码的字节数
  • 四、通过计算文本相对于字节数的比率来获取文本密度
  • 五、最后用神经网络来决定这一行是不是正文的一部分。

仅仅通过判断行密度是否高于一个固定的阈值(或者就使用平均值)你就可以获得非常好的结果。但你也可以使用机器学习(这易于实现,简直不值一提)来减少这个系统出现的错误。 现在让我从头开始……

转换HTML为文本

你需要一个文本模式浏览器的核心,它应该已经内建了读取HTML文件和显示原始文本功能。通过重用已有代码,你并不需要把很多时间花在处理无效的XML文件上。 我们将使用Python来完成这个例子,它的htmllib模块可用以解析HTML文件,formatter模块可用以输出格式化的文本。嗯,实现的顶层函数如下:

def extract_text(html):
    # Derive from formatter.AbstractWriter to store paragraphs.
    writer = LineWriter()
    # Default formatter sends commands to our writer.
    formatter = AbstractFormatter(writer)
    # Derive from htmllib.HTMLParser to track parsed bytes.
    parser = TrackingParser(writer, formatter)
    # Give the parser the raw HTML data.
    parser.feed(html)
    parser.close()
    # Filter the paragraphs stored and output them.
    return writer.output()

TrackingParser覆盖了解析标签开始和结束时调用的回调函数,用以给缓冲对象传递当前解析的索引。通常你不得不这样,除非你使用不被推荐的方法——深入调用堆栈去获取执行帧。这个类看起来是这样的:

class TrackingParser(htmllib.HTMLParser):
    """Try to keep accurate pointer of parsing location."""
    def __init__(self, writer, *args):
        htmllib.HTMLParser.__init__(self, *args)
        self.writer = writer
    def parse_starttag(self, i):
        index = htmllib.HTMLParser.parse_starttag(self, i)
        self.writer.index = index
        return index
    def parse_endtag(self, i):
        self.writer.index = i
        return htmllib.HTMLParser.parse_endtag(self, i)

LinWriter的大部分工作都通过调用formatter来完成。如果你要改进或者修改程序,大部分时候其实就是在修改它。我们将在后面讲述怎么为它加上机器学习代码。但你也可以保持它的简单实现,仍然可以得到一个好结果。具体的代码如下:

class Paragraph:
    def __init__(self):
        self.text = ''
        self.bytes = 0
        self.density = 0.0
class LineWriter(formatter.AbstractWriter):
    def __init__(self, *args):
        self.last_index = 0
        self.lines = [Paragraph()]
        formatter.AbstractWriter.__init__(self)
    def send_flowing_data(self, data):
        # Work out the length of this text chunk.
        t = len(data)
        # We've parsed more text, so increment index.
        self.index += t
        # Calculate the number of bytes since last time.
        b = self.index - self.last_index
        self.last_index = self.index
        # Accumulate this information in current line.
        l = self.lines[-1]
        l.text += data
        l.bytes += b
    def send_paragraph(self, blankline):
        """Create a new paragraph if necessary."""
        if self.lines[-1].text == '':
            return
        self.lines[-1].text += 'n' * (blankline+1)
        self.lines[-1].bytes += 2 * (blankline+1)
        self.lines.append(Writer.Paragraph())
    def send_literal_data(self, data):
        self.send_flowing_data(data)
    def send_line_break(self):
        self.send_paragraph(0)

这里代码还没有做输出部分,它只是聚合数据。现在我们有一系列的文字段(用数组保存),以及它们的长度和生成它们所需要的HTML的大概字节数。现在让我们来看看统计学带来了什么。

数据分析

幸运的是,数据里总是存在一些模式。从下面的原始输出你可以发现有些文本需要大量的HTML来编码,特别是标题、侧边栏、页眉和页脚。

虽然HTML字节数的峰值多次出现,但大部分仍然低于平均值;我们也可以看到在大部分低HTML字节数的字段中,文本输出却相当高。通过计算文本与HTML字节数的比率(即密度)可以让我们更容易明白它们之间的关系:

密度值图更加清晰地表达了正文的密度更高,这是我们的工作的事实依据。

过滤文本行

过滤文本行的最简单方法是通过与一个阈值(如50%或者平均值)比较密度值。下面来完成LineWriter类:

    def compute_density(self):
        """Calculate the density for each line, and the average."""
        total = 0.0
        for l in self.lines:
            l.density = len(l.text) / float(l.bytes)
            total += l.density
        # Store for optional use by the neural network.
        self.average = total / float(len(self.lines))
    def output(self):
        """Return a string with the useless lines filtered out."""
        self.compute_density()
        output = StringIO.StringIO()
        for l in self.lines:
            # Check density against threshold.
            # Custom filter extensions go here.
           if l.density > 0.5:
                output.write(l.text)
        return output.getvalue()

这个粗糙的过滤器能够获取大部分正确的文本行。只要页眉、页脚和侧边栏文本并不非常长,那么所有的这些都会被剔除。然而,它仍然会输出比较长的版本声明、注释和对其它故事的概述;在图片和广告周边的比较短小的文本,却被过滤掉了。 要解决这个问题,我们需要更复杂些的启发式过滤器。为了节省手工计算需要花费的无数时间,我们将利用机器学习来处理每一文本行的信息,以找出对我们有用的模式。

监督式机器学习


这是一个标识文本行是否为正文的接口界面: 所谓的监督式学习就是为算法提供学习的例子。在这个案例中,我们给定一系列已经由人标识好的文档——我们知道哪一行必须输出或者过滤掉。我们用使用一个简单的神经网络作为感知器,它接受浮点输入并通过“神经元”间的加权连接过滤信息,然后输后另一个浮点数。大体来说,神经元数量和层数将影响获取最优解的能力。我们的原型将分别使用单层感知器(SLP)和多层感知器(MLP)模型。 我们需要找些数据来供机器学习。之前的LineWriter.output()函数正好派上用场,它使我们能够一次处理所有文本行并作出决定哪些文本行应该输出的全局结策。从直觉和经验中我们发现下面的几条原则可用于决定如何过滤文本行:

  • 当前行的密度
  • 当前行的HTML字节数
  • 当前行的输出文本长度
  • 前一行的这三个值
  • 后一行的这三个值

我们可以利用FANN的Python接口来实现,FANN是Fast Artificial Neural NetWork库的简称。基本的学习代码如下:

from pyfann import fann, libfann
# This creates a new single-layer perceptron with 1 output and 3 inputs.
obj = libfann.fann_create_standard_array(2, (3, 1))
ann = fann.fann_class(obj)
# Load the data we described above.
patterns = fann.read_train_from_file('training.txt')
ann.train_on_data(patterns, 1000, 1, 0.0)
# Then test it with different data.
for datin, datout in validation_data:
    result = ann.run(datin)
    print 'Got:', result, ' Expected:', datout

尝试不同的数据和不同的网络结构是比较机械的过程。不要使用太多的神经元和使用太好的文本集合来训练(过拟合),相反地应当尝试解决足够多的问题。使用不同的行数(1L-3L)和每一行不同的属性(1A-3A)得到的结果如下:

有趣的是作为一个猜测的固定阈值,0.5的表现非常好(看第一列)。学习算法并不能仅仅通过比较密度来找出更佳的方案(第二列)。使用三个属性,下一个 SLP比前两都好,但它引入了更多的假阴性。使用多行文本也增进了性能(第四列),最后使用更复杂的神经网络结构比所有的结果都要更好,在文本行过滤中减少了80%错误。 注意:你能够调整误差计算,以给假阳性比假阴性更多的惩罚(宁缺勿滥的策略)。

结论

从任意HTML文件中抽取正文无需编写针对文件编写特定的抽取程序,使用统计学就能获得令人惊讶的效果,而机器学习能让它做得更好。通过调整阈值,你能够避免出现鱼目混珠的情况。它的表现相当好,因为在神经网络判断错误的地方,甚至人类也难以判定它是否为正文。 现在需要思考的问题是用这些“干净”的正文内容做什么应用好呢?

使用python发布wordpress博文

原文如下:
http://www.jansipke.nl/using-python-to-add-new-posts-in-wordpress/

代码如下:

import datetime, xmlrpclib

wp_url = “http://www.example.com/xmlrpc.php”
wp_username = “someuser”
wp_password = “secret”
wp_blogid = “”

status_draft = 0
status_published = 1

server = xmlrpclib.ServerProxy(wp_url)

title = “Title with spaces”
content = “Body with lots of content”
date_created = xmlrpclib.DateTime(datetime.datetime.strptime(“2009-10-20 21:08″, “%Y-%m-%d %H:%M”))
categories = [“somecategory”]
tags = [“sometag”, “othertag”]
data = {‘title': title, ‘description': content, ‘dateCreated': date_created, ‘categories': categories, ‘mt_keywords': tags}

post_id = server.metaWeblog.newPost(wp_blogid, wp_username, wp_password, data, status_published)

核心思想,就是通过wordpress的XML RPC通信接口来实现发文。

 

今天把谷歌的adsense重新挂在airoot和zqfx网站了

更新服务器后,谷歌的广告就一直没重新挂,今天重新挂上了。

zqfx用的是discuz论坛,发现后台那里就有广告的设置,很顺利的就设置好了。

airoot用的是wordpress,以前用的啥插件忘记了,今天测试了:
adsense now
google adsense dashboard
quick adsense cn
easy adsense等插件,其中easy adsense启用后网站就崩溃了,到了目录里直接删除了该插件才恢复:
# rm -r easy-adsense-lite/

另外顺便安装了Akismet插件,是用来对付垃圾评论的。

另discuz论坛升级,有一个文件discuz_database.php,显示有变更,但我用diff看了,只相差了一个尖括号,个人认为新版本文件是尖括号手误写错了。
discuz有很多插件,安装了超级防水墙后,网站无响应,但管理页面有响应,把该插件关闭后,网站正常了。

小说最新章节自动化处理

测试代码如下:

import re
import urllib.request
text='最新章节哈哈'
text="""['校园全能高手  第243章 惊心较量(下)', '第243章 惊心较量(下)
  “呼~!”
  那中年警察缓缓吐出一口气息,脸上的表情也略微的缓和了一些……直到现在,他才算是从季枫那一记重踹中恢复过来。
  由此可见,季枫刚才那一脚有多重,攻击力是何等的凌厉!
  要知道,这中年警察的体质可是相当强悍的,他甚至可以跟季枫正面硬碰硬的进行一场激战,自己却也只是略微处于下风。
  可见,这中年警察的身体强度也绝对不会比季枫弱太多!
  然而即便是如此强悍的身体,在挨了季枫刚才那一记重踹之后,竟然好一会才恢复过来,那种内脏都仿佛被一脚踹碎的剧烈疼痛,才渐渐地消失,试想一下,如果季枫这一脚是踹在了一般的高手身上,恐怕会直接将人一脚给踹死']
"""
url2="http://www.study520.com/read/266/"
url1="http://www.17k.com/book/89718.html"
url3="http://www.520xs.com/10003/"
for i in [url1,url2,url3] :
  url=i
  get=urllib.request.urlopen(url)
  text=get.read()

  if ("utf" in str(text)):
    text=text.decode('utf8')
  elif ("gbk" in str(text)):
    text=text.decode('GBK','ignore') #解决gbk中全角空格的问题
  elif ("gb2312" in str(text)):
    text=text.decode('gb2312')
  get.close()

  #r=re.compile(r'<a.*?最新章节.*',re.U|re.I)
  r=re.compile(r'最新.*第/d{1,4}章.*|最新章节.*|<a.*?最新章节.*',re.U|re.I)
  text1=r.findall(text)
  print('匹配内容是:',text1)

  for j in text1:
    p2=re.compile(r'ref="(.*?)"')
    if j is not None:
      print('j is ',j)
      text3=p2.findall(j)
      print('链接地址是',text3)

  print()

ps,使用pre标签可以在wp博客页面中保留python代码的个空格缩进。

对三种不同的页面情况,进行了处理,前两种可以拿到url链接,第三种需要自己去找…..
后面针对第三种情况,还要继续处理……