SQL查询优化: 既有Unique Index为何还要另加Index?

在使用 -GWA2 进行WebApp开发时,我们创建基于MySQL的相关数据表时,都会有意识地在数据表的关键字段上增加索引,以期待查询时能够较快地返回结果集。

在我们现有的生产线上的数据观测中,同样一张数据表,通常当数据达到10M+时,如果某个待检索字段(用在Where里作为查询字段)没有使用索引,一次查询大约需要耗时50s+,如果增加了相应的索引,则单次查询大约耗时5s左右,性能提升10倍以上。

所以,理论联系实际,我们都应该在相关待检索的字段上增加索引,这次要提及和澄清的是增加Unique Index还是Index? 只增加Unique Index,还是Index即可?或者两种Index都需要? 在检索方面,Unique Index保持了数据的唯一性,实际兼有Index的功能,在被检索时提供同样的优化性能。

情况稍微复杂一些的例子是这样,当一个Unique Index增加到多个字段的组合上时,其Index的作用并不能想当然地将Index效果追加到每一个组合中的字段上。如下是 -MySQL 官方文档对于组合字段的Unique Index的描述。

-R/u2SN  ) “If the table has a multiple-column index, any leftmost prefix of the index can be used by the optimizer to look up rows. For example, if you have a three-column index on (col1, col2, col3), you have indexed search capabilities on (col1)(col1, col2), and (col1, col2, col3).
MySQL cannot use the index to perform lookups if the columns do not form a leftmost prefix of the index. ”

用简略地话来说,Unique Index的Index作用:1)当只有一个字段时,其Index作用也同样地施加到该字段上;2)当为多个字段的组合时,其Index的作用,只施加到组合的第一个字段上。

所谓差之毫厘,谬之千里。当待检索的字段是某个Unique Index的组合字段之一,且不是第一个时,被用做Where的查询条件,查询性能将急剧下降,每次皆是全表扫描,逐行对比。

这种性能隐患,在开发初期并不容易发现,只有当数据量级增长到10M+时,查询耗时才会逐步显现出来。

 

gwa2-logo-201606.v2

-GWA2 是”通用网络应用架构( General Web Application Architeture )”,基于 -GWA2 可以轻便构建各种网络应用程序, 
包括复杂的在线购物商城、 旅游交易平台、社群或者社交网站和新闻资讯网站等, 
也包括各种企事业单位网上门户,在线交互及服务作业系统等. 
还可以包括为NativeApp做服务器端支持, 甚至是WebApp的全部.
-GWA2 是为数不多的支持跨开发语言的应用框架,目前支持 -Java, -PHP, -Perl, -Aspx and -Python .
-GWA2 is a “General Web Application Architecture”, and based on -GWA2 developers can easily build a variety of network applications,
Including complex online shopping malls, travel trading platforms, community or social networking sites and news information sites, etc.
Also the applications include various enterprises and institutions online portals, online interaction and service operations systems.
And it also includes server-side support for NativeApp, or even all of the WebApp.
-GWA2 is one of the web frameworks which provide cross-language support for -Java, -PHP, -Perl, -Aspx and -Python at present.

-GWA2 is E.A.S.Y 
Easy Along, Swift Yield
轻松启动, 快速产出. 

Posted in -GWA2, 服务器运维, 计算机技术 | Tagged , , , , , | Leave a comment

Apache-Tomcat: 虚拟主机VirtualHosts

接续此前的 “嘗試 Apache + Apache Tomcat (簡稱 Tomcat)融合” , -R/H2SL ,和 第二篇,“apache tomcat: mod_jk missing uri map”, -R/n2SK ,  这次叙述一下在 Apache 和 Tomcat 下融合搭配虚拟主机 Virtual Hosts的事, 顺带回应前述,为何技术选型是 Apache + Tomcat ,而不是 Nginx + Resin ?

1. 为何选用“Apache + Tomcat”?
单一就性能而言, Ningx 在服务静态页面胜过 Apache , Resin 在服务动态页面上胜过 Tomcat,那么强强联手,Ningx + Resin 的搭配应该会胜过 Apache + Resin. 至少理论上是这样,然而理性的技术选型中,技术性能是一方面,也会考虑经济性,这也是一些互联网公司曾经有过的关于去 IOE (IBM, ORACLE和EMC,分别代表大规模计算, 数据处理和存储)的浪潮的一个依据。

在从计算机&IT业早期,我所接触的就是 Resin 作为Java的Application Server,多年过去之后,当我再次思考这个问题的时候,我的认识发生了改变,这次我选择了 Tomcat,而不是 Resin,经济是一方面,其开源和社区属性应该是另外一面,相应地性能优势已经不是那么明显。
由于硬件性能几十年来一直以摩尔定律(单位面积上的集成电路晶体管数量每18-24个月翻一倍,性能提升而价格-成本下降)的速度在发展,如果纯粹的开源软件无需考虑这些,而如果是以一定的成本购买来的性能提升,是否该软件带来的性能提升速度能够跟得上硬件摩尔定律的发展?
设若以1000$的硬件运行A软件(1000$)获得性能为1000个并发,B软件(0$)为500个并发;一两年后,1000$的硬件自然地能够运行B软件(0$)获得1000个并发。此时如果A软件(1000$)相应地预期应该能够获得2000个并发,如果不能,我们认为这笔开支是不理性的。实际运营需求,可能对性能的要求并没有快过硬件的摩尔定律式的发展。这一问题回归,就是花成本在购置软件上的获得性能提升是否值得或者经济,尤其是在分布式,云计算大行其道的情况下? 可能的场景是,如果现在花1000$购置某闭源软件带来+500个并发性能,而1-2年后,同样的硬件成本可以0$的获得+500个并发性能,此时额外的1000$到底该不该花?

决策时的另一个考虑是,无论是 Ningx 还是 Resin 其开源版本总是给人一种“阉割版”的印象,要想要更高级的功能,都需要花钱才能实现,这多少令人不爽。开源和闭源都可能打造较好的软件,但免费推出“阉割版”,然后根据高级功能收费,这种做法,在我看来是不合适的,只好对 Ningx 和 Resin 说再见,尽管他们在性能上有优秀的表现,我更相信对 Apache 和 Tomcat 的站队投资,能促使其不断成长、优化和改进,形成良性循环。

多年来,随着 -gMIS-GWA2 的成长、成熟,从软件开发者的角度,我越来越能理解到,一款所谓好的软件,就是有人不断地使用,不断地应对新的scenarios,不断地修正bugs,从而不断地健壮、丰富和强大。Apache, Tomcat 应该也是这样,软件发展注定会是马太效应,强者更强,弱者更弱,某个细分领域,某个独特场景下,最终可能只会存在1-2款软件。

几年前,在 -人民网 进行某个互联网项目前期调研时,其中对互联网应用的发展趋势,有个小结是,互联网因的越来越具有服务方式的排他性和内容格式的统一性——大白话就是某种应用(服务)只存在其本身就够了,天下无二;在其上,各种内容兼容并包,既有文字、图片、动画,也有音频和视频,基于这些小众内容分类创新也基本不用想了。

这是今次我这么选择 Apache + Tomcat 的原因。接下来继续回复关于在 Apache 和 Tomcat 下设置虚拟主机VirtualHost的细节。

2. Tomcat 的虚拟主机配置
虚拟主机的配置,在以前的blog里提到过,”apache, resin, ssl对虚拟主机的支持”,  -R/12SY , 这次就不再重复在 Apache 里设置虚拟主机的情况,转而重点在 Tomcat 对虚拟主机的支持及设置情况.

Tomcat对虚拟主机的支持,官方文档和网上教程也有一些,下面是一个小结。

在 Tomcat 的 conf/server.xml 中,在
<Server>
    –> <Service>
        –> <Engine>
            –> <Host> 
中并列地新增一个 <Host> 标记即可。例如,默认的 <Host> 形式为

<Host name=”localhost” autoDeploy=”true” appBase=”webapps” …

在此之后,并列的新增一个针对虚拟主机的 <Host>设置,一般情况的形式为

<Host name=”srvXXX.ufqi.com” autoDeploy=”true” appBase=”/www/webroot/srvXXX”>
    <Context path=”” docBase=”/www/webroot/srvXXX”></Context>
    <!– something else –>
</Host>

其中 “<Context>” 需求强调的是,如果不通过其设置 docBase, 按 Tomcat的默认,则请求 http://srvXXX.ufqi.com/abc.jsp 时会将解析指向默认 <Host> 的默认 docBase ,通常是 默认 <Host> 的 appBase , 也即 webapps/ROOT .
通过 <Context> 设置新的 docBase之后,这可以解决这一解析寻址路径,再次请求 http://srvXXX.ufqi.com/abc.jsp 路径时,会按图索骥地在 /www/webroot/srvXXX 目录下进行寻找,从而能够获得预期的请求资源。

进一步地,由于 Tomcat 的部署默认对象单位是 application,所以即便不指定 docBase ,在 /www/webroot/srcXXX 子目录(application)下的相应资源是能够被准确定位的。上述情况,如果不指定 docBase , 通过访问路径 http://srvXXX.ufqi.com/pathX/abc.jsp 则是能够获得相应地资源的。

3. 对SSL 的支持
在设置相应的虚拟主机时,如果在 Apache 上启用了 SSL支持,可能一般情况下都会启用,而且以后会成为默认选项。
按 “apache, resin, ssl对虚拟主机的支持”,  -R/12SY  的描述需要在 Apache 的 conf/extra/http-ssl.conf 中做相应的设置,才能使得 Apache + Tomcat 对 SSL 的预期的支持。

Posted in 服务器运维, 编程技术, 计算机技术 | Tagged , , , | Leave a comment

-gMIS持续优化更新, +InSiteSearch站内搜索

-gMIS 部署和应用的场景越来越多,最近在考虑为所有gMIS承载管理的数据库系统增加一个站内搜索功能, +InSiteSearch 。前因是在 2017年11月份的更新中,我们设想“层级目录导航是“传统”的,属于 Yahoo 时代的产物,未来的导航应该是 Google 式的智能导航。
未来拟开发一个 gMIS 域内全文搜索引擎,这样用户就无需使用或者记录层级目录。” (-R/p2SM)。 约半年后,我们实现了这方面的一个探索。

主要动机可以类比为Yahoo时代的目录搜索与Google时代的全文检索,当 -gMIS 所管理的对象超过一定数量级后,管理人员面临的问题就自然而然地迷失在多层复杂的目录式的导航中,如何有效地定位到目标功能模块成为迫切需要解决的问题。(在Google出现之前,用户想找某个主题/关键词的内容,需要去Yahoo的站点目录里去逐层逐级的查找相应的站点,Yahoo提供的网站目录满足了当时的需求)

站内搜索也被称之为局域网搜索Intranet search /Onsite search有别于互联网搜索Internet search. 其目的是搜索网址内部通常不公开的,格式化或者非格式化的内容。-gMIS 针对此项的规划远景是集成一个智能助理。

  1. 站内搜索InSiteSearch主要思路

    格式化数据的搜索是一个老课题。相对于非格式化数据,比如常见的网页数据,格式化数据有得天独厚的优势,我们能确切的预先知道,数据的格式、类型与规模。
    在获得这些之后又该怎样实现站内搜索呢?
    大致有两个思路,列如下。

    一是将待搜索的数据,读取到某个index service上实现对数据的indexing,当有某种关键词进行搜索时,按indexing的数据进行相应数据的返回。
    这种方式,是事先、同步地将所有格式化数据同步到indexing 服务,并实现相应的增删改的操作同步。
    也即,在格式化数据库/表之外,需要独立的建立一套应对全文搜索的数据结构存储系统,通常为 keyword–>pagelist 结构,也即某个待搜索关键词会对应一个包含该关键词的文档列表,其中列表的排序规则为某个权重值,其主要指标是为了表名当前关键词与当前文档的依存关系。
    若无意外,该indexing的数据存储结果将同等尺寸于原始格式化数据。
    另外一种思路,也即,是否可以为待搜索的数据提供某种roadmap(路书、地图),当有某种关键词进行搜索时,知道在什么地方以什么方式进行搜索。而实际数据的增删改人保留在原数据库/表中,当下的站内搜索InSiteSearch只是提供某种ShortCut服务,该服务能够实现以较为经济的、智能的方式,帮助调用者以较合理地方式返回预期的搜索内容。
    可以设想,在这种思路下,系统不需要创建一套indexing服务,也不需要额外地复制全部格式化数据副本作为待检索的对象。
    也即,当触发在全域进行某个关键词进行搜索时,InSiteSearch知道该关键词最可能出现在某些数据表的数据字段项上,而不太可能出现在其他字段项或者其他数据表相应的字段项上。
    这种路书(地图)导引式的搜索辅助设施,将极大地提升搜索范围和搜索精度,在格式化数据的搜索上,很好的契合了搜索需求的应用场景。

    两相比较,在 -gMIS 中,我们选用了,基于路书的指引式站内搜索方式。

  2. 站内搜索InSiteSearch的实现方式

    依据前述讨论,我们在 -gMIS 中实现了基于导引式地站内搜索实现。其主要操作内容如下。
    A. 创建 insitesearch 表
    用于存储当有基于某个关键词进行搜索时,所依赖的数据表路径。
    insitesearch表的生成主要依赖 /act/insitesearchsort.php 程序。
    该程序读取当前数据库连接下的所有数据表,并分析每个数据表的每个字段,如果发现当前字段数据可被检索字符串类型,通常为char(4-255),则将该数据库、数据表的数据字段记为待检索字段。
    以此循环所有数据表的所有数据字段,生成待检索数据字段列表。
    当有待搜索关键词递交到系统程序时, /extra/insitesearch.php , 站内搜索引擎程序按图索骥地逐个待搜索数据库、数据表、数据字段的进行检索。
    根据当前页的size设置,搜索到N个结果时,自动返回给调用者,以此形成翻页功能。

    B. 增加站内搜索入口
    对应地,我们在 进入系统主页和list view识图页面,在顶部导航栏增加了对 站内搜索 的接入功能,若用户需要进行站全域站内搜索,只需将待搜索关键词递交给搜索模块即可实现该功能。

    C. 动态更新搜索源
    辅助地,我们在 

    Π 首页  桌面 & 系统配置 → 搜索源配置 | 搜索源配置 

    增加了对 搜索源的配置与管理,在该模块可以实现对待搜索列表的手工更新与配置。当有新的数据模块被手工添加到当前数据库时,可以通过 “更新搜索源列表” 来实现对待搜索资源列表的更新与维护。

    D. 精细化操作的黑白名单设置
    同样地,我们在

    Π 首页  桌面 & 系统配置 → 搜索源黑白名单 | 搜索源黑白名单

    额外地增加了对待搜索源的黑白名单设置,以满足特性的运营需求,比如当某个数据库的数据表的数据字段被程序规则判定为“黑名单”时,可以在此将相应的条件设置为允许“白名单”;同样地,当某个数据库的数据表的字段被程序判断为“白名单”而通过系统检测,可以在此将相应条件设置为“黑名单”,以阻止其进入待搜索队列。

  3. UI批量更新与优化
    单条记录更新模块,增加了行间距,当字段之间跟容易识别;
    字段名称加粗显示,区别与字段值、字段备注等信息;
    列表显示时,增加了 break-all 属性,数据表默认不再撑破窗口,在纵向滚动和横向滚动中选择其一,仍不能排除某些情况下,纵横项同时滚动的可能;
    更新GTAjax,修正增加对 Array.sort 的支持;
    增加对List View下的活跃记录的所有字段值加粗显示,响应鼠标事件;
    增加对JavaScript更多的异步调用,页面提速更快;
    bugfix for getSelectOption;
    +checkSQLKeyword
    +allow multiple order fields

  4. 增删改查搜算
    截至 InSiteSearch 功能发布以后, -gMIS 的核心功能已经由 增删改查 升级为 增删改查搜算 (Create, Retrieve, Update, Delete, +Search, +Statistics)。
    其中”搜” 指的是增加了站内搜索功能,而算 则是指 -gMIS 中的数据透视功能,可以轻易地实现对目标数据表的各种维度的数据统计计算功能。
    可以预见 -gMIS 将从普通的通用信息管理功能逐渐升级改进,增加更多的商业智能功能模块,为业务运营支撑提供更多的信息数据与决策支持。

  5. GitHub 被 Microsoft 收购
    会影响到 -gMIS 在 -Github 的托管与开源吗?

 

gmis-logo-201606

-gMIS 是一种基于 -GWA2 的通用管理信息系统(Management Information System)软件,具有可配置的输入和输出接口。
可以在其上构建各种管理应用软件系统,如
内容管理系统(CMS),客户资源管理(CRM), 企业资源计划管理(ERP),
办公自动化系统(OA)等, 以及各种行业应用管理系统软件,如
人力资源管理系统(HR),学生管理,档案管理,旅游管理,图书管理,
商品管理及业务运营支撑系统等等。
实现零代码开发、快速搭建各种管理信息系统(MIS).

-gMIS is a -GWA2 based Management Information System (MIS) software with configurable input and output interfaces.
Various management application software systems can be built on it, such as
Content Management System (CMS), Customer Resource Management (CRM), Enterprise Resource Planning Management (ERP),
Office automation systems (OA), as well as different industry application management system softwares, such as
Human Resource Management System (HR), Student Management, Archive Management, Tourism Management, Book Management,
Commodity management and business operations support systems, etc.
With zero code development, -gMIS can build a set of management information systems (MIS) software in a minute.

Lower Costs, Better Productivity.
降低成本, 提高效率.

Posted in -gMIS, 服务器运维, 编程技术, 计算机技术 | Tagged , , , | 2 Comments

商业组织忠诚与职业道德

最近在读《Investments》(投资学, -R/G2SS )第十版,在其中“Excerpts from CFA Institute Standards of Professional Conduct”章节提到CFA对客户第一条要“Loyalty(忠诚)”,对雇主的要求中第一条也是要“Loyalty(忠诚)”。尤其是对客户的忠诚里,要求必须把客户利益的优先级放在自己的利益前面。这听起来与某些党派的对组织忠诚、先人后己的要求很相似,如果是这样,是不是觉得“党性”要求不那么苛刻?

顺着这个忠诚的话题,我捡了几个反例叙述,商业不忠诚及职业不道德的例子示以警示。

  1. 中介员工自己跳单
    做中介的最怕跳单,大意是在居间服务市场,买家和买家通过中介取得联系后自行交易,绕过了中介一方。这在中介市场是严重不允许的,中介居间费用也是中介赖以生存的源泉。所以如果买家、卖家任一方试图绕过中介进行跳单,必遭中介追诉。
    据闻眼下,有某中介组织员工可以自己设定跳单并私吞中介服务费用。当某员工履行职责引荐买家、卖家之后,撮合达成交易收取居间费用,但上报给中介组织的内容却是交易未达成,并以服务费打折、优惠为条件劝诱买、卖双方与自己保持一致的说辞。然后再通过某种方式取消此次买卖标的物的邀约。一切像没发生过一样。
    买家、卖家、中介员工三方均受益,而唯一受损的一方是中介组织。

    类似例子,似乎并不止于中介服务,其他组织中应该也存在,员工利用其组织平台谋取私利,并对组织谎报内容。

    以损害组织利益谋取私利实在罪有应得,却屡禁不绝,大致是人的本性使然,组织如何在一定程度上使之不能、不敢、不想这样?

    也据闻眼下有在不损害组织利益的情况下谋取私利,比如统计数据修改。

  2. 程序“魔法值”修改账单
    统计数据是组织进行商务活动所依赖的根本。实施统计数据修改,一般是内外勾结在一起进行。员工A与外部合作伙伴甲达成利益输送,员工A在其数据底层,通过修改日志、统计数据输出,将原本属于合作伙伴乙的收益算入到合作伙伴甲账上。进而,合作伙伴甲收到额外的空账后再分赃给员工A。
    表面上看,似乎天衣无缝一般。组织总账平衡,不多不少,员工A和合作伙伴甲都受益,唯一受损的是合作伙伴乙,但其并不知情。

    这一犯罪的实施,需要修改生产系统或者统计程序的源代码,而且要通过某种“魔法值”(未经定义的常量,语见《码出高效——阿里巴巴Java开发手册》,-R/92SP )来进行,也即所说的“后门”的一种。

    计算机程序代码通用规范中明确要求不能使用这种“魔法值”,而一些不遵守这样约定的软件通常以“高效”等要求直接在代码中使用这些魔法值,通过使用这样的“魔法值”来满足日益复杂多变的运营需求。久而久之陷入混乱的恶性循环,也为通过这样的“魔法值”修改来实施利益输送提供了温床。

    大型的软件及互联网企业,严格要求这一项,既有技术层面的代码规范、可读性要求,还有言下之意不允许额外的特例出现在代码层,从根本上杜绝了通过“魔法值”来实施犯罪。

    如果某些作业系统程序复杂、多变,且充满了“魔法值”,则这样的犯罪实施起来将得心应手,且死无对证。除了员工A和合作伙伴甲,无人知晓,而利益受损方合作伙伴乙并无感知,也不会发起追诉。

本质上,个体是趋利的,理性的思维又要求个体要遵守商业文明。个体选择扭曲价值观的不忠诚、犯罪,一定是群体的体制机制存在一定问题。列以上反例,大致也能从侧面显示商业环境的恶劣、人性的扭曲和制度的崩溃。

法国经济学家Thomas Piketty在其著作《Capital in the Twenty-First Century 》(21世纪资本)(-R/M2SM )中表示,社会财富正由拥有资产(土地、工厂、设备)等的“地主”向拥有知识与创新的“精英”转移,职业经理人将在财富分配中扮演越来越重要的角色,其对组织的忠诚度似乎也显得格外重要。

这种白手起家或靠发明创造而快速巨额致富成为可能的社会,被现任英国首相Theresa May在其演讲中称之为“MeritCracy”(-R/F2SO ),这似乎是对经济学家的发现的印证。 

经理人或员工是人,人本性是自私的,如果一个组织不能抑私扬善,职务犯罪则防不胜防,组织最终将溃于一个个自私的蚁穴。就像一个社会,如果不能弘扬正义、彰显公平,各种犯罪则愈演愈烈,社会最终将泯灭于一件件自私的犯罪下。

Posted in 社会生活 | Tagged , , , , | Leave a comment

[转]母亲的舍得

【编按】微信朋友圈传的文章,题目是自拟的,有人说可比语文课的《父亲的背影》,微言大义,是为推荐。

父亲去世10年后,在我的“软硬兼施”下,母亲终于同意来郑州跟着我——她最小的女儿一起生活。这一年,母亲70岁,我40岁。70岁的母亲瘦瘦的,原本只有一米五的身高,被岁月又缩减了几厘米,看起来更加瘦小,面容却仍然光洁,不见太多沧桑的痕迹,头发亦未全白,些许黑发倔强地生长着。 

我们借了一辆车回去接她,她早把居住了几十年的老屋收拾妥当,整理好了自己的行李。那些行李中有两袋面,是她用家里的麦子专门为我们磨的,这种面有麦香。但那天,那两袋面我决定不带了,因为车的后备箱太小,我们要带的东西太多。母亲却坚持把面带着,一定要带,她说。 

她这样说的时候,我忽然愣了一下,看着她,便想明白了什么,示意先生把面搬到里屋,我伸手在外面试探着去摸。果然,在底部,软软的面里有一小团硬硬的东西。如果我没猜错,里面是母亲要给我们的钱。 

把钱放在粮食里,是母亲很多年的秘密。十几年前,我刚刚结婚,在郑州租了很小的房子住,正是生活最拮据的时候。那时,我最想要的不是房子,不是一份更有前途的工作,只是一个像样的衣柜。就是那年冬天,母亲托人捎来半袋小米。后来先生将小米倒入米桶时,发现里面藏着500块钱,还有一张小字条,是父亲的笔迹:给梅买个衣柜。出嫁时,母亲给我的嫁妆中已有买衣柜的钱。后来她知道我将这笔钱挪做他用,便又补了过来。那天晚上,我拿着10元一张厚厚的一沓钱,哭了。那些年,母亲就是一次次把她节省下来的钱放在粮食里,让人带给我,带给大姐二姐,在我们都出嫁多年后,仍贴补着我们的生活。但那些钱,她是如何从那几亩田里攒出来的,我们都不得而知。这一次,即使她随我们同行,也还是将钱放到了面袋里,在她看来,那是最安全的。

面被带回来后,我把钱取出来交还母亲,母亲说,这是我给童童买车用的。童童是她的外孙,这段时间他一直想要辆赛车,因为贵,我没有给他买,上次回老家,他许是说给母亲听了,母亲便记下这件事。2000块,是她几亩地里一年的收成吧,我们都不舍得,但她舍得。记忆中,母亲一直是个舍得的人,对我们,对亲戚,对左邻右舍,爱舍得付出, 东西舍得给,钱舍得借,力气也舍得花。有时不知道她一个瘦小的农村妇人,为什么会这样舍得。母亲住下来,每天清晨,她早早起来做饭,小米粥、小包子、鸡蛋饼……变着花样儿。中午下班我们再也不用急赶着去买菜,所有家务母亲全部包揽。阳台上还新添了两盆绿莹莹的蒜苗,有了母亲的家,多了种说不出的安逸。 

母亲带来的两袋面,一袋倒入桶里,另外一袋被先生放到了阳台上。过了几天,我却发现阳台地板上的那袋面被移到了高处的平台上晾晒。先生是个粗心的人,应该不会是他放的,我疑惑地问母亲,她说,啊,我放上去的,晒晒,别坏了。我一听就跟她急了,那平台, 一米多高 ,那袋面,六七十斤,身高不足 一米五,体重不足90斤的母亲,竟然自己把它搬了上去。我冲她大喊,你怎么弄上去的?那么沉,闪着腰怎么办?砸着你怎么办?出点儿什么事怎么办……一连串地凶她。她却只是笑,围着围裙站在那里,等我发完脾气,小声说,这不没事吗?有事就晚了!我还是后怕,但更多的是心疼。直到母亲向我保证,以后不再干任何重活,我才慢慢消了气。 

母亲来后不久,有天对先生说,星期天你喊你那些同学回家来吃饭吧,我都来了大半个月了,没见他们来过呢。先生是在郑州读的大学,本市同学的确很多,关系也都不错,起初还会在各家之间串门,但现在,大家都已习惯了在饭店里聚会。城市生活就是这样繁华而淡漠,不是非常亲近的,一般不会在家里待客了。我便替先生解释,妈,他们经常在外面聚呢。母亲摇头,外面哪儿有家里好,外面饭菜贵不说,也不卫生。再说了,哪儿能不来家呢?来家才显得亲。然后,母亲态度坚决地让先生在周末把同学们带回家来聚一聚。我们拗不过她,答应了。 

先生分别给同学中几个关系最亲近的老乡打了电话,邀请他们周末来我们家。周末一整天,母亲都在厨房忙碌。下午,先生的同学陆续过来了,象征性地提了些礼品。我将母亲做好的饭菜一一端出,那几个事业有成、几乎天天在饭店应酬的男人,立刻被几盘小菜和几样面食小点吸引过去。其中一个忍不住伸手捏起一个菜饺,喃喃说,小时候最爱吃母亲做的菜饺,很多年没吃过了。母亲便把整盘菜饺端到他面前,说,喜欢就多吃,以后常来家里吃,我给你们做。那个男人点着头,眼圈忽然就红了,他的母亲已经去世多年,他也已经很久没回过家乡了。 

那天晚上,大家酒喝得少,饭却吃得足,话也说得多。那话的内容,也不是平日在饭店里说的生意场或单位里、社会上的事。很少提及的家事,被慢慢聊起来,说到家乡,说到父母……竟是久违的亲近。那以后,家里空前热闹起来。母亲说,这样才好,人活在世上,总要相互亲近的。 

母亲来后的第三个月,一个周末的下午,有人敲门,是住在对面的女人,端着一盆洗干净的大樱桃。女人有点儿不好意思地说,送给大娘尝尝。我诧异不已,当初搬过来时,因为装修走线的问题,我们和她家闹了点儿矛盾。原本就不熟络,这样一来,关系更冷了下来,住了3年多,没有任何往来。连门前的楼道,都是各扫各的那一小块儿地方。她冷不丁送来刚刚上市的新鲜樱桃,我因摸不着头脑,一时竟不知该说什么好。她的脸就那样红着,有点儿语无伦次,大娘做的点心,孩子可爱吃呢……我才恍然明白过来,是母亲。母亲并不知道我们有点儿过节儿,其实即使知道了,她还是会那么做,在母亲看来,”远亲不如近邻”是句最有道理的话。所以她先敲了人家的门,给人家送小点心,送自己包的粽子,还送自己种的新鲜小蒜苗……诚恳地帮我们打开了邻居家的门。后来,我和那女人成了朋友,她的孩子也经常来我们家,奶奶长奶奶短地跟在母亲身后,亲好得犹如一家人。 

邻居们,不仅仅是对门,前后左右,同一个社区住着的许多人,母亲都照应着。她常在社区的花园和先生同事的父母聊天,帮他们照顾孙子。不仅如此,还有物质上的往来,母亲常常会自制一些风味小点,热情地送给街坊四邻,这也是母亲在农村生活时养成的习惯。小点心虽然并不贵重,却因有着外面买不到的醇香味道,充满了浓浓的人情味。 

有一次,得知先生一个同事的孩子患了白血病,母亲要我们送些钱过去。因为是来往并不亲密的同事,我们只想象征性地表示一下,母亲却坚决不答应,说,人这辈子,谁都可能会碰到难事,你舍得帮人家,等你有事了,人家才会舍得帮你。孩子生病对人家是天大的难事,咱们碰上了,能帮的就得帮。我们听了母亲的。 

在母亲过来半年后,先生竟然意外升职,在单位的推荐选举上,他的票数明显占了优势。先生回来笑着说,这次是妈的功劳呢,我这票是妈给拉来的。我们才发现,最近我们的人际关系竟然空前好起来,那种好,明显地少了客套多了真诚。一个字都不识的母亲,只是因为舍得,竟不动声色地为我们赢得了那么多,是我们曾经一直想要赢来却一直得不到的。再想她说过的话,你舍得对人家好,人家才会舍得对你好。于她,这是一个农村妇人最朴实本真的话;于我们,无疑是一个太过深刻的道理。 

温煦的日子里,我很想带母亲到处走走。可母亲因为天生晕车,坐次车如生场大病,于是常拒绝出门。那个周末,我决定带她去动物园。母亲说,没有见过大象呢。动物园离家不远,几站路的样子。母亲说,走着去吧。我不同意,几站路,对一个70岁的老人,还是太远了。可她又坚决不坐车,我灵机一动,妈,我骑车带你去。母亲笑着同意了。我推出车子,小心地将她抱到前面的横梁上,一只胳膊刚好揽住她。抱的时候,心里一疼,她竟然那么轻,蜷在我身前,像个孩子。 

途中要经过两个路口,其中一个正好在闹市区。小心地骑到路口,是红灯,我轻轻下车,还未站稳,却有警察从人流中穿过来,走到我面前说,不许带人你不知道吗?还在前面带。说完,低头便开罚单。母亲愣了一下,攥着我的胳膊要下来,我赶忙扶稳她,跟那个年轻的警察说了声对不起,解释说,我母亲晕车,年纪大了,不能坐车,我想带她去动物园看看…… 

警察也愣了一下,这才看清我带的是一位老人,还不等他说什么,母亲责备我,你怎么不告诉我城里骑车不让带人呢?然后坚持要下来。我正不知所措,那个警察伸手一把搀住了母亲,大娘,对不起,是我没有看清楚, 城里只是不让骑车带孩子,您坐好。然后他忽然抬起手,向我认认真真地敬了个礼。接着,他转身让前面的人给我腾出一个空间,打着手势,阻止了四面车辆的前行,招手示意我通过。我带着母亲,缓缓地穿过那个宽阔的路口,四面的车辆静止行人停步,只有我带着母亲在众人的目光里骄傲前行。 

那是我有生以来第一次受到如此厚重的礼遇。因为母亲,因为舍得给予她一次小小的爱,一个萍水相逢的年轻警察,便舍得为我破例,舍得给我这样高的尊敬。这礼遇,是母亲送给我的。 

母亲是在跟着我第三年时查出肺癌的。 结果出来以后,有个做医生的朋友诚恳地对我说,如果为老太太好,不要做手术了,听天命尽人事吧。这是一个医生不该对患者家属说的话,却是真心话。和先生商议过后,决定听从医生的安排,把母亲带回了家。又决定不向母亲隐瞒,于是对她讲了实情。母亲很平静地听我们说完,点头,说,这就对了。然后,母亲提出要回老家。 
母亲在世的最后一段时间,我陪在她身边。药物只是用来止疼,抵挡不了癌症的肆虐。她的身体飞快地憔悴下去,已经不能站立,天好的时候,我会抱她出来,小心地放在躺椅上,陪着她晒晒太阳。她渐渐吃不下饭去,喝口水都会吐出来,却从来没有流露过任何痛苦的神情,那些许黑发依旧倔强地蓬勃着,面容消瘦却光洁,只要醒着,脸上便漾着微微的笑容。那天,母亲对我说,你爸他想我了。妈,可是我舍不得。我握着她的手,握在掌心里,想握牢,又不敢用力,只能轻轻地。梅,这次,你得舍得。她笑起来,轻轻将手抽回,拍着我的手。但是这一次,母亲,我舍不得。我说不出来,心就那么疼啊疼得碎掉了。母亲走的那天,送葬的队伍浩浩荡荡,从村头排到村尾,除了亲戚,还有我和先生的同学、朋友、同事,我们社区前后左右的邻居们……很多很多人,里面不仅有大人,还有孩子,是农村罕见的大场面。 
队伍缓缓穿行,出了村,依稀听见围观的路人中有人议论,是个当官的吧?或者是孩子在外面当大官的……母亲这一生,育有一子三女,都是最普通的老百姓,不官不商。母亲本人,更是平凡如草芥,未见过大的世面,亦没有读过书,没有受过任何正规教育,她只是有一颗舍得爱人的心。而她人生最后的盛大场面,便是用她一生的舍得之心,无意间为自己赢得的。 

Posted in 社会生活 | Tagged | Leave a comment

apache tomcat: mod_jk missing uri map

接续此前的 “嘗試 Apache + Apache Tomcat (簡稱 Tomcat)融合” , -R/H2SL , 出现异常,在 https 下tomcat可以接管解析jsp页面,但在http却不行,于是使劲检查如下。

apache tomcat: mod_jk missing uri map

首先排除了所有因为url格式不匹配的情况下,在 conf/extra/httpd-jk.conf  打开日志为 trace :

# Our JK log level (trace,debug,info,warn,error)
JkLogLevel trace

需要检查,URI的匹配的写法,在 

conf/extra/uriworkermap.properties

中进行修正:

# java ??
/*\.jsp=balancer 

如果仍有问题,需要进行下面的配置命令的检查。

JkMountCopy On 

的设置,这一语句通常需要在所有 VirtualHost 和 SSL 的 VirtualHost 里面,

涉及到的Apache Httpd的配置文件有

conf/extra/httpd-vhosts.conf 
conf/extra/httpd-ssl.conf 

 

Posted in 服务器运维, 编程技术, 计算机技术 | Tagged , , | Leave a comment

-gMIS 中操作同时并发操作和管理多个数据库multiple databases

如前所述,我们实现了 -gMIS 中可以同时并列/并行/并发管理多个数据库的目标数据表,
“-gMIS 更新多库连接及工作流workflow” , -R/b2SI ,

新近部署了一个 -gMIS 的应用实例,也涉及到跨数据库的信息管理系统,于是归集整理了在 -gMIS 中操作多个数据库的使用步骤,列如下,备忘。

  1.  inc/config.class 中添加数据库配置信息
    ….
    # db slave info
    $conf[‘dbhost_slave’] = ‘127.0.0.1’; 
    $conf[‘dbport_slave’] = ‘3306’;
    $conf[‘dbuser_slave’] = ‘dbuser’;
    $conf[‘dbpassword_slave’] = ‘dbpassword’;
    $conf[‘dbname_slave’] = ‘dbname’; 
    ….

  2.  inc/conn.class 中创建数据库连接所需的对象
    ….

    class Db_Slave{

        var $mDbHost = “”;

        var $mDbUser = “”;

        var $mDbPassword = “”;

        var $mDbPort = “”;

        var $mDbDatabase = “”;

        function __construct(){

            $db_suffix = ‘_slave’;

            $gconf = new Gconf();

            $this->mDbHost = $gconf->get(‘dbhost’.$db_suffix);

            $this->mDbPort = $gconf->get(‘dbport’.$db_suffix);

            $this->mDbUser = $gconf->get(‘dbuser’.$db_suffix);

            $this->mDbPassword = $gconf->get(‘dbpassword’.$db_suffix);

            $this->mDbDatabase = $gconf->get(‘dbname’.$db_suffix);

        }

    }
    ….

     

  3.  class/gtbl.class 中添加所需指定数据的连接对象

    在类的 __construct 方法中,在调用父类的 __construct 之前,
    ….

    if($args[‘dbconf’] == ‘default’){

        $args[‘dbconf’] = ‘Db_Master’;

    }

    else if($args[‘dbconf’] == ‘slavedb’){

        $args[‘dbconf’] = ‘Db_Slave’;

    }

    ….

  4.  在管理界面设置数据表所需连接的数据库名称(别名)
    在 Π 首页  桌面 & 系统配置 → 菜单调整 | 菜单调整 路径中增加针对某个被管理对象表时,指定所需连接的数据库.


    在 菜单管理中,增加对被管理对象时,设置所需链接的数据库.

 

-gMIS 是一种基于 -GWA2 的通用管理信息系统软件,具有可配置的输入和输出接口。
可以在其上构建各种管理应用软件系统,如
内容管理系统(CMS),客户资源管理(CRM), 企业资源计划管理(ERP),
办公自动化系统(OA)等, 以及各种行业应用管理系统软件,如
人力资源管理系统(HR),学生管理,档案管理,旅游管理,图书管理,
商品管理及业务运营支撑系统等等。
实现零代码开发、搭建各种管理信息系统(MIS).

Lower Costs, 降低成本; Better Productivity, 提高效率.

Posted in -gMIS, 编程技术, 计算机技术 | Tagged , , , | Leave a comment

信息加解密与摘要Encryption and Message Digest

这篇短文最早写在 -Maimai 上,后来转发到 -Linkedin 上,再后来备份到 -Wordpress-wadelau 上,现在再复制到 -Ufqi-Blog 上。

关于账号密码的保存,昨天回复的仓促,重理一下。

先区分是加密和信息摘要,两者区别是内容是否可逆。能从密文恢复到原文的是加密,不能的是消息摘要,或信息摘要。加密又可分为算法加密和使用秘钥加密,区别是在加解密过程中是否使用“秘钥”。置换、交换、取模异或等可看做无秘钥加密,仅依靠某种算法实现加密。

使用“秘钥”加密又分为对称加密和非对称加密。区别是对称加密收发两方用同一个密钥,非对称基于一对密钥: 公钥和私钥。发方用收方的公钥加密,收方用自己的私钥解密密文;或者发方用自己的私钥加密,收方用发方的公钥解密。

回到密码保存这个话题,明文存储不是人干的事。密文存储是业界标准做法。至于密文是加密后内容,还是明文的消息摘要,一般从形式上可以判断,消息摘要多会生成一个由0-9, a-f的字符串。密文则各种字符串形态均有,如 -base62x 的输出。

消息摘要一般能满足账号密码保护需求,但自从md5被碰撞算法找回原型后,md5就不安全用在密码上了。这方面可以选升级的md6, sha1, sha256, sha512, sha1024等。

至于加密的对称算法,有很多。加密的非对称算法,也有不少,多用rsa。

加解密,矛和盾。哪个锐利,哪个坚厚?

%e5%8a%a0%e5%af%86encrypt%0a%e6%b6%88%e6%81%af%e6%91%98%e8%a6%81digest%0a%e7%bc%96%e7%a0%81coding%0abyxenxin-201608

Posted in Base62x, 编程技术, 计算机技术 | Tagged , , , , , , | Leave a comment

擰巴 Apache Httpd 和 Tomcat 到一起

此前Apache HTTPD (簡稱Apache) + Caucho Resin作爲 Java 容器,

現在嘗試 Apache + Apache Tomcat (簡稱 Tomcat)融合在一起愉快地工作。

爲何不是 Ningx + Resin 融合在一起工作?

  1. 安裝 Apache Httpd
    配置站點根目錄 /path/to/apache/document_root
  2. 檢視Apache是否成功安裝
    查看 apxs目錄, /path/to/apache/bin/apxs
  3. 安裝mod_j
    下載 tomcat-connectors
    按手冊配置,./configure –with-apxs=/path/to/apache/bin/apxs
    編譯出 mod_jk.so
    複製 mod_jk.so 到 /path/to/apache/modules/mod_jk.so
    複製  tomcat-connectors/conf下的 httpd-jk.conf 到 /path/to/apache/conf/extra 下
    複製 tomcat-connectors/conf下的 uriworkermap.properties  , workers.properties 到 /path/to/apache/conf/extra 下
    修改 apache/conf/httpd.conf 增加: 
        # java
        Include conf/extra/httpd-jk.conf
    修改 apache/conf/extra/httpd-jk.conf :
         JkWorkersFile conf/extra/workers.properties
         JkMountFile conf/extra/uriworkermap.properties
        JkLogLevel trace 
        info –> trace 跟進觀察所有流程
    修改 apache/conf/extra/workers.properties :
          worker.node1.port=8009
          worker.node2.port=8009 
          如果衹有一個node的話,將loadbalancer的兩個端口改爲一樣,
         具體端口數字需要與Tomcat的實際保持一樣
    修改 apache/onf/extra/uriworkermap.properties :
          /*.jsp=balancer
          攔截所有 .jsp 的程序給 Tomcat 來處理
    如果Apache 啓用了SSL,則需要修改 apache/conf/extra/httpd-ssl.conf:
           在 <VirtualHost _default_:443> 項下,增加:
            # java?
            JkMountCopy On
  4. 檢視mod_jk是否安裝成功
    如果 訪問 /a.jsp 被映射到 tomcat ,則測試成功
  5. 安裝Apache Tomcat
    配置 tomcat/webapps/ROOT 為 apache的document_root :
          shell> ln -s /path/to/apache/document_root /path/to/tomcat/webapps/ROOT
  6. 檢視Tomcat是否安裝成功
  7. 融合在一起
  8. 檢視融合在一起
Posted in 服务器运维, 编程技术, 计算机技术 | Tagged , , , , , | 1 Comment

Base62x比Base64的编码速度更快吗?

Base62x与Base64的编码速度测评

现在几乎所有企事业单位、政府机构、军工系统等的IT生产系统都会用到Base64编码,从RSA安全密钥到管理信息系统登录入口回跳,目前越来越多的IT系统研发者开始使用 Base62x 替换 Base64.

Base62x 提供了一种无符号输出的Base64的编码方案,在许多应用场合其纯字母和数字的输出形式,可以有效的规避因为符号带来的各种负面影响,并能够有效削减或兼容各种Base64的变种形式。

借着 Base62x 在 -GitHub 上获得几个赞之后,我们探讨另外一个问题,Base62x 的编码在输出文本形式上略胜一筹,是值得推荐的替代方案,但其编码速度和效率如何?

为此我们设计一个评测任务,分别使用Base62x 和 Base64进行20万次编码操作,其中Base62x 使用 PHP的ext module方式实现的 base62x_encode , Base64 也是 PHP内置的 base64_encode , 两种均是使用C语言实现,并通过扩展方式集成在 PHP中,相对而言,可比性较好. 运行主机是在 Windows下虚拟主机运行 OpenSuSE 42,Nginx 1.12, PHP 7.0.
通过脚本Command Line调用方式进行20万次编码任务,对比测试数据:

base62x 200000 timestart:1513077337.6748 timecost:0.30399990081787
base64 200000 timestart:1513077337.9788 timecost:0.16817998886108

base62x 200000 timestart:1513077401.2177 timecost:0.29567098617554
base64 200000 timestart:1513077401.5134 timecost:0.17081189155579

base62x 200000 timestart:1513077424.234 timecost:0.30112099647522
base64 200000 timestart:1513077424.5351 timecost:0.1718909740448

base62x 200000 timestart:1513077447.9861 timecost:0.29450607299805
base64 200000 timestart:1513077448.2806 timecost:0.16546702384949

base62x 200000 timestart:1513077470.7367 timecost:0.45493698120117
base64 200000 timestart:1513077471.1917 timecost:0.24029588699341

运行5次之后,Base62x 和 Base64 其均值分别为,0.330047 和 0.183329 . 由此可见,Base62x 比 Base64 在编码速度上稍慢,20万次操作耗时比值为 1:0.555 , 尽管每次操作其耗时差(7.33589E-07)可以忽略不计,但考察比值,Base62x 慢了大约 44.5%,大致是 Base64 完成两个编码操作, 目前版本的 Base62x 完成一个多一点的编码操作。

如果加上在应用层的各种判断,使用 Base62x 替代 Base64 可能是有优势的,比如判断是否包括+,进而转化为空格,是否包括等号等,因为任何一步额外的判断或替换操作,其耗时将可能远超过 Base62x 与 Base64 操作耗时的差值。

比如其中一个 URLEncode 的应用场景,在 -github/wadelau/gMIS/comm/ido.js 中( -R/J2SI ):

var actx = unescape(tObj.action);
actx = actx.replace(+, );  

取代的改进使用Base62x的方案是:

var actx = Base62x.decode(tObj.action);
 /* no more action needed */

从代码层分析耗时差值原因,尽管两者都使用了位操作进行计算,但 Base62x 在单位编码长度上多了数值判断,由此导致其速度下降。Base62x 还是新事物,其代码应该还有可以再改进优化的空间。

如果进一步改进优化,Base62x 有可能与 Base64 相同的编码速度吗?

有没有可能存在另外一种不需要数值判断,也能够满足与 Base62x 一样无符号输出的64进制编码方案?

小结,单就编码速度而言, Base64 方案快,如果加上其他判断与替换操作, Base62x 方案胜出,未来可能会有鱼(无符号输出)和熊掌(速度)兼得的新编码方案出现。

Posted in Base62x, 编程技术, 计算机技术 | Tagged , , , | 2 Comments

软件编程技术水平的标志性关键点分析

Title: 软件编程技术水平的标志性关键点分析

刘振兴 / Liu Zhenxing

摘要:软件编程技术水平的考评与分级是困难的, 同时也是必要的。本文在相关文献检索和经验总结的基础上提出了软件编程技术水平的三个具有标志性的关键点并逐一对其进行简述和应用分析. 这三个分水岭一样的关键点是正则表达式、软件开发框架的掌握与运用和现实世界问题数学模型创建技能的掌握与运用。与之对应地我们称呼具备相应技能水平的人员为工程师、高级工程师和技术专家。

关键词:软件编程;技术水平;正则表达式;软件开发框架;数学建模

中图分类号:TP311.5                     文献标识码:

An Analysis on Key Points of Software Programming Technology Level

LIU Zhen-Xing[1]

【Abstract】It is not only difficult but also necessary for software programming technology level of assessment and classification in software industry and Internet+ sectors. Based on the related literature search and directional experience, this paper puts forward three key points of software programming technology level and analyzes them briefly on their applications one by one. The watershed-like three points are regular expression, the mastery and application of the software development framework and the mastery and application of the creation of skills in the mathematical model of the real world. Correspondingly, we call them with the appropriate level of skills as the engineers, senior engineers and technical experts.

【Key words】Software Programming; Technology Level; Regular Expression; Software Framework; Mathematical Modelling

1   引言

计算机专业及软件产业属知识密集型领域,其中最重要的资源是人力资源,软件开发人才的培养与甄选日益重要。同时,传统软件行业的快速发展叠加移动互联网、互联网+、人工智能战略布局稳步推进,催生了大量的软件开发从业人员。对软件编程水平及能力的评估是一件复杂而又严肃的事情( -R/02SI , [1] [2]),出于对自身或者同行技术能力的评估需求 [3],也需要在某些方面从某种程度上,对编程水平及能力有些大概粗略的感性认识。关于软件工程美国IBM公司的软件技术专家布鲁克斯(Frederick Brooks)在其论文中提到软件编程受目标任务的复杂度、一致性、可变性和不可见性的约束,在各种约束条件下取得均衡和达成目标就是对软件编程技术及水平的考察与验证 [4] [5]。

IT行业技术巨头往往会开展一些编程技术水平认证,如微软公司的MSDN,思科公司的CCIE等;一些行业学会、协会也会推出一些编程技术水平认证,如美国IEEE下计算机协会的各种认证和中国计算机学会的“CCF计算机职业资格认证” [6]。这些认证往往是基于某些厂商自家产品或者囿于特定领域的认证。是否有通用的可供参考的软件编程水平的参考标准?带着这个疑问,我们进行一些文献检索,同时结合我们多年学习、工作中编程实践、思考与经验总结,在本文如下部分提供如下三点作为软件编程技术水平的参考。

中国近代学者王国维将做学问的状况划分为三个境界,分别是“望尽天涯路”、“为伊消得人憔悴”和“那人却在灯火阑珊处”。写程序研发软件也有如下三个具有标志性的关键点,我们称之为软件编程的三个分水岭一样的标志性关键点,他们分别是正则表达式的运用、软件开发框架的掌握与运用和现实问题数学建模的掌握与运用。

余下的章节中,第二节我们讨论了正则表达式及模式识别相关的理论及技术应用,第三节讨论了软件开发框架在软件研发及其生命周期中的地位及作用,第四节讨论了针对现实世界问题进行数学模型创建的相关应用,然后是针对全文的总结和展望。

2   正则表达式

正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串,可以视之为狭义上的模式识别(Pattern Recognition),也可以将其视作在某种编程语言下的子类语言——用来描述其他语言的“语法”。使用它有一定的难度,句法全由符号表达,看起来抽象,可读性差,不容易理解。比如,

/^([0-9]{1,6})$/g

表示任意1位到6位的数字,也即0~999999 ,在匹配结果集中,将反向引用被匹配到的数字串,

/^(\d{1,6})$/

表示与前文相关的语法。下图(图 1)展示一个正则表达式工作机制的应用程序 [6],将前述正则表达式输入到“Regular Expression”相关区域,在“Test String”里输入相应待检测、匹配的文字,则下面“Match Information”区域会显示匹配过程及结果。


图 1 正则表达式匹配样例
Figure 1 Example of Regular Expression

正则表达式被广泛的应用于很多软件中,包括 *nix(Linux, Unix等)、HP 等操作系统,PHP、C#、Java 等开发环境,以及很多的应用软件中,都可以看到正则表达式的影子。如对外部输入的校验、提取,对目标对象的格式化等。

每种编程语言在进阶开发和使用时都有不少需要特别关注的地方,如指针、内存、链表和树、正则匹配等,若在这些不同的语言之间寻找共性的进阶开发所需掌握的技能,则正则表达式是其中关键点之一。

掌握了某种编程语言的基本数据结构和流程控制之后,一名软件工程师(或称程序员)若能够运用某种编程语言进行读写文件、数据库和通过网络收发数据,则其就是一名合格的软件工程师。具备这样素质的人可以胜任一般的软件开发任务,能够面向任务较好地完成给定的软件开发需求,实现相应的功能。

由于计算机科学兴起之处,其主要应用是对数据和文本的处理,所以正则表达式成为进阶开发的必由之路也在情理之中。初阶的开发人员往往止步于使用字符串查找、分割等方式来部分地完成相应功能。

正则表达式本身就是一门学问,已经有很多书籍专门就此展开详述,其中有本《精通正则表达式》(Mastering Regular Expressions)的书 [8],在豆瓣网有一个广为赞许的评价为面向“愿意从一个代码工人向专家进化的” (-R/A2SI )。

相比较而言,掌握和熟练使用正则表达式工具的软件编程人员能够高效而准确地实现相应的功能,我们称之为第一个分水岭。

3   软件开发框架

软件开发框架(Software Development Framework)软件开发框架(Framework)是代码组织和软件逻辑实现的思考方式。这种思考更多的是“管理”的视角,而非计算科学技术的视角。这种管理的方式是建立在对软件编程技术较深入、全面理解的基础上的。一般意义上的软件框架,是指为解决一个开放性的计算问题而设计的具有一定约束性的软件支撑结构。在此结构上可以根据具体问题扩展、安插更多的组成部分,从而更迅速和方便地构建完整的解决问题的IT技术方案 [9] [10] [11] [12]。软件框架本质上是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法。简而言之,是构建结构及实例交互方法的结合体。

一名软件编程人员在掌握了某一种编程语言之后,随着所解决的单个、多个任务的积累,终将会面临一个复杂任务——任务复杂到不能通过一个或几个小程序能够实现和满足其功能,这时候就需要从整体上思考,需要多少个程序(模块),这些程序和模块之间如何交互?软件框架就是要回答这些问题。

3.1          软件开发框架的特征

软件框架是成功软件项目的一般化实现。进入视野或者进行开源的多数软件框架都经历过一个或者多个成功项目的检验,是成功经验的积累。软件编程者当完成一个项目后,如果发现项目本身有可以进行一般化处理的代码段或功能模块,会对其进行封装以便后续使用,软件的组成架构设计也是这样,当发现所用的设计具有一般性后,就可以在随后的项目中继续使用,继而形成“框架”。框架不一定都开源,一些私有的或者基于开源定制的框架可能在某些方面具有更好的表现。

软件框架普遍实现了关注点分离设计(Separation of Concerns)和代码复用(Code Resue)。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过侧面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好的管理起来,如常见的MVC分层设计(模块Module、视图View和控制器Controller)。


图 2 架构设计中的关注点分离
Figure 2 Separation of Concerns in Framework Design

代码复用本质上就是对曾经编写过的程序代码的一部分甚至全部重新加以利用,从而构建新的程序。使用这种方法就可以将程序员从费时费力的重复劳动中解放出来。框架(类库)是一种代码复用的很好的形式。编程人员可以创建内部抽象以便程序的部分代码可被复用,或者直接创建一个自定义库给自己使用。一个规划和设计良好的框架应该是实现了上述两点。

清晰的关注点分离和高效的代码复用是避免软件项目陷入泥潭(the ball of mud)的基础和前提,也是软件项目成功的保证。

3.2          跨语言的软件开发框架

各种编程语言分别有许多不同的软件框架。例如,C++编程语言的框架(类库)有.Net、STL、Boost、Qt、MFC等;Java编程语言的框架有Structs、JSF、Spring MVC、Wicket、Stripes、Seam、GWA2等;PHP编程语言的框架有Zend Framework、Yii、Code Igniter、Lavarel、Symfony2、GWA2等;JavaScript编程语言的开发框架有Angular.js、Backbone.js、D3、jQuery.js、React.js等。

一个软件开发框架一般都与所使用的某种编程语言高度绑定。这一方面是框架需要高度复合利用了编程语言的特性,使之能够在该框架下将其性能发挥至极致;另一方面是框架的开发者和使用者需要具备指定开发语言的软件编程的基本知识。在此之外,也有为数不多的跨编程语言的软件开发框架,比如上文提到的“通用网络应用架构(GWA2) [13]”——提出一种软件架构思路,然后分别使用Java、PHP、Perl、C#等语言进行实现,从而有了针对各个编程语言的软件开发框架的版本。软件开发人员在其中一门编程语言下使用GWA2之后,可以无缝平滑地切换到另外一种开发语言继续使用对应版本的GWA2进行开发,重新学习成本降低为几乎为零。


图 3 GWA2 多层架构设计(DBA)
Figure 3 Multiple Layers in GWA2 (DBA)

通常软件编程对软件框架的应用可以分为两类:学习和使用一种软件框架,或者自行开发一套软件框架。学习有学习的成本 [14],开发也有相应的开发风险。显然,前者会更多一些,许多软件编写都是遵循某种软件框架而进行的。对软件框架和类库应该持有某种谨慎的态度,我们在早前针对JavaScript编程的框架做过一些分析(《自行创建类jQuery的JavaScript库》, -R/02SH , [15]),在学习成本、需求匹配度和框架性能三个方面需要做一些权衡。

相比较而言,我们推荐使用具有跨语言特性的软件开发框架,由于软件技术自身发展和开发人员自身成长是日新月异的,所处的时空变换要求每一名开发人员要掌握两种以上软件开发语言,相应地,如果其所依赖和学习的软件开发框架没有跨语言特性,则软件开发人员就需要付出两倍的学习成本;相反地,如果开发人员使用的是具有跨语言特性的开发框架,如上所述的GWA2,则可以平滑无缝地切换到新编程语言中去,无需再从零开始学习另外一种软件开发框架。

像武学的拳术一样,一招一式组成一套拳法,也像文学的八股一样,起承转合组成一篇文字,软件编程中的这套拳法就是“框架”。软件框架没有好坏,或者都是“好的”,使用者所需工作是寻找“合适的”,因时因地使用能够满足业务需求的框架就是合适的,是好的,既要避免不足(Underqualified),也要考虑不会多余(Overqualified)。 

我们将软件编程的第二个分水岭视为使用软件框架进行开发。无论是学习一个现有的软件框架或者开发一个全新的框架,都需要完整的软件框架知识。开发一个全新的框架需要知识、勇气和精力,而学习一个现有的框架其应用水平该如何来衡量呢?是否对原软件框架的源代码递交过Bug或做过修改、打过补丁,这是在读懂源代码的基础上对软件框架有进一步提升的动议。

4   现实问题数学建模

学习计算科学与技术,在掌握了基本的学科知识之后,应用层面所面临的专业细化就是使用计算机进行文本分析与处理,进行图像的分析与处理,对音频的分析与处理。对文本、图像和音频的计算是三个主要方向,后续可能还有机器学习或者人工智能,这些是使用计算机技术解决现实客观世界的主要方法和途径。本质上看,作为人工智能的代表方法之一机器学习就是计算机利用输入的样本,调整一个通用数学模型的参数,使得这个模型能正确地回应新的输入 [16]。

在掌握了某一种编程需要的单个程序应用,熟悉了由多个程序组成的软件项目的组织结构和运行流程,接下来就是使用这些知识和技能解决现实世界的问题。对现实世界的问题进行数学建模是主要方法之一,这样才能对问题进行计算。

具有一定的数学思维是进行数学建模的前提。观察客观世界的现象,抓住其主要特征,抽象出概念或者建立模型;进行探索,通过直觉判断或者归纳推理、类比推理以及联想等作出猜测;然后进行深入分析和逻辑推理以及计算,揭示事物的内在规律,从而使纷繁复杂的现象变得井然有序。这其中进行分析、推理和计算的过程,就需要借助计算机进行软件编程。

计算机领域的实际问题数学建模(Mathematical Modeling)需要根据现实问题设计相应的算法(计算过程),求解描述实际问题的数学公式、函数等,进而通过这些数学公式、函数解释、验证实际问题,对当下进行计算,对未来进行分析、预测等 [17]。这类知识、规律的发现越来广泛应用到各种个性化、智能化服务当中。


图 4 数学建模的逻辑表述
Figure  Mathematical Modeling in Logic Representation

基于全样本的大数据集,运用测试分析方法开展的机器学习、人工智能等越来越多的被应用到各种软件编程应用场景。利用机器使用测试分析方法逐渐取代人工的机理分析,成为发现知识和规律的主要途径之一。

问题建模是将现实问题简化,使其变成“可计算”,然后使用编程将可计算的部分以软件功能的形式表现出来。编程是建模实现的一种重要工具和手段,针对问题进行数据建模后的拟合、仿真和计算过程才是软件编程大展身手的地方。在数学建模的实践中,几乎没有哪个模型是不需要用到如MatLab、SPSS、Lingo、C/C++或Python这样的编程工具的。这些将我们用数学语言描述的问题再通过计算机来实现,编制良好的程序确实能极大地帮助我们模型的实现,甚至取得更好的效用。

网络发展的如此迅速,一些IT公司会面临各种实际问题需要进行数学建模,而这些互联网公司往往没有数学专家,只有计算科学与技术专家,这就需要此前从事软件编程工作的人员对实际问题进行数学建模,并使用软件编程来实现它。IT公司面临的问题既有其本身发展的需要产生的,也由全社会发展面临的难题。机器翻译是这样的,人脸识别、人工智能都是这样的。逐渐多的,面向各种问题的“算法”工程师、技术专家的需求量增加,正是这一趋势的发展现象。

能不能对现实世界的实际问题进行数学建模,成为我们称之为第三个分水岭的关键点。 

5   结论与展望

本文简要分析了软件编程技术水平的三个具有标志性的关键点——正则表达式、软件开发框架和数学建模。这些分水岭似的关键点有助于软件开发人员甄选,也对软件开发人员自身水平认识起到一定的参考作用。同时,这些知识点也能够从另外一些方面引导软件编程、开发人员尽快、尽早的掌握这些知识和技能,提升自身知识水平。

对软件编程的技能对计算科学与技术的水平进行分层分级是困难的,我们就此列出的三个具有标志性意义的考察点在某些场合并不适用。然而,在一般意义上来说,能够熟练掌握正则表达式、能够掌握并对已有软件框架进行修正或者开发一种软件框架我们将之视为高级计算技术人员;能够对现实世界需求问题进行数学建模,并将其映射为软件应用,我们称之为技术专家。

计算机及软件行业在不断发展变化中。一些编程语言或者编程工具会随着整体发展或日益完善或日渐凋零,只有那些隐藏在编程技能背后的原理与思想保持不变,并随着技术的进步以另外一种编程语言或表现形式再次出现在软件研发行业。

因此,对软件编程技术水平的考评既不能以某一个厂商的某种产品为基准,也不能以一时的技术平台或编程工具为依托,从技术或技能背后的编程原理、编程思想来设计相应的考评体系更能够全面整体地反映出从业人员的真实水平,也许未来可能有其他等同于正则表达式等这三点的参考标志出现。

[参考文献] (References)

[1]

中国计算机技术职业资格网, “计算机技术与软件专业技术资格(水平)考试简介,” 10 2015. [联机]. Available: http://www.ruankao.org.cn/focusExam/ksjs/detail/news-00005/. [访问日期: 09 2017].

[2]

李二霞, 软件编程高端人才效标群体研究, 西南大学, 2010.

[3]

冯向科,邓莹,彭勇, “高职软件技术专业学生的面向对象分析、设计和编程能力培养的研究,” 科教导刊, 卷 28, pp. 41-42, 2011.

[4]

布鲁克斯(FrederickP.Brooks.Jr.), “没有银弹-软件工程中的根本和次要问题,” 出处 人月神话, 北京, 清华大学出版社, 2002.

[5]

李娜, “浅谈软件工程技术发展,” 软件, pp. 204-205, 03 2014.

[6]

中国计算机学会, “CCF计算机职业资格认证简介,” 02 2014. [联机]. Available: http://cspro.org/lead/info.do?__action=info_view&catalog=notice&id=hrvnsypp-1gg&__forward=true. [访问日期: 09 2017].

[7]

F. Dib, “Regular Expression 101,” 08 2012. [联机]. Available: https://regex101.com/. [访问日期: 09 2017].

[8]

J. E·F·Friedl, 精通正则表达式(Mastering regular expressions), 第三版, 北京: 电子工业出版社, 2007.

[9]

D. Riehle 和 T. Gross, “Role Model Based Framework Design and Integration,” 出处 Proceedings of the 1998 Conference on OOP Systems, Languages and Applications, ACM Press, 1998.

[10]

袁立国, 陈中育, 李方 和 郭婷, “一种软件开发框架的设计优化,” 计算机系统应用, 卷 22, 编号 5, pp. 70-74, 2013.

[11]

O. Vogel, I. Arnold, A. Chughtai 和 T. Kehrer, Software Architecture: A Comprehensive Framework and Guide for Practitioners, Heidelberg, Germany: Springer Science & Business Media, 2011.

[12]

张合 和 刘小红, “面向对象的对象建模技术及其应用研究,” 软件, pp. 66-68+72, 03 2011.

[13]

刘振兴, “GWA2,” UFQI.COM, 11 2011. [联机]. Available: https://ufqi.com/dev/gwa2/?_via=-naturedns. [访问日期: 09 2017].

[14]

金旭亮, “如何学习复杂的软件技术开发框架?,” 07 2017. [联机]. Available: https://weibo.com/ttarticle/p/show?id=2309404135192531986821#_0. [访问日期: 09 2017].

[15]

刘振兴 和 张楠, “自行创建类jQuery的JavaScript库,” 中国计算机学会通讯, 卷 06, 编号 6, 2013.

[16]

应行仁, “什么是机器学习,” 中国计算机学会通讯, pp. 42-45, 04 2017.

[17]

谢金星 和 姜启源, “清华大学公开课:数学模型-现实世界的理性视角,” 网易公开课, 04 2013. [联机]. Available: http://open.163.com/movie/2013/4/9/6/M98EVI91I_M98PE9E96.html. [访问日期: 09 2017].

 

作者简介:刘振兴(1977-),男,硕士研究生,原人民网研究院网络技术研究员,中国计算机学会会员(14229M),主要研究领域包括计算机网络通信协议、互联网后台支撑技术和网络架构与安全等.

(原文登载于 《软件》(Computer Engineering & Software),2017年11月号,有改动)

Posted in -GWA2, 编程技术, 计算机技术 | Tagged , , , , | 1 Comment

gMIS吉密斯导航Navimenu、自动安装等更新

gMIS吉密斯通用管理信息系统在使用中不断被优化和更新,这次主要改进和修正的内容如下:导航菜单,录入修改表单项和自动安装程序等,以下分述备忘。

  1. 导航菜单的Bug及更新
    1. 导航菜单二级/三级目录不显示的Bug
      导航菜单使用层级式CSS和JavaScript实现,在实际使用中,如果某个终端设备其屏幕分辨率设置的很高,其相应的显示字体就会变小,此时用户为了获得较大较清晰的字体显示,会在操作系统层面调整字体显示比例,比如将 Text Size调整为 125%,150%,如此高分辨率叠加扩增字体设置,导致gMIS的二级/三级菜单无法展出。

      解决这一问题的思路是,回退操作系统层面的Text Size,然后二级菜单就会重新显示展开,如果获得较大较清晰的显示,可以降低屏幕分辨率分辨率的方式。

      为兼容这一情况,我们升级了gMIS的导航,在三级目录无法展开的情况下,通过点击父级目录能够在 Index 层面以宫格的形式展开该目录的子目录模块,再进一步地点击子目录,可以展开孙目录,如此递进可以抵达任意层级子目录。

      在通过Index导航时,我们还修正了以Extra命名的菜单,也即某个菜单指向的链接,其Module Name为空,但又不是Directory Name,此时需要将访问目标调整为指向动态参数(Dynamic Parameter)所设置但Extra模块。

    2. 菜单路径的最贴合选择
      由于gMIS的菜单设计支持动态参数(Dynamic Parameters)的特色功能,所以同一个模块,使用不同的动态参数进入,可以呈现不同的内容。依据此功能,我们可以在进入某功能模块时,显示A/B项,这样可以将一个功能模块复用为多个。于是就产生了可以在菜单中的多个入口指向同一个模块(带有不同参数)。

      问题发生在,如果多个入口进入同一个模块,在Moudle Path中显示哪一个的问题。

      预期的效果应该是展示最贴合当前路径的那个菜单设置,此时就需要确切知道菜单的层级位置 Levelcode 参数。于是我们进一步地修改Module Path模块,改进单一依靠模块名称生成Module Path的做法,优先使用菜单的Level Code来生成Module Path。

      这样就生成最贴合当前菜单的路径。

    3. 未来规划
      层级目录导航是“传统”的,属于 Yahoo 时代的产物,未来的导航应该是 Google 式的智能导航。
      未来拟开发一个 gMIS 域内全文搜索引擎,这样用户就无需使用或者记录层级目录。
      再未来,可能会有交互方式的改进及人工智能的引入,比如一个能够交互使用自然语言进行交互的管理信息管理系统.

  2. 录入、修改表单项
    1. Add/Modify UI Middle/Bottom -> Top
      在新增。修改UI界面,调整和优化了显示方式。
      主要修改是,当 textarea 和 text普通录入框等并列显示时,text但布局没有作处理。问题发生在textarea但竖向设置为 top,而Text默认设置为bottom/middle,于是就产生了不协调。
      此次我们修改和调整了Text但设置,默认都修改为在竖向使用Top方式,取得一致都显示效果,预览更方便直接。

    2. Caption Font + Bold
       同样是在Add/Modify都界面上,我们还修改了数据项的显示,使用加粗的方式使之能够更进一步地的一目了然。
      这一修改还同步到View模块。

  3.  自动安装程序的改进
    根据网友反馈在新用户使用gMIS自动安装程序进行安装时没有报错信息的情况,默认启用了 is_debug;

    修改了cache设置,改为默认不启用服务器端 Cache Service;

    修改了新版 MySQL 连接时 localhost 报错信息,改为默认使用 127.0.0.1 连接本地 MySQL 数据库;

    修改了下载(wget)、解压(unzip)和验证安装程序的一些内置命令参数。

gmis-logo-201606

-gMIS 是一种基于 -GWA2 的通用管理信息系统(Management Information System)软件,具有可配置的输入和输出接口。
可以在其上构建各种管理应用软件系统,如
内容管理系统(CMS),客户资源管理(CRM), 企业资源计划管理(ERP),
办公自动化系统(OA)等, 以及各种行业应用管理系统软件,如
人力资源管理系统(HR),学生管理,档案管理,旅游管理,图书管理,
商品管理及业务运营支撑系统等等。
实现零代码开发、搭建各种管理信息系统(MIS).

Lower Costs, Better Productivity.
降低成本, 提高效率.

Posted in -gMIS, 计算机技术 | Tagged , , , , | Leave a comment

2017,开不动的印钞机–中国经济发展态势分析

转按:2017年5月份,经济学者许小年发表“许小年:转折点上的中国经济/中等收入陷阱”,文中说资金/资本驱动的模式已经无法凑效,取而代之的将是创新驱动等。所言前半部分资金/资本无法驱动经济的观点与本文有所接近,附贴如下。

注:本文的数据已更新到2017年8月份。

 我们从这样一组数据开始本文:2013年初,我大中国央行“对其它存款性公司债权”(央行借给商业银行的债)规模为1.45万亿。当年6月,钱荒发作,各商业银行的现金流濒临断裂,全社会陷入恐慌。央行紧急启动“SLF”、“MLF”等方式,直接借钱给商业银行,补充商业银行的现金流。至2014年底,央行对其它存款性公司债权的规模为2.50万亿,2015年底为2.66万亿。这两年央行在借钱给商业银行的问题上,算得上极尽克制,两年时间加起来也就是借了1.21万亿出去。然而到2016年底,该数据暴增到8.47万亿,较2015年底暴增了5.81万亿,增幅高达218%。

到2017年,这种令人震惊的增幅突然就停止了。6月底的数据为8.59万亿,较2016年底仅仅微弱上升了1200亿,增幅只剩下可怜的1.4%。看起来,商业银行已经不再需要找央行借钱了似的。 

我们必须知道的是,央行借钱给商业银行,乃是2013年以后,我大中国最重要的金融现象,没有之一。2014和2015年央行借钱给商业银行的规模偏小的结果,是全中国的房地产市场都陷入萎缩,于是我大中国政府被迫在2015年底启动“地产去库存”运动,并敞开央行的大门,让各商业银行想借多少就借多少。这就是2016年央行对各商业银行的债权规模剧增的原因。然而,2017年,这一切都戛然而止,商业银行竟然突然停止向央行借钱了。在这种现象的背后,一定有着非常深刻的经济学上的原因。而将这个原因挖掘出来,一定能让我们更加清晰的理解未来之路。这,就是本文的核心目的。

——是以为序

 

【一】以债为锚

一直到1971年,人类才正式放弃以贵金属作为纸币发行之锚的做法,从这个时候开始,人类进行了以债为锚发行纸币的新时代。要理解这一点,我们必须回头,重新认识货币的历史。

首先我们要重新认识一位伟大的历史人物:伊萨克·牛顿,人类历史上神一样的科学家,鲜为人知的是,牛顿同时也是一位神一样的经济学家。他担任英国铸币厂长长达30年,并建立起一套完善的货币发行体系。牛顿之后,人类才真正理解了货币,解决了国际贸易中不同种类的货币如何相互兑换的问题,英国也因此获得了巨大的国际竞争优势,成长为真正的“日不落帝国”。...

1696年,时年53岁的牛顿接受其当时的英国财政大臣,也是他学生的推荐,担任英国铸币厂的皇家监理,3年后正式接任厂长,此后牛顿长期担任铸币厂长一职,直至1727年去世。在牛顿接任铸币厂长的时候,大航海时代已经到了尾声,海洋的神秘面纱已经被揭开,通往各大陆的航道都已成熟。大英帝国内部已经正式建立起君主立宪制,外部则刚刚结束与法国之间的大同盟战争,举国上下正是朝气蓬发,试图向全世界扩张,拓展殖民地。而这个时候,制约英国脚步的最大问题,就是货币。

在那个时代,人类依然处于贵金属货币时代,以贵金属打造的金银币是最为流行的货币。英国当时面临的问题,其实是当时欧洲各主要国家普遍遇到的问题:金银币的铸造标准问题。最基本的问题有两个:第一,一个标准贵金属币上标注的数值,是货币单位还是重量单位?比如标注为10便士,还是10克?第二,如果标注为货币单位,那么该贵金属币是否应该足值,也就是标注为10便士的金币,其中必须含有相当于10便士的金子?当然了,这两个问题其实是一个问题:贵金属币是否必须足值?

牛顿以其科学界崇高的威望压制住了争议,坚持以货币单位为贵金属币的标注单位,这算是解决了第一个问题。到1717年,在牛顿的建议下,英国议会通过决议,确定了黄金与贵金属币的兑换比例:每盎司(纯度0.9)黄金=面值为3英镑17先令10便士的贵金属币,英国政府官方承诺兑换。这是人类历史上第一次,由政府出面,对货币币值与黄金重量之间的兑换关系作出正式承诺。事实上,这就意味着自此之后,英国的贵金属币可以不足值,一个面值10便士的贵金属币中,可以只含有价值7便士的金子,然而英国政府的官方兑换承诺,给予了这枚不足值的金币以足够的信用,让它可以作为完完整整的10便士使用。大家对英国政府有信心,当然就对英国政府发行的金币有信心。反过来,所有使用英国金币的人,无论他在世界的哪个角落,为了确保自己手上的金币的购买力,他都会主动维护英国政府的利益。就这样,英国逐步获得了全世界的支持,四十年后,原本在欧洲一直处于边缘地位的英国终于崛起,彻底击败了西班牙和法国,成为独一无二的海上霸主。此后日不落英国在各殖民地效仿金币的发行机制,发行纸币,承诺可以凭借纸币兑换等面值的金币。这些纸币在殖民地流通,促进了国际贸易的蓬勃开展。

到了这个时候,英国的货币发行体系分成了两个圈层。在英国内部,政府以足额兑换的承诺,依靠7成的黄金储备就能发行10成的金币;在外部殖民地,则以承诺兑换金币为基础大量发行纸币。英国政府的信用,成为了货币发行的根基。将政府信用与货币发行相捆绑,这恰恰是牛顿爵士在经济学领域做出的突破性贡献。在我看来,这种贡献对人类社会的意义,不比发现万有引力定律来得小。

有了英国政府进行信用背书,英国本土的金币加上殖民地的纸币英镑,乃是人类历史上最早的国际货币,它的使用一直持续到1930年代的全球经济大萧条时期,英国政府财政濒临崩溃,已经无力再承担国际货币的责任,对于世界各地拿着纸币英镑过来兑换金子的要求,英国政府已经无法承受,于是只能在1931年取消兑换承诺。全世界突然就丧失了能够支持国际贸易并能为所有人接受的国际货币,全球经济雪上加霜,并终于带来了第二次世界大战。

二战之后,美国成长为新的全球霸主,对于当时缺乏国际货币因此难以开展国际贸易的问题,除了美国,其它国家根本就解决不了。好在这个时候美国也出了一位真正的经济学大神,哈里·怀特,近代史上充满了争议的传奇人物,此人乃是当代国际经济秩序的制定者,布雷顿森林体系之父,在人类经济制度史上,唯一可以与牛顿相媲美的神。

1944年,在美国新罕布什尔州布雷顿森林召开联合国国际金融会议,讨论如何解决缺乏国际货币的问题以及如何建立新的国际秩序的问题,时任美国财政部助理部长的哈里怀特说服了其他与会代表,以美元作为国际货币,组建国际货币基金组织和国际复兴开发银行(即世界银行)。同时,在怀特的推动下,美国政府向全世界承诺,1盎司黄金=35美元,美国政府以国家信用担保兑换..

(布雷顿森林会议上的美国代表团,后排左一为怀特)

1946年,国际货币基金组织和国际复兴开发银行在华盛顿正式开始营业,这在事实上宣告了“布雷顿森林体系”的正式确立。它们的章程规定,每个国家的货币币值都必须使用黄金或与黄金等价的美元来表示,并且未经批准不得修改。这就在事实上确立了美元=黄金的信用关系。1947年,在布雷顿森林体系的基础上,美欧各主要国家达成《关税总协定》,确定成员国之间放弃贸易壁垒,以美元为媒介进行交易。1948年,美国启动“马歇尔计划”,直接向欧洲各国投资,复建其被打成废墟的工业体系,振兴欧洲各国经济。如此三管齐下的结果,就是美元自此成长为国际货币,具有了黄金般的信用,为世人所普遍接受。这一系列的举措,统统都是在落实哈里怀特的经济计划。 

然而哈里怀特本人在1946年国际货币基金组织正式开始营业后,就陷入了一堆莫名其妙的苏联间谍指控。他很快就退出政坛,为了应付责难心力交瘁,在1948年就黯然辞世。人类自此失去了最后的经济学大神,对于美元作为国际货币而可能引发的各种问题,再也没有人能进行系统的思考和总结。

在这里顺便说一句,当时的中华民国曾经是国际货币基金组织、世界银行和关税总协定的创始国,可惜的是,新中国建国之后向苏联靠拢,并立刻就退出了这三大组织。此后,到1980年中国才重新加入国际货币基金组织和世界银行,到2001年才重新加入关税总协定。为了恢复这三个组织的席位,加入到新的经济秩序之中,新中国经受了重重考验和磨难,不过这都是后话。

布雷顿森林体系的本质,是以美国的国家信用为美元的购买力进行担保,美国官方承诺美元可以按固定利率兑换黄金,这种做法与当年英国的牛顿爵士如出一辙。甚至,只要美国的国家信用还在,有没有黄金可以兑换,都不是问题。英国在1931年取消英镑兑换黄金的承诺,英镑立刻就丧失国际货币资格的原因,在于当时的英国内忧外患,各殖民地纷纷在闹独立,英国的经济本身遭受重创,国家信用岌岌可危,英国无法再为其货币的购买力进行信用背书。然而美国不一样。1971年美国尼克松总统迫于兑换压力,同样取消了美元兑换黄金的官方承诺,但是当时的美国依然是世界第一大国,具有不可挑战的经济和军事领导地位,其国家信用坚不可摧,因此美元作为世界货币的地位完全没有受到影响,建立在布雷顿森林体系之下的国际货币组织、世界银行和关贸总协定依然在平稳运行。经济学界鬼哭狼嚎的所谓布雷顿森林体系在1971年后就陷入崩溃的说法,基本上就是瞎扯淡。从这一点上看,全世界的主流经济学家,在大神怀特去世之后,就只剩下一帮白痴。 

 

我们今天回头来看,无论是大英帝国的“金本位”制度,还是布雷顿森林体系早期的“美元锚定黄金”制度,它们真正能够生效的机制,都是国家信用。货币,就相当于是政府发行的信用债!朝气勃发勇于进取的帝国精神,才是英镑真正的信用之源,而不是英国皇家国库的那点子库存黄金。一旦1930 年代英国丧失进取心,变成整天追忆往昔荣耀的破落户,英镑立刻就随之丧失了国际货币的地位。英国本身让人丧失了信心,英镑才随之被世人抛弃。而美国之所以能在1971年取消美元锚定黄金的制度之后,依然维持着美元的国际货币地位,唯一的原因,就在于美国依然强大,依然富有强烈的进取精神。它依然是全世界尖端科技的带领者,流行文化的传播者,它的士兵训练有素身经百战,在最短的时间内能出现在世界的每一个角落。在这样的情况下,黄金这种不知所谓并且几乎没有工业价值的玩意儿,终于退出了人类的货币价值体系。直接将纸币的币值锚定在国家信用之上,国家信用的强弱,直接决定纸币的购买力大小,这才是人类的正途,也是纸币的终极归宿。

在确立了以美国的国家信用作为美元之锚后,美元成为了真正的世界货币,并最终成为全世界的发展基石,全球经济因此得到了持续发展,人类进入了经济发展的黄金岁月。1950年全球GDP规模只有1万亿美元,到1970年超过了3万亿。1950年全球跨国商品贸易规模只有600亿美元,到1970年已经超过5000亿美元。1971年美元与黄金脱钩,对世界经济的发展毫无阻碍。到1980年,全球GDP总规模就超过11万亿美元,跨国商品贸易总额达到3.6万亿美元。在这种背景下,1981年上任的美国总统里根顺理成章的走出了下一步:以债为锚。里根政府大规模发行国债,并由美联储直接认购,政府手里有了钱,就可以进行各种直接投资和采购。这当然就是以发债的形式,将美国的国家信用直接变现为美元了。1981年里根刚刚上任时美国的国债规模是9979亿美元,到1989年里根离任,美国的国债规模上升到了28574亿美元,增加了近两倍。财大气粗的美国政府因此可以大规模的加强军备,搞星球大战计划,拖着苏联进行军备竞赛,将苏联政府拖得苦不堪言。同时,刚刚启动改革开放的中国脱离社会主义阵营,投向美国,积极争取美国投资。苏联内外交困,到1991年就黯然解体。美国一家独大的世界格局就此形成。全世界都被捆绑在了“美元”的战车之上,捆绑在了美国的国家信用,也就是美国国债之上。 

然而,接下来我们必须进一步追问的是:以国家信用为锚,以信用债的形式发行货币的制度,始于1717年牛顿爵士的建议,并先后催生了大英日不落帝国和美利坚共和国这两个超级大国。以债为锚的货币信用设定,乃是人类社会至今为止,最基础的金融设定。我们今天所有的财富,所有的产业经济,所有的科技文化成果,都建立在这个基础设定之上。然而,这个设定是无限的吗?它可以永恒的持续下去吗?到今时今日,人类跨入2017年,这种以债为锚的设定,已经持续了整整300年,它到达终点了吗?如果这种基础设定轰然崩塌,整个人类社会,将要遭遇什么样的噩梦?

 

【二】 卅年风雨

一般而言,各国央行主要是通过三种形式发行基础货币:第一,向商业银行提供借款,第二,以人民币兑换各经济主体挣回来的外汇,第三,向政府或各国字号单位提供借款。这三种方式发行的基础货币之和,再加上其它一点零零碎碎的资产,就是央行的总资产。从这个意义上来说,央行总资产,与基础货币发行量,是基本等同的。对美国这样的国际货币发行国来说,正如我们在第一章所讲述的,第三种方式是最主要的货币发行方式,比如2011年,美联储29300亿美元的总资产中,持有美国政府各类债券26224亿,占总资产的比值达到89.5%。到2017年7月,美联储总资产45120亿,其中持有美国政府各类债券42423亿,占比94.0%。这其实就是美国以政府债形式发行基础货币,美国政府的信用,就等于美元的信用,两者之间是相互绑定的。

而我大中国这样的国家,则主要是通过前两种方式发行基础货币,第三种方式事实上使用得很少。以2016年为例,我大中国央行总资产343712亿,其中外汇占款(也就是历年兑换外汇而印出来的人民币总额)219425亿,占比63.8%;对商业银行借款84739亿,占比24.7%。两者合计达到了88.5%。至于向中央政府的借款,总额只有15274亿,占央行总资产的比值只有4.4%。我大中国政府事实上无法提供足够的信用,用于货币发行。基于这样的判断,我们来认真的梳理一下,从1986年至今,央行总资产中的外汇占款以及对商业银行债权的数据演变,看看在这三十年里,我大中国在货币发行领域到底经历了什么的惊心动魄的故事。..

1986年,改革开放初期,我大中国的央行总资产3345亿,其中外汇占款38亿,占比仅1.1%;而对商业银行的借款规模高达2682亿,占比高达80.2%。可见,在这个时候,我大中国的印钞方式,主要就是央行向各大商业银行提供借款。

但是,请注意这个但是:我大中国的商业银行与欧美国家不同。我大中国的商业银行基本上都是国有银行,央行向商业银行的借款,基本上都提供给了中农工建交这五大行。事实上,这五大行的信用,都是政府信用、国家信用,也就是说,1986年我大中国央行向商业银行提供的2682亿的名义上的借款背后,是由政府进行最终的信用背书。也就是说,整个1980年代,我大中国都是依靠自己的政府信用在发行货币。按某些经济学家津津乐道的说法,这就是所谓的主权货币,不依赖美元加持就能独立获得信用的货币。然而事实是:这个所谓的主权货币是虚假的,根本经不起任何考验。

1986年美元兑人民币的中国官方汇率是3.45,但是黑市汇率一直都在8到10之间浮动。我大中国政府试图以低廉的官方汇率吸纳外资,自己来占便宜,算盘确实打得很好。但是外国人都不傻,除了一些爱国港资企业,以及少数几家基于政治目的欧美日企业,比如可口可乐和丰田之外,基本上就没有外资企业上这个当,根本就不愿意在中国大规模投资,也不愿意敞开了跟中国做生意。1980年代的改革开放之路,其实走得极为艰难。我大中国要坚持主权货币的道路,守住3.45的汇率,代价就是经济根本发展不起来。在外贸数据上,整个1980年代,有8年都是逆差状态,单1986年的贸易逆差就有120亿美元。这种持续的外贸逆差情况,当然无法守住外汇储备,由爱国港商投资带来的外汇储备很快就见了底。1983年的外汇储备数据为89亿美元,算是80年代的峰值,到1986年已经下降到21亿美元的谷底,1989年也就是勉强恢复到56亿美元。就这么磕磕碰碰的发展到1990年代初,不光是美元有黑市,在价格双轨制之下,全国范围内,几乎所有商品都有黑市, 这已经是经济失控的征象了。人民币信用根本得不到老百姓的信任,官方无法再为任何商品制定价格,老百姓也习惯了不使用官方价格去购买商品。这种局面如果持续下去的话,那真是万劫不复。

想要平抑物价,恢复人民币的购买力,唯一的办法,就是人民币持续的贬值,以吸引外商投资,促进商品出口,增加外汇储备,以美元的信用,来为自身信用已经崩塌的人民币进行加持。指望我大中国政府打着商业银行借款的旗号为货币发行提供终极信用,这已经是不现实的事。在数据上,1990年的官方汇率是3.78,到1993贬到5.76,然而这种贬值幅度跟黑市上的汇率相比依然不够看,到1993年,中国经济终于走到了崩塌边缘,当年度消费物价涨幅高达15%,1994年物价涨幅24%,1995年依然高达17%。经历过这三年物价疯涨的国人至今回忆起这三年来都心有余悸。在这样的生死关头下,再羞答答的试图守住汇率没有任何意义。1994年人民币汇率因此跳贬到了8.62

在这种持续并且剧烈的货币贬值的刺激之下,我大中国终于迎来了真正的大规模的外商投资,外贸终于恢复顺差,外汇储备量开始上升。1990年我大中国实际利用外资额为103亿美元,到97年,利用外资达到90年代的峰值,644亿美元。在外贸收据方面,1990年代只有1年是逆差状态,其它9年都是顺差,1990年的外贸顺差只有87亿美元,到了1998年,顺差规模达到90年代峰值,435亿美元。在外资持续加大流入的背景下,我大中国的外汇储备迅速提升,1990年的外汇储备规模仅111亿美元,到1999年已经上升到1547亿美元,上涨了足足13倍!

汹涌而至的外资拯救了中国经济。1990年外汇占款占央行总资产的比值仅8.2%,到1999年已经上升到了39.8%。而对商业银行借款占央行总资产的比值,则从1990年的70.1%下降到1999年的43.5%。这意味着到90年代末期的时候,人民币信用,已经是由美元和中国的国家信用共同支撑的了,两边基本上平分秋色。 

然而这个时候中国经济遭遇到一次真正的债务危机。在放开人民币汇率,真正打开国门迎进外资,并随之真正扩大外贸规模之后,国人惊讶的发现,原来除了国企生产的傻大黑粗的产品之外,世界上竟然还有那么多精美耐用的商品,于是纷纷弃国货不用。国企长期积累的技术落后效率低下的问题在90年代中后期逐步爆发了出来,并因此丢失了市场。麻烦在于,国企身上统统背负着沉重的银行债务,现在国企的产品卖不出去,现金流纷纷断裂,当然就是还不起债。这算是中国历史上第一次真正的债务危机。中国政府迫于无奈,只能通过央行不停的直接向各国有企业输血,也就是直接凭空印钱。体现在数据上,就是从1998年到2002年,外汇占款占央行总资产的比值在40%左右浮动,而对商业银行的借款,倒是从40%一直下降到了不足20%。如此下降的结果,外汇占款与对商业银行借款合计占比,在2002年竟然跌到了62.8%!这意味着有近4成的钱,乃是央行印出来凭空借给了各国企去吊命。我这里给几个这样性质的央行资产分项数据,首先是“央行对其它金融机构债权”项数据。这笔钱事实上就是央行借给各种信托机构,让它们再拿给国企花的。1999年央行对其它金融机构的债权规模为3833亿,到2002年上升到7240亿。再比如,2002年央行的资产负债表里突然冒出来一个“其它资产”,规模不小,年底的数据为5266亿。这笔钱当然也是拿去给国企救命的。5266+7240=12506,占当年度央行总资产的比值达到24.5%。总而言之,2002年是中国经济在改革开放之后经济最危险的年份,一个不小心,债务链条就彻底崩断了。

所幸天佑中华。2001年底我大中国加入世贸,算是彻底打开国门,并完全放弃了主权货币地位。我们也不再坚持国企的领导地位,除了金融、矿产、通讯和运输领域外,其它竞争性领域的国企基本上都被卖掉了。国企员工统统下岗,让他们去外企和民企寻找生路。甚至我们也不再坚持商业银行必须100%国有的政策,五大行纷纷选择在国外上市,我大中国政府逐步放弃了与商业银行直接捆绑的固有理念。在这种背景下,外资更加汹涌的进入中国,投资到基础制造业领域,中国在新世纪的前十年就成长为真正的世界工厂,生产了全世界超过20%的基础消费品。外资的涌入解救了中国,资金链濒临崩塌的央行获得了庞大的外汇输入,就此变得财大气粗。在数据上,外汇占款占央行总资产的比值迅速提升,到2013年达到峰值的83.3%。而央行对商业银行的借款则迅速下降,2009年下降到谷底的3.1%,2013年也只不过是4.1%而已。至于外汇储备数据,2013年为38213亿美元。这个时候,人民币获得了美元的完全信用加持,牛气冲天,汇率不断升值,到2013年达到6.19。中国经济看起来形势一片大好。这个时候,如果我们再提起90年代初期的通货膨胀和2000年代初期的债务危机,简直没人会相信。

中国人到这个时候,也才过了不到十年的好日子,就把之前遭遇到的磨难忘了个一干二净。全国人民雄心勃勃,要在10年之内实现人民币的国际化,把美元打倒在地再踏上一万只脚。在这个时候,我们完全忘记了,这个国家在经济上所取得的所有成就,都建立在逐步放弃我们的主权货币体系之上,建立在彻底并入美元体系之上,建立在美国的国家信用之上!直接说吧:美元,已经成为人民币的信用根基。一旦整个趋势逆转,中国经济被排挤出美元体系,那么,我们现在的整个货币体系,都将要遭遇直接的冲击。三十年风风雨雨,历尽艰辛,中华民族的苦难岁月,算是熬到头了吗?现在时间到了2013年,在前方等到我们的,到底是什么呢?

 

【三】 极限杠杆

 在讲述2013年后的故事之前,我们先来学习一个简单的概念:货币乘数。各经济主体将外汇兑换为人民币之后,总是会存在商业银行。商业银行本身也能得到央行的借款。这两笔钱,就构成了商业银行的原始存款,也就是基础货币。商业银行会将这些钱拿出去放贷。每10块钱的存款,商业银行会留下至少2块5作为准备金,贷出去7块5毛钱。获得贷款的经营者,事实上又会将这笔贷款存回银行,于是商业银行又拿着这7块5中的5块钱出去放贷。如此反复循环的结果,就是存款规模被放大了。以这个被放大之后的资金总规模,除以央行总资产(即基础货币量),得到的结果,就是货币乘数。

在这里,我们很有必要梳理一下,从1990年代至今,我大中国的货币乘数演变史。..

1990年到2001年,我大中国经历了一次货币乘数逐渐提升的过程,到2001年达到当时的峰值3.72。这个时候我们必须重新回忆起第二章的内容,在当时的中国,发生了第一次债务危机。银行借给国有企业太多的贷款,根本收不回来,债务炸弹接近爆灭。人民币差点就失去信用支撑,掉入万劫不复的深渊。幸亏到了年底我国加入了世贸组织,汹涌而至的外资解救了中国经济,给了濒临崩塌的人民币以信用加持,中国经济开始好转。

2001年之后伴随着经济逐步复苏,我国的货币乘数逐渐下降,到2008年下降到了最低值2.29。这个时刻我大中国其实并没有什么太大的金融负担,日子也好过得很,算是中国经济发展中最黄金的岁月。然而一场席卷全球的金融海啸改变了一切。当时美国的金融机构大肆借钱给穷人买房,甚至连首付的概念都没有,全部购房款都是借的。到2008年的时候,穷人终于普遍还不起钱了,于是债务炸弹爆发,整条借贷链上的金融机构一个接一个的倒闭。美国整个金融系统都在回收资金,以确保生存。美联储推出了大规模的QE计划,也就是大规模印钱,向金融系统补充流动性,但依然不够应付灾难。在这个时刻,我大中国面临着终极拷问:如果美元就此大规模回流怎么办?人民币岂不是就丧失信用支撑了吗?我国对此作出的回答是:自己印。四万亿借款投资计划横空出世,央行开始提高向商业银行借款的规模。体现在数据上,2009年央行向商业银行借款占央行总资产的比值达到最低值3.1%之后,就开始进入上升通道。与此同时,从2009年开始,我国的货币乘数开始重新上升,到2013年上升到3.49,这个数据事实与2001年第一次债务危机时3.72的货币乘数已经算是非常接近了。然而此后我国并没有收敛,货币乘数持续上升,2015年达到4.38,2016年已经达到了4.51。进入2017年之后,货币乘数就进入了纠结状态。3月份微弱上升到4.74,此后开始反复的纠结下行,到8月份又勉强恢复到4.74。

在进一步阐述我国货币乘数演变背后所隐藏的经济规律之前,我先给出一组参考数据。美国2011年的M2为9.6万亿美元,对比其当年度2.93万亿的美联储总资产,货币乘数为3.29。到2017年7月,美国M2总量为13.7万亿美元,对比4.5万亿的美联储总资产,货币乘数3.04。整体而言,伴随着近年来美国进入加息通道,收缩资金,美元开始回流,美国的货币乘数正在缓慢而坚定的下降。美国不再愿意向全世界提供货币信用,这事已经算是板上钉钉,不会再有什么变数。不管怎么样,像美国这样可以向全世界发行纸币,并以其货币信用支撑起全球外贸的国家,货币乘数也不过是长年保持在3左右,而我大中国,自2013年之后,货币乘数就坚定的超过了3,目前在4.6左右浮动。我国这种超高的货币乘数,这种已经达到极限的货币杠杆,就是我们现在面临的一切问题的根源。

现在我们再回头去看2008年之后我大中国央行的资产演变。2009年央行对商业银行的借款占央行总资产的比值下降到3.1%的最低值,此后,伴随着我国开始启动大借款模式,这一比值恢复上升,到2012年上升到5.7%。这个时候我国开始感觉到紧张。央行向商业银行提供了太多的资金,供商业银行借给地方政府,让他们去兴建各种毫无现金回报的基础设施,按照当时普遍的说法,地方债在那一年就超过了20万亿人民币。好吧,关于地方债总额,事实上我国从来都没有真正全面的统计。总之当时这个20万亿地方债的说法一出来,我大中国从上到下开始紧张,开始了对四万亿借债投资计划的全面反思。于是从2013年初开始,我国开始紧缩银根,央行开始减少向商业银行的借款,并通过一系列窗口指导,尝试打压银行的贷款冲动,并多次以行政命令的方式压制地方债务扩张的冲动。到2013年底,央行对商业银行的借款占总资产的比值下降到了4.1%。然而,这一次根本谈不上严厉的金融调整,却引发了非常严重的后果:2013年中,钱荒爆发了。

..

 要知道当时银行主要的借款对象,其实就是政府的各种平台公司,主要的资金去向,都是一些市政道路啊园林广场啊之类的基建工程,根本无法产生现金回报。商业银行要维持现金流,就必须依赖央行不停的借钱输血。现在央行突然停止输血,于是“DUANG”的一声,商业银行的现金流断裂了。银行之间的资金拆借利率在一夜之间暴涨,直奔50%而去,这可是名副其实的高利贷,却依然借不到钱。在当时地方政府搞基建,当然首先是从城商行手里借钱,所以当时城商行的资金情况最为紧张。规模小点的城商行在当时已经沦落到完全还不起拆借资金的地步,只能眼睁睁的违约,恨不得直接变成老赖。到这个时候,我大中国上上下下,才赫然发现,原来我们已经深深的踏入了债务陷阱,根本就跳不出来了。

2013年的整个六月份,中国金融市场一片风声鹤唳,股市暴跌,债市暴跌,所有人都在追问,钱到底到哪里去了?很简单,被各类政府债和国企债借去了,沉淀到了不能创造现金回报的市政工程、基础建设里去了。资金紧张的局面一直持续到6月底,央行终于撑不住了,放弃了紧缩银根的做法,继续向商业银行提供大规模借款,以吊住银行的命。在数据上,2012年底央行对商业银行的借款规模为16701亿人民币,到2013年5月,钱荒发作前夕,下降到11844亿,减少了4857亿,降幅达到29%。这显示了当时央行停止防水和降杠杆的决心。然而到6月底,面对持续了整个一个月的钱荒,央行迫于无奈,终于重新启动杠杆。6月底央行对商业银行的借款规模就恢复到了16182亿。此后央行依然不死心,依然试图关上供钱的水龙头。到12月份的时候,央行又尝试了一把,当月央行对商业银行的借款规模下降到13148亿,结果立竿见影:钱荒第二次发作,资金拆借利率当场暴涨到6月份的水平,全国人民都被这连续两次钱荒吓尿了裤子。央行自此再也不敢尝试紧缩政策,到2014年1月,央行对商业银行借款规模暴增到21281亿,较2013年12月份的借款规模增加了8133亿,增幅高达62%从这一刻开始,中国的商业银行就再也离不开央行的持续放水吊命,就像深度毒瘾患者一样。只要央行放水的速度稍微减缓一点,金融市场立刻就会爆出一堆银行拆借违约案例。这种事一开始还是新闻,连续三年下来,到今时今日,对拆借市场上的违约,所有人都已经习以为常,视之为经济新常态的有机组成部分。

2014年,央行对商业银行借款占央行总资产的比值已经上升到7.4%,到2015年继续上升到8.4%。就商业银行这种一停止供水就会随时暴毙的状态,当然是非常危险的,简直令人无法直视。我大中国当然不会坐以待毙。要把银行从债务陷阱里解脱出来,就必须让企业找到新的融资渠道。传统的银行贷款路径,乃至于债券市场都不是好办法,冷眼看过去,最合适的还是股市。如果把股市给拉起来,一口气让它涨个几千点,以后企业们都能通过股票发行融资,甚至说不定还能靠卖股票还清银行的债务。于是从2014年底开始,一场股市的国家牛市被强行吹了起来。银行不计成本的借钱给券商,让券商拿去借给股民,让他们融资炒股。无数资金跟风而至,拼命的在股市加杠杆。事后我们根本无从统计在这个疯狂的国家牛市过程中,到底吞噬了多少资金。上证指数从2000点开始,每个月能涨个一千点。到了6月12日,上证指数涨到历史最高点5178点的时候,整个国家都已陷入疯狂,根本没人相信短短一个星期之后,股市就会坍塌。到6月18日,噩梦开始,千股跌停盛大开演。从那一天开始,几乎每天都是千股跌停,一直持续到8月底,整整跌足两个半月,上证指数跌到3000点左右,才算是跌到了底。从此之后,上证指数就在3000点附近徘徊,一直到今时今日。在股灾期间,我大中国尝试了无数种救市的手段,根本无济于事。近两万亿的救市资金砸进市场,直接就被汹涌的浪潮席卷而去,连水花都听不到。所谓人定胜天的豪言壮语,在经济规律面前,被证明只不过是一个笑话。

股灾之后,中国整体陷入债务陷阱的现状已经无从掩饰。所谓君子不立危墙之下,我们当然不能指望外资跟我们共患难,于是外资开始撤离,汇率失守。2014年外汇占款27.07万亿就是历史峰值,到2015年底下降到了24.85万亿。这当然是由于外资将手里的人民币兑换为美元,然后汇出中国。我大央行面对股灾时措手无策,现在面前外资撤离,同样毫无办法。2015年,由于外汇占款的减少,我大央行的总资产减少到31.78万亿,相对于2014年的33.82万亿,缩减了6%,这就是一次被动缩表了。通过本文的阅读,大家已经知道了,央行总资产事实上就是基础货币,基础货币竟然缩减了6%,这一定会传导到整个经济领域,让所有人都感觉到资金紧张。好吧,我大中国本来就由于债务陷阱的事,银行资金都被绑定在各种毫无现金回报的政府基建项目上,想要回款不知道要等到哪年哪月,现在雪上加霜,股灾之后,外资撤离令资金紧张的情况加剧,甚至都引发了央行缩表的后果,这种情况如果持续下去,我大中国估计要重回2001年了。这种后果想一想,都令人不寒而栗。

到2015年底,我大中国终于决定,要赌一把国运了。我们终于拿出了大杀器:房地产。原本整个2014年和2015年,伴随着银行资金紧张,停止向房地产市场输血,无论是地产商的开发贷还是客户的按揭贷,想申请下来都不容易,以致中国整个房地产市场陷入了普遍萎缩,政府拿出来一块地,有事没事就陷入流拍的窘迫境地,与2016年之后地王频出的现象,就好像位于不同的次元似得。体现在数据上,2013年全国土地出让金总收入4.13万亿,到2014年下降到4.04万亿,到2015年继续下降到3.25万亿。这算是债务危机的连锁反应,冲击房地产市场的同时,也会造成地方政府收入的锐减,以致于地方政府无法偿还地方债务。这要是继续发作下去,基本上就是恶性循环,我大中国就没有反抗的余地了。于是到2015年底,反正已经无法可想,再拖下去,基本上就一无所有,连赌桌都要被掀翻了。现在趁着赌局还在,干脆把房地产泡沫再吹起来。在泡沫的掩盖之下,所谓的债务陷阱,看起来也会五彩斑斓,就好像根本不存在一样了。

2015年底,央行对商业银行的借款总额2.66万亿。此后,为了让商业银行有足够的资金投入到房地产领域,央行彻底打开了人民币的水龙头。到2016年底,央行对商业银行的借款规模暴涨到8.47万亿,增幅高达318%。面对这种增幅数据,这种豪赌国运的雄心,我直接就被震惊到目瞪口呆,已经无法给出一个形容词了。

获得了充足的资金支持后,商业银行在房地产领域大展拳脚。开发商可以轻易获得极便宜的贷款,覆盖从买地到建楼的全链条资金需求。炒楼客户也可以随意申请到各种美好的金融产品,满足从首付到按揭的全部需要。2016年真是一个美好的年份,短短一年时间,就足以改变国人的信仰,让他们忘记了2014和2015年房地产市场的普遍不景气,让他们忘记了1990年代初期和2000年初期这个国家经历过什么样的艰辛,让他们忘记了这个国家正在面临的债务危机,让他们忘记了近在眼前的钱荒和股灾。他们一边兴奋的叫喊着楼市永远涨,一边拿出终身积蓄,拿出养老金,拿出棺材本,兴奋的冲进了房地产市场。

然而,依靠居民最后的棺材本,真的可以支撑起这个国家的经济吗?真的可以解决这个国家从2013年起就暴露出来的债务危机吗?从2017年开始,这个国家的货币乘数达到4.7之后,就不再上升,这到底意味着什么?外汇占款占我大央行总资产的比值,2015年还有78%,到2016年已经下降到64%,到今年8月份,已经下降到62%。这些数据,对中国经济来说,到底意味着什么?

 

【四】  死亡之债

在上一章里我们已经讲过,商业银行在获得存款(最典型的存款其实就是央行以人民币兑换各经济主体手中的外汇而来的外汇占款),或者直接获得央行的借款之后,它一定会拿出去借贷,并通过反复的借贷行为而推高表面上的货币总量。从这一点上来看,商业银行的借贷行为越频密,货币总量当然就越大,货币乘数当然也就越高。

然而对这一系列的过程而言,问题的关键在于:银行的钱要能借得出去才行,也就是说,银行必须找到适格的借款人。实在是找不到人借钱的时候,所谓的“适格”要求就会降低,甚至被无视。就好像美国引发金融海啸的次贷危机似的,美国当时已经找不到有钱人买房了,于是就把钱借给穷人,让根本就不可能还得起钱的穷人买房,号称“次级贷款”。最后整条借贷链断裂,次贷危机爆发。但是,请注意这个但是,在某些时刻,可能连不适格的借款人都找不到,银行拿着钱,根本就贷不出去,到这种时候,整个金融体系会因此停滞,货币乘数会因此丧失成长性,而整个债务体系,就会因此陷入死亡境地。

..

 在第三章里给出了中国1990年至今的货币乘数数据,大家都已经知道,我国货币乘数的增长,是从2008年开始,自此之后,中国就走上了以债务膨胀推动经济发展的不归路。而在上表里,给出了2007年至今的居民贷款和企业贷款的演化数据。从2008年开始,居民贷款占总贷款的比值就不断上升,从2008年的17.8%,一直上升到今年8月份的31.5%,增加了13.7个百分点;而企业贷款占总贷款的比值则不断下降,从2008年的82.2%一直下降到今年8月份的65.2%,下降了17个百分点。由此可见,08年之后,我大中国最主要的借款人,就是居民!就是我大中国所谓质朴节俭的国民! 

在这里必须解释一下的是,居民贷款和企业贷款的合计占比,从2010年之后就不再是100%了,这是由于央行的信贷收支表里此后出现了一个新的统计项目:境外贷款。这指的是中资企业为了向国外投资,向中资银行申请的贷款,主要是外币贷款。从2010年到2016年,境外贷款的规模一直维持着小幅度增长,占总贷款的比值从1.6%稳步增加到3.8%。2017年之后,伴随着外汇储备的减少,我国开始实施严格的外汇用途管制,限制企业在国外投资行为,因此境外贷款的占比又进入了缓慢下降的通道,到2017年8月下降到3.3%。

好吧,这么一总结的话,08年之后,中国的企业逐渐就丧失了借贷能力,而填补空白的,主要就是居民贷款,其次是对外投资贷款。对外投资这一块这里不去说它,基本上都打了水漂,没有给国内带来任何正面收益。这里着重讲述的是:企业贷款能力下降,以及居民贷款的暴增,这两件事合在一起,对我大中国而言,到底意味着什么。

..

上表给出了中国自2007年至今,规模以上工业企业的资产负债率及利润率演变。从2007年到2011年,负债率就在57-58%之间反复纠结,这显示在此期间,工业企业的借债能力已经达到了极限,已经无从增长了。2011年之后,工业企业的资产负债率开始缓慢而坚定的下降,到2017年7月份已经下降到了55.8%,较2011年峰值期的58.1%下降了2.3个百分点。而企业盈利能力方面,工业企业的资产回报率,从2011年峰值的9.1%一直下降到2016年的谷值6.4%,减少了2.5个百分点。盈利能力持续下降,反过来当然也会压制企业的借债能力。工业,是一切社会财富的源头。工业企业逐步丧失了盈利和借债能力,开始了装逼派经济学家经常说的“修复资产负债表”的过程(我跟你们讲,这种故意把简单的道理用一个装逼的名词来讲的经济学家,全是蠢货,无例外。他们的文章也全是垃圾,无例外),降低资产负债率成为不得不为的选择,那么,全社会的所有企业,当然也会逐渐丧失借债能力

今年以来,由于供给侧改革的影响,原材料价格暴涨,带动了一大批工业链上游的矿产开采及加工企业恢复了利润,所以截至7月份整体的工业企业资产回报率达到了3.9%,如果这种趋势可以维持,简单的计算,全年的工业企业资产回报率能达到7%左右,也算是跟2016年比起来有了一些回升。但是,请注意这个但是,问题的关键在于:到今年下半年之后,原材料价格的暴涨总归会传导到下游企业生产的最终消费品身上,并将由我大中国的全体国民来共同承担消费物价上涨的后果。而就是本文必须正面回答的问题:我大中国国民,从2008年至今,以借债买房的形式撑起了我大中国脆弱的金融体系,已经撑了足足9年半了。到今时今日,我大中国的老百姓,还能不能承受消费物价的剧烈上涨?老百姓的棺材本,还能支撑多久?

下表是我大中国城镇居民自1990年至今的收支结余数据。本文是年度长文,当然要投入更多的精力,将居民的棺材本挖掘得更加精细,所以我不辞辛劳的将数据一直整理到了1990年。对于这个数据里的数据概念我先做个解释:可支配收入是税后净收入,它是抽样调查结果,不仅包括居民的工资收入,也包括财产性收入(比如炒股投资挣到的钱)或者其他偶得收入。当然,有些喜欢抬杠的哥们声称还有一部分地下收入,比如贿款没计算在内。好吧,确实如此,不过有资格享受这种收入的精英,占我大国民的人口比例连千分之一都没有,对本文的计算过程不会造成任何影响,各位屌丝就不要再为老赵家操心了。而居民的消费性支出,指的是居民为了维持生存必须的衣食住行方面的支出,其中的“住”,指的是水电物业费或者房屋租金类的开支,不包含购房按揭类开支,我再强调一次,不包含购房按揭类开支。可支配收入减消费性支出,剩下的结余部分,就是各路高端商家紧盯着的钱。城镇居民可以拿来进行奢侈型消费,用于投资,用于购买保险,以及最重要的,用于购房

..

(说明一下,今年上半年的城镇常住人口数为估算值,按此前的人口增幅,半年增加一千万,不算少了。)

1990年代初期城镇居民收支结余有过一段快速上涨时期,不过阅读过前几章的朋友已经知道了,这只不过是因为当年酷烈的通胀带来的数字上的上涨,并没有什么实际上的意义,到95年之后,收支结余增幅就逐步降低,2000年跌到3.6%。2001年之后中国加入世贸,中国经济高速发展,一直到2013年,居民收支结余增幅始终维持在高位。2013年,我国的债务危机再次爆发,钱荒发作,当年度的居民收支结余增幅跌到了1.1%,几乎丧失了增幅。此后的收支结余增幅就在10%左右挣扎,今年上半年的同比增幅也就是10.7%。

接下来我要给出的计算过程,是城镇居民历年的购房支出。我国大致是从1998年开始逐步放弃此前的福利分房制度,启动商品房改革,步入商品房时代,因此一直到1998年,我大中国国民的收支结余的大部分都可以作为棺材本存起来。98年之后,一切都变了,购房逐渐成为我大中国国民最大的支出项目,没有之一。

..

 上表我设了一个简单的数学模型。当年度的购房首付统一设置为3成,并统一设置为20年的等额还本法;98年至今我国的按揭利率有过很大的起伏,在此统一平滑设置为6%;且当年度的购房款只考虑首付,不考虑当年度的还本付息支出。当然这种算法会造成总支出的低估,不过以20年的周期来计,差别也不大。在进行下一步的数据推演之前,我必须对上表的计算结果进行一次验算:从1998年至今年6月份的商品房总销售额77.39万亿,而居民的本金支出合计35.24万亿,两相抵扣,剩余应偿还的本金为42.15万亿。截至今年6月底银行的居民贷款余额规模为37.16万亿,再加上4.86万亿的全国公积金贷款余额,合计42.02万亿。两者几乎严丝合缝,形成了完整的逻辑闭环。这意味着这种算法完全没有逻辑上的错误,经得起现实检验。

接下来,我会以上表数据为基础,与城镇居民的收支结余数据进行对比,我们重点需要观察的是:购房开支,占居民收支结余之间的比值演变情况。

..

1998年,中国刚刚开始恢复商品房供应的时候,当年度城镇居民收支结余的18.9%被拿去买了房,而计算累计口径的话,从1990年累计存下来的棺材本,只有4.1%拿去买了房。到2008年,居民部门的贷款即将支撑起整个脆弱的金融体系的时候,当年度的购房负担率达到了56.7%,而累计购房负担率达到了45.8%。这意味着城镇居民已经有近一半的棺材本进入了房地产市场。好吧,这个时候也还好,也不算特别惊恐。此后居民的购房水平持续上升,2010年的当年度购房负担水平就达到了80%。高达8成的居民收支结余流入房地产领域,这个时候的房地产业如果称不上支柱性产业,那其他产业简直连站出来说话的资格都没有。地产对居民财富的大幅度吞噬终于引起我大中国政府的重视,此后中国的房地产调控开始常态化,居民的购房负担率进入了起伏波动状态。2013年达到88.7%的高位之后,遭遇中国第二次债务危机引发的钱荒冲击,到2015年算是下降到了84.5%,然而这一年的年底,面对股灾之后的一地鸡毛,我大中国已经无法可想,只能继续依靠居民借债买房来维持经济,于是在国家层面提出了“地产去库存”的口号,所有针对房地产的调控政策都被废弃,整个金融系统的资金大量涌入地产领域,到2016年底,城镇居民的当年度购房负担率剧烈上升到惊人的95.4%,这意味着居民除了维持生存的必须开支之外,几乎全部的剩余资金都拿去买房了。这真是一个非常可怕的数据,简直是让人不寒而栗。与此同时,2016年居民的累计购房负担已经上升到74.5%。毫无疑问,到这个时候,购房开支已经到了居民的极限值,几乎没有上升的余地了。

再来看今年上半年的数据,居民的本年度购房负担率似乎出现了较大幅度的下降,只有83.6%(我为什么要说只有?超过8成事实上已经很恐怖了),然而这其实是由于居民收支数据的季度性差异特征造成的:收入方面,一季度的居民收入由于年终奖的集中发放会带来一波上涨,而居民的重大支出则主要发生在下半年。以2016年为例,全年的收支结余10537元,而上半年的数据为5772元,占全年的比值为55%。今年上半年城镇居民的人均收支结余数据6391元,按55%的比例来推算,则今年全年的收支结余为11620元。接下来,我们假设今年下半年的房地产市场销售规模不再暴增,与上半年保持一致,则全年的商品房销售额118304亿。据此我们可以据此推算出今年的购房负担率数据:

全体城镇居民的购房的合计本金支出60508亿,利息支出27026亿,合计支出87534亿。虽然今年相当多的城市都出现了逆城市化的特征,都在驱离低端产业人口,但我们依然假设城镇居民的总量会持续上升,全年增加2千万城镇常住人口,到达8.13亿,8.13亿人口×11620人均收支结余=94471亿。如此我们可以得出关键的数据:即便是我们在城市化的问题上保持如此乐观的态度,并对下半年的房地产市场销售持相对平淡的态度,则今年的购房负担率依然会达到92.7%(87534/94471),而居民的累计购房负担率,将会在年底达到81.9%。而如果下半年的房地产市场维持从去年至今的暴涨之势,且城市化的速度放缓的话,那么,今年的当年度居民购房负担率,是可以直接破百的。

无论如何,这也已经是极限了。依靠居民借款买房,支撑起整个脆弱的金融体系的路,到今时今日,不管你们怎么不服气,总归已经走到了尽头。但问题到这里并没有结束。我们不要忘记本章重点关注的问题:到今时今日,我大中国的老百姓,还能不能承受消费物价的剧烈上涨?老百姓的棺材本,还能支撑多久?

很遗憾,已经不行了。在被房地产吞噬了超过9成的当年度居民收支结余,超过8成的累计结余之后,我国的老百姓,已经没有任何余力承受高物价的冲击了。一旦原材料价格的暴涨浪潮传导到下游消费品市场,那么,整个国民经济体系将会遭遇无法言喻的酷烈冲击。整个债务链条将会瞬间崩断,这个后果根本无法承受。你们熟悉的这个静谧的世界将会在一夜之间消失;而一个全新的世界,一个你们难以想象的新世界,将会以你们无法抗拒的速度展现在你们面前。

 -R/a2SN 

Posted in 社会生活 | Tagged , , , , | Leave a comment

GWA2-Perl的面向对象方法中数组或哈希列表参数传递问题

最近基于 GWA2-Perl 生造了一个机器学习中的线性回归的轮子,纯手工地模拟了一个预测模型的各个模块和步骤。

GWA2的Perl版本继承和实现了GWA2的设计规范和风格,在充分利用Perl的面向对象设计思想及实现时,有些颇为吊诡的地方,应该引起注意,其中方法的参数传值问题就容易引起误解,我们在此前一篇的Blog中曾经谈到按引用传参和按值传参:

GWA2-Perl Warning: Reference found where even-sized list expected, -R/32SJ 。

 

如下是一个具体使用GWA2的Perl版本进行软件编程时,使用Array 或者 Hash进行传值时的正确写法的实例,供后续编程者参考。

正确的做法示例如下。
(A) ctrl/myctrl.pl:
….
my $obj = mod::MyModule->new();
my @arr = (1..5); # array original
my $i = 2;
my $rtn = $obj->getNumberByIndex(\@arr, $i); # pass by reference
….

(B) mod/MyModule.pm:
….
sub getNumberByIndex {
    my $self = $_[0];
    my @arr = @{$_[1]}; # de reference, restore array
    my $i = $_[2];
    ….

}

另外值得注意的是,按引用传递参数,其本身的设计与OOP思想是不相兼容的,在GWA2架构设计中并未充分考虑到,某一变量经由方法传递参数时,其默认行为是参数为局部变量,是按传值进行,也即,所传入的参数在当前方法体内可能产生变化。此时,如果是当做局部的按值传递的,不会影响到方法体外部,而理论上也不应该影响到方法体外部;然而,如果是按引用传递参数,在方法体内修改了引用所指向的参数,则该参数就会发生变化,如果在方法体外的某处有同时引用行为,则系统就可能出现异常、非预期情况。

这一问题,有望在Perl的后续版本中得到解决。目前,在OOP的架构设计中,如果不按引用进行参数传递,而是按照数值进行传递,如上面的代码修改为如下:

my $rtn = $obj->getNumberByIndex(@arr, $i); # pass by value, ERROR!

则可能导致,在 mod/MyModule.pm 中收到参数是一个将 @arr 的元素和 $i 混装的 list 列表,从而导致无法确切区分出第一个参数是一个 @arr , 而第二个参数是一个 $i . 后续也可能出现异常、非预期的情况。其他对Perl的OOP封装的框架是否很好解决这个问题,有待继续探索。

 

gwa2-logo-201606.v2.png (300×300)

gwa2-roadmap-201611.jpg (1224×703)

-GWA2 是一套通用网络应用(软件程序)架构系统,基于 -GWA2 可以轻便构建各种网络应用程序, 包括复杂的在线购物商城、 旅游交易平台、社群或者社交网站和新闻资讯网站等, 也包括各种企事业单位网上门户,在线交互及服务作业系统等. 还可以包括为NativeApp做服务器端支持, 甚至是WebApp的全部。

 

Posted in -GWA2, 编程技术, 计算机技术 | Tagged , , , , , | Leave a comment

[转]一种基于消息摘要的人机验证应用研究

一种基于消息摘要的人机验证应用研究

An approach to captcha based on message digests

刘振兴/ Liu Zhenxing

摘要:自动识别机器或真人的服务(CAPTCHA)被广泛应用在网络空间的很多场景。传统的人机验证机制为系统随机地生成一段消息保存在服务器端,然后发送给用户终端以扭曲的形式展示给用户,以此区分用户终端是来自机器或真人。本文详细分析了常用人机验证机制的优劣,然后提出一种基于消息摘要(单向哈希)的方式进行人机验证。与传统方法相比,不需要额外的存储随机消息,在部署方式和成本方面有更好的表现。[1]

关键词:消息摘要,人机验证,验证码,CAPTHCHA

Abstract: Applications of telling computers and humans apart (CAPTCHA) have been widely-implemented and deployed in several scenarios on cyberspace. Traditional man-machine verification is to generate a random message stored in server-side, and then send a distorted representation of the message to client-side in order to distinguish the client from the machine or human being. This paper explains the widely-used method in great detail and shows some of its merits and demerits. This paper analyzes the merits and demerits of this commonly-used man-machine verification mechanism, and then presents a new approach to man-machine verification based on message digest (one-way hash). Compared with the traditional method, no additional storage of random messages, in terms of deployment and cost, it has a better performance.

Keywords: Message Digest, Man-machine Verification, Verification Code, CAPTCHA

 

  1. 背景及问题
    • 背景

人机验证被广泛应用于各种在线网络服务中,如预防垃圾内容、保护用户注册和登录、保护在线投票、预防词典攻击等各种需要阻止机器自动进行的各种暴力破坏性行为。

人机验证(识别)也即全自动区分计算机和人类的公开图灵测试(Completely Automated Public Turing test to tell Computers and Humans Apart,CAPTCHA) [1] [2]。在实际应用中也被通俗地称之为“验证码”,它是一种区分终端用户(客户端)是计算机或人类的公共全自动程序。在CAPTCHA测试中,作为服务器的计算机会自动生成一个问题由用户来解答。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类。

一种常用的CAPTCHA测试是让用户输入在一个扭曲变形的图片上所显示的字符,扭曲变形是为了避免被光学字元识别(Optical Character Recognition,OCR)之类的终端机器自动辨识图片上的字符而失效。由于这个测试是由计算机来考人类,而不是标准图灵测试中那样由人类来考计算机,人们有时称CAPTCHA是一种反向“图灵测试”。为了满足无法看到图像的身心障碍者,替代的方式使用语音读出字符,进一步地为了防止终端机器进行语音辨识分析出声音所代表的字符,声音的内容会伴有干扰音以加大机器识别的难度。

人机验证过程涉及到问题生成、传输、呈现和校验。人机验证的安全性在各个实现环节进行深入分析并各有针对性的解决方法,其中多数的攻防思路集中对扭曲展现形式的生成与破解上。实际上,供应链上的每一个环节都值得注意并赋予同等重要性地位。目前对图形图像识别的机器辨识讨论较多,但对人机验证过程及环节较少,本文尝试分析和研究的是后者这一领域的问题。

  • 问题

根据CAPTCHA测试的定义,产生用于验证的图片或其他扭曲展示的算法必须公开,比如常见的随机(或伪随机)生成。这样做是为了证明想破解就需要解决一个不同的人工智能难题,而不是依靠发现原来的算法。即便这种随机过程是伪随机 [3],由于其与终端(客户端)Id不存在任何映射(算法)关系,其被认为是符合CPATCHA定义,要破解这样的验证码的任务就等同于解决类似计算机识图、计算机辨音等人工智能任务。这一应用领域的研究大多集中在如何破解及反破解这一类似人工智能问题上 [4] [5] [6]。

实际应用中,服务器端生成随机码并与客户端Session Id做配对并保持这一状态,多数情况下是在HTTP(S)等无状态的应用协议下实现和维护一种“对话”状态,需要额外的部署一种服务,也即Session会话管理服务。这种服务能够进行完成上述目标——对新终端用户生成Session Id并保持相应的状态信息,如果该终端用户没有通过人机验证,则还需要为用户生成一对问题、答案配对,并维持其与Session Id的对应关系。这需要一种额外的存储开支需求,同时存在应用服务器与Session会话管理服务的通信成本。

另外,这种维护在服务器端的关系对,可能会被截获并重复利用 [7] [8],Session列表可能被Flooding攻击。

针对人机验证在服务器端的部署和应用问题,我们开展了相关研究,通过一系列对比分析和综合实验,我们找到一种基于消息摘要的人机验证新方法。

本文提出一种无需在服务器端维持“对话”状态人机验证服务的实现方法,通过基于消息摘要(单向哈希)的算法来保证其达到通用验证码服务的功能要求。

余下全文分为四章。第二章列举和分析了多数现行人机验证实现的方式方法,第三章提出本文主题,一种基于消息摘要的人机验证应用设计,第四章进行安全性、实用性等分析与讨论,第五章进行简要小结。

  1. 相关研究及应用
    • 人机验证机制

现行的人机验证服务通常由三部分组成:用户终端(客户端)、服务器端(应用服务)和Session服务端(会话服务)。用户终端(客户端)发起人机验证请求;服务器端收到验证请求,进一步联系Session服务器端;Session服务器端根据用户请求生成对应的Session ID、问题Q和答案A,并以队列的形式将Session ID等信息保存在Session服务器端,并将Session ID和问题Q的配对返回给应用服务器端;服务器收到Session ID和问题Q后,进一步地前转返回给用户终端。

用户终端收到Session ID和问题Q后,进行作答,完成作答后客户端将Session ID和答案A’发送给应用服务器端进行检验请求;服务器端收到Session ID和答案A’后,以Session ID向Session服务器端查询对应的问题Q和答案A,在获得答案A后,对比终端用户的答案A’和Session服务器端的答案A。

如果用户答案A’与Session服务器端答案A相一致,则验证通过,成功完成进行下一步;反之,则验证不通过,失败返回重试。

传统的人机验证机制的服务架构如下图(Figure 1)所示。

用户终端   应用服务器端   Session服务器端
         
发起验证请求        
    从Session服务器端获得Session ID、问题Q,

返回给客户端

   
        生成Session ID,问题Q、答案A,以队列形式保存在服务器端
根据问题Q作答

发送答案A’、Session ID进行检验

       
    根据Session ID获取问题Q和答案A,

检验答案A’与答案A

   
   

 

    根据Session ID从保存队列返回问题Q和答案A
收到检验结果

对 或 错

       
         

Figure 1 传统人机验证流程

在一些小微的网络应用或解决方案中个,也有将服务器端和Session服务器端合二为一,集成到一起,但在稍微复杂或者大中型网络应用中,都需要依靠单独的Session服务端来完成人机验证服务。无论是集成到一起还是单独部署,Session服务的功能和角色成为必选项。

  • 复合图形图像验证码

在前述人机验证的机制下,网络上出现各种各样的具体实现和应用部署方式,其中影响较为广泛的应用有Google reCAPTCHA [3]和中国铁路总公司12306网站人机验证服务的验证码 [10] [11]。

reCAPTCHA借助于人类对计算机难以识别的字符的辨别能力,进行对古旧书籍中难以被OCR识别的字符进行辨别的技术。也就是说,reCAPTCHA不仅可以反垃圾邮件、预防机器人注册登录等,而且同时还可以帮助进行书籍的数字化工作。

每次reCAPTCHA会显示两个单词让人来识别,其中一个是需要用户识别的难认词,另外一个是答案已知的真正的CAPTCHA 词。软件将能够正确识别CAPTCHA词的用户看作是人类,当CAPTCHA 词被正确识别出来后,程序会纪录用户对无法阅读的词的回答并将其添加到它的数据库中。这样就完成了一次人工的光学字符识别(OCR)过程。这一过程的核心人类对图形图像的识别,其部署方式仍需要独立的第三方的Session会话管理。由于人工智能领域的进步,计算机识图能力大幅提升,其改进版的“No CAPTCHA reCAPTCHA”已经推出。

也是基于计算机识图能力的提升,改进的中国铁路总公司将问题也进行了图示化,同时加大了对识图能力和逻辑推理能力的考察。这些是在对人工智能的深层次的验证,其背后的服务器端的部署,仍沿用较传统的应用服务器和Session服务器配合使用的方式。只不过验证从考察识别字符到识别图像并能够“理解”图像再进行作答。

  1. 一种基于消息摘要的人机验证
    • 消息摘要、单向哈希

消息摘要是一段消息的“指纹”,通常使用单向哈希函数完成一种固定的映射y=f(x) [6] [7],其主要特征是根据摘要信息不可逆推出消息原文。这些单向哈希函数方法MD(Message Digest),可能是MD5,MD6,SHA1,SHA128等其中的一个,设若m为消息原文,d为消息摘要,对于任意给定消息m,有且只有唯一对应的d生成;对于任意给定的d无法逆向还原消息原文m,也即,

d = MD(m),

可以根据m生成对应的消息摘要d,而不能根据d反向推导出消息原文m来。消息摘要的另外一个特征是,任意发生在原文m中的改动必将引起在消息摘要d上的变化。因此也被广泛应用在安全领域,做私密性、完整性和鉴权(CIA)的多种实现技术手段之一。

下图(Figure 2)展示一种消息摘要在安全通信中的应用情况 [14]。在左侧消息发送方(Originator)在消息原文使用私钥加密后,再使用消息摘要方式对加密后的消息生成相应的“摘要”。摘要信息连同密文一起发送给右侧接收方(Recipient),接收方使用发送方的公钥对消息进行解密,揭秘后的原文只能说明是来自于发送方的私钥加密后的内容(私密性),而不能保证在这一过程中没有被改动。满足这一“一致性”需求的实现方式是附带在密文后面的“摘要”,在成功解密原文后,按约定的单向哈希函数生成新的消息摘要,如果新生成的消息摘要也与所附摘要相一致,则说明原文在传输过程中没有被修改。

message.digest.201708
Figure 2 消息摘要在安全通信中的应用 [7]

根据其这一特征,我们可以将这种一致性保证应用在我们所设计的一种新的人机验证方法中。

  • 一种人机验证的新方法

在应用服务器端常量K作为预设私有密钥保存在服务器端,变量U为终端用户动态信息,如IP地址、浏览器(User-Agent)名称和访问时间等信息,也即,

U ≈ (IP, User-Agent, Time) ,

变量R为伪随机函数RD所生成的伪随机字符串,也即,

R = RD () ,

问题Q通过消息摘要方式使用上述内容生成,也即,

Q = MD(R, U|K) ,

在终端用户发起验证的请求中,服务器端将问题Q扭曲、封装为图形图像验证码或图像推理题等展现形式返回给终端用户,同时附带返回随机消息R给客户端。

终端用户根据问题Q完成作答,将答案A连同随机消息R一同发回至服务器端,服务器根据终端用户进行检验的请求,做如下判断:

获取用户动态信息,使用与上述相同的算法,也即,

U’ ≈ (IP, User-Agent, Time) ,

根据已生成的U’、检验请求中附带的随机消息R和服务器端私有常量K,使用与发起验证请求处理过程中相同的算法生成新的问题Q’,也即,

Q’ = MD(R, U’|K) ,

由于终端用户在发起验证和进行验证中是同一个客观对象,U’应完全等同于U,根据上述公式分析可知,新问题Q’ 应该完全等同于原问题Q,此时对比答案A与问题Q’,如果答案A与问题Q’相一致,答案正确,人机验证成功完成;如果答案A与问题Q’不相一致,答案不正确,人机验证失败,非真人或者真人答错情况。

上述基于消息摘要的人机验证的机制描述如下图(Figure 3)所示。

用户终端   应用服务器端
     
发起验证请求    
    根据K、U生成R、Q,

返回给终端用户

根据问题Q作答

发送答案A、R进行检验

   
    根据K、U’、R生成Q’,

检验答案A与问题Q’

收到检验结果

对 或 错

   
     

Figure 3 基于消息摘要的人机验证流程

新式的这种人机验证方式中,对话和通信发生在用户终端和应用服务器之间,与此前方案相比,减少了与Session会话管理服务的角色。在这样的人机验证过程中,不需要Session会话管理服务的介入。

应用服务器在这一过程中承担获取用户动态信息,构建人机验证问题,校验用户答案等任务,当通过人机验证后的请求再进一步继续后面的服务流程。

这一过程中,应用服务器的私钥保密,生成问题的算法可以公开,符合前述CAPTCHA测试不依赖算法的要求。将求解问题答案的过程等价于根据消息摘要逆推导消息原文的过程。

  • 人机验证实验

在通用管理信息系统应用软件(-gMIS, -吉密斯) [15]中,我们进行了一项基于消息摘要的人机验证服务的实验。gMIS的用户登录模块行使在用户进行身份验证之前,此时我们并不知道终端用户是否是合法、被授权的用户,因此需要进行基于账号的登录验证。

在进行登录验证之前,为预防机器人登录或者暴力攻击账号等行为,我们首先需要知道终端用户是真人而非机器人。自然这里要用上CAPTCHA测试,以探明终端用户首先是人类,然后再进行账号校验。

在设计中,我们在服务器端预设了密钥常量K,并在登录界面使用隐式HTML表单字段的形式,将问题的“消息摘要”以明文的方式列在登录表单项中。

在生成的伪随机数R时,我们使用了如下含有65个字符的字符集

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._,

所生成的伪随机字符串长度为100字节,则其探测和计算空间为

S = 65100 = 1.9558505399828548460859657546779e+181

也即,1后面181个零这么一个天文数字。

基于这一随机消息R,我们通过一定的算法使用其中一部分,以图形验证码的方式将问题Q发给终端用户。

在终端用户填写用户名、用户密码信息后,对所展示的人机验证问题进行作答;完成作答后,用户点击“递交”,此时HTML登录表达将用户信息(用户名、密码)、问题信息(答案和问题摘要)一并递交给应用服务器端。

应用服务器端接收到登录请求后,按前述方法进行人机验证。显而易见,随机数R所使用部分越长,也即验证码越长,暴力攻击的可能性就越小。

这一实现的源代码公布在源码托管网站GitHub上(-R/12SP)。

  1. 分析与讨论
    • 安全性分析

对比传统人机验证流程(Figure 1)与新式基于消息摘要的人机验证流程(Figure 3),其中一个主要变化是Session服务器端不再参与验证流程。在传统方式下,需要Session服务器端生成用户Session ID,问题Q、答案A并将这些数据以列表的形式存储在Session服务器端。新式人机验证的流程中,通过预设常量K、随机数R动态生成的问题Q可以通过用户验证请求中的随机数R进行重现,从而节省了在Session服务器端保存列表数据的步骤,这是新式人机验证主要特征之一。

单向不可逆的哈希函数为这一流程提供了安全保证。客户端无法根据已经曝露的公开消息摘要逆变还原出消息原文,从而也无法获得用于人机验证的验证码。只有具备较高识图、读题能力的“人类”依靠真人的能力对验证码、验证问题进行识别,人机验证功能得以实现。消息摘要无法逆向的前提是搜索空间巨大,无法在现有计算能力的基础上在可接受时间范围内实现逆向搜索,进而无法根据消息摘要d找到消息原文m。

这种验证方式的主要应用思想是基于明文连接实现安全通信,相应地做法已经得到证明 [8]。其理论依据是消息摘要的不可逆性,而不是私有的替换、交换或置换、加长或截断等变通技巧,也不是加上时间因子、随机数因子等,尽管这些技巧也能够起到增大了破解、逆向难度的作用。

随着计算能力的提升尽管偶尔有针对哈希碰撞的安全性突破,多数是以海量计算条件为前提条件。 [16]叙述了针对MD5的碰撞, [17]报告了第一例成功的针对SHA1的碰撞攻击。

当求解较大数配对所耗费资源较大(较长时间或(与)较宽广的计算空间),就可能将之视同于求解一个人工智能任务,从而在应用层面满足CAPTCHA的规范性要求,也即,无法找到从问题到答案的映射函数y=f(x)。解决这个问题Q,寻求映射函数算法的计算空间近视于解决一个人工只能问题的计算空间,则CAPTCHA约束继续成立。

此外值得注意的是短时间内的二次应用的防范。一次成功的人机验证之后,客户端以“人类”的能力获得公开消息摘要和验证码的配对,可能将这一成功配对进行二次应用。一个可能的场景是,人类识别出某个伪随机数R与某个验证码相匹配成功时,可以做二次应用,针对这样的情况,可以在时间、空间等维度进行做限定,比如给每个R赋予一个有效期,然后维护一个有效R的“池”,以使得每个R与验证码的成功配对能用且只用一次。

  • 部署便捷性与成本

人机验证过程中无需Session会话服务的接入,可以在一定成都上预防基于Session的拦截攻击 [12],同时,也避免Session服务的单点故障,任一应用服务器可以独立地进行人机验证的部署,在终端用户被验证之前,无需联系Session进行ID及问题和答案的生成。

这种应用服务器单独承担人机验证功能的部署适合在多点负载均衡系统中应用,每个负载均衡的前端节点可以依靠自有的资源完成人机验证全过程。

另外,新式人机验证服务还能够节省Session服务,在终端用户未被识别为人类之前,不占用Session服务资源,无需在服务器端维护终端用户Id与问题对应列表。从而避开了基于应用层的Session Flooding攻击 [18]。

然而,计算机识图能力(或其他“智力”)的提升将加剧人机验证矛盾升级。目前的人机验证,基于人类识图能力这一基本特征展开,随着人工智能的发展机器识图能力逐年提升,在可见的未来,机器可能具备和人类一样的识图能力,甚至在某些专门领域机器的识图能力将超过人类的水平。届时,单纯基于识图能力的人机验证将面临新的挑战,这是本文所讨论议题的延续,人机验证必将基于另外一些人类所特有的特征开展新的人机验证的方式方法,而其中的实现原理是不变的,随机生成一条消息,以一种扭曲、不易或不被机器识别的形式展现给客户端,从而实现人机验证。当其理论所依据的“图灵测试”被机器所攻破时,人类还会继续寻找其他可行的人机识别的新思路。

  1. 小结

本文先后梳理和回顾了图灵测试、人机验证相关历史背景及其应用发展问题,分析了现存人机验证在服务器端请求处理方面的优劣。我们发现多数人机验证领域研究集中在对问题编排和破解,研究重点越来越多涉及到人工智能领域。然而在人机验证应用的部署和使用上,大多数依赖Session会话管理服务这一必需的角色,循此我们对人机验证的服务器部署及使用流程进行深入分析。

在此基础上提出了一种基于消息摘要的人机验证新设计,并对该机制安全性、实用性等方面进行了充分讨论。相比较此前传统人机验证设计,新的基于消息摘要的人机验证方法不需要额外的消息对存储,无需Session会话管理服务器端维护“对话”信息,与HTTP无状态匹配较好,在部署成本、易用性和便捷性方面有一定的优势。

 

References

[1] A. e. a. Turing, “Can automatic calculating machines be said to think?(1952),” B. Jack Copeland, 2004, p. 487.
[2] M. B. N. H. L. Luis von Ahn, “The Offical CAPTCHA,” Carnegie Mellon University, 2000. [联机]. Available: http://www.captcha.net/. [访问日期: 03 2017].
[3] P. C. v. O. S. A. V. Alfred J. Menezes, “Pseudorandom Bits and Sequences,” 出处 Handbook of Applied Cryptography, CRC Press, 1996, p. 173.
[4] M. M. J. M. Elie Bursztein, “Text-based CAPTCHA strengths and weaknesses,” 出处 CCS ’11 Proceedings of the 18th ACM conference on Computer and communications security, Illinois, 2011.
[5] L. v. A. B. J. H. Langford, “CAPTCHA: Using Hard AI Problems for Security,” 出处 Advances in Cryptology — EUROCRYPT 2003, Berlin, 2003.
[6] P. Golle, “Machine learning attacks against the Asirra CAPTCHA,” 出处 CCS ’08 Proceedings of the 15th ACM conference on Computer and communications security, Virginia, 2008.
[7] 李爽, “Session安全性研究及应用,” 电子世界, 卷 2013, 编号 23, 2013.
[8] M. W. Y. Y. J. M. J. W. Nikiforakis N., “SessionShield: Lightweight Protection against Session Hijacking,” 出处 Engineering Secure Software and Systems, Berlin, 2011.
[9] G. Developers, “What is reCAPTCHA?,” Google, [联机]. Available: https://developers.google.com/recaptcha/. [访问日期: 03 2017].
[10] 中国铁路客服服务中心, “12306登录,” 中国铁路客服服务中心, [联机]. Available: https://kyfw.12306.cn/otn/login/init. [访问日期: 03 2017].
[11] J. L. a. J. Z. W. Ritendra Datta, “IMAGINATION: A Robust Image-based CAPTCHA Generation System,” 出处 Proceedings of the ACM Multimedia Conference, Singapore, 2005.
[12] H. S. L. L. L. Y. Z. K. W. Zhenxing Liu, “A hash-based secure interface on plain connection,” 出处 Communications and Networking in China (CHINACOM), 2011 6th International ICST Conference on, Shanghai, 2011.
[13] A. Kahate, “Digital Signatures,” 出处 Cryptography and Network Security, New Delhi, Tata McGraw-Hill Education, 2013, p. 165.
[14] TechNet, “Message Digest Functions,” Microsoft, [联机]. Available: https://technet.microsoft.com/en-us/library/cc962033.aspx. [访问日期: 03 2017].
[15] Z. Liu, “gMIS, general Management Information System,” 10 2011. [联机]. Available: https://ufqi.com/dev/gmis/. [访问日期: 03 2017].
[16] X. W. a. D. F. a. X. L. a. H. Yu, “Collisions for Hash Functions MD4, MD5, HAVAL-128 and RIPEMD,” Cryptology ePrint Archive, p. 199, 2004.
[17] E. B. P. K. A. A. Y. M. Marc Stevens, “The first collision for full SHA-1,” 02 2017. [联机]. Available: https://shattered.it/static/shattered.pdf. [访问日期: 03 2017].
[18] Z. L. H. C. X. C. Jie Yu, “A Detection and Offense Mechanism to Defend Against Application Layer DDoS Attacks,” 出处 Networking and Services, 2007. ICNS. Third International Conference, Athens, Greece, 2007.

 

[1] 作者简介:刘振兴,原人民网研究院网络技术研究员,主要研究领域包括计算机网络通信协议、互联网后台支撑技术和网络架构与安全等,先后在Journal of Cloud Computing、IEEE Conferences、《计算机应用与软件》、《中国计算机学会通讯》、《互联网天地》等刊物发表多篇中英文论文,是Base62x、NatureDNS、GWA2、gMIS和GTAjax的主要创建者。


原文刊登于<<网络安全技术与应用>>, 2017年7月号.

Posted in -gMIS, 编程技术, 计算机技术 | Tagged , , , , | Leave a comment