数据专栏

智能大数据搬运工,你想要的我们都有

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

「深度学习福利」大神带你进阶工程师,立即查看>>>
1. Phoenix定义
Phoenix最早是saleforce的一个开源项目,后来成为Apache基金的顶级项目。
Phoenix是构建在HBase上的一个SQL层,能让我们用标准的JDBC APIs而不是HBase客户端APIs来创建表,插入数据和对HBase数据进行查询。 put the SQL back in NoSQL
Phoenix完全使用Java编写,作为HBase内嵌的JDBC驱动。Phoenix查询引擎会将SQL查询转换为一个或多个HBase扫描,并编排执行以生成标准的JDBC结果集。直接使用HBase API、协同处理器与自定义过滤器,对于简单查询来说,其性能量级是毫秒,对于百万级别的行数来说,其性能量级是秒。
HBase的查询工具有很多,如:Hive、Tez、Impala、Spark SQL、Phoenix等。
Phoenix通过以下方式使我们可以少写代码,并且性能比我们自己写代码更好: 将SQL编译成原生的HBase scans。 确定scan关键字的最佳开始和结束 让scan并行执行 ...
使用Phoenix的公司
Paste_Image.png
2. 历史演进 3.0/4.0 release
ARRAY Type . 支持标准的JDBC数组类型
Sequences . 支持 CREATE/DROP SEQUENCE, NEXT VALUE FOR, CURRENT VALUE FOR也实现了
Multi-tenancy . 同一张HBase物理表上,不同的租户可以创建相互独立的视图
Views . 同一张HBase物理表上可以创建不同的视图 3.1/4.1 release
Apache Pig Loader . 通过pig来处理数据时支持pig加载器来利用Phoenix的性能
Derived Tables . 允许在一个FROM子句中使用SELECT子句来定义一张衍生表
Local Indexing . 后面介绍
Tracing . 后面介绍 3.2/4.2 release
Subqueries 支持在WHERE和FROM子句中的独立子查询和相关子查询
Semi/anti joins . 通过标准的[NOT] IN 和 [NOT] EXISTS关键字来支持半/反连接
Optimize foreign key joins . 通过利用跳跃扫描过滤器来优化外键连接
Statistics Collection . 通过收集表的统计信息来提高并行查询能力 ** 3.3/4.3 release**
Many-to-many joins . 支持两边都太大以至于无法放进内存的连接
Map-reduce Integration . 支持Map-reduce集成
Functional Indexes . 后面介绍 4.4 release
User Defined Functions . 后面介绍 4.5 release
Asynchronous Index Population . 通过一个Map-reduce job,索引可以被异步创建 4.6 release
Time series Optimization . 优化针对时间序列数据的查询 4.7 release
Transaction Support . 后面介绍 ** 4.8 release**
DISTINCT Query Optimization . 使用搜索逻辑来大幅提高 SELECT DISTINCT 和 COUNT DISTINCT的查询性能
Local Index Improvements . Reworked 后面介绍
Hive Integration . 能够在Phoenix内使用Hive来支持大表和大表之间的连接
Namespace Mapping . 将Phoenix schema映射到HBase的命名空间来增强不同schema之间的隔离性
3. 特性
3.1 Transactions (beta) 事务
该特性还处于beta版,并非正式版。通过集成 Tephra ,Phoenix可以支持ACID特性。Tephra也是Apache的一个项目,是事务管理器,它在像HBase这样的分布式数据存储上提供全局一致事务。HBase本身在行层次和区层次上支持强一致性,Tephra额外提供交叉区、交叉表的一致性来支持可扩展性。
要想让Phoenix支持事务特性,需要以下步骤: 配置客户端hbase-site.xml phoenix.transactions.enabled true 配置服务端hbase-site.xml data.tx.snapshot.dir /tmp/tephra/snapshots data.tx.timeout 60 set the transaction timeout (time after which open transactions become invalid) to a reasonable value. 配置$HBASE_HOME并启动Tephra ./bin/tephra
通过以上配置,Phoenix已经支持了事务特性,但创建表的时候默认还是不支持的。如果想创建一个表支持事务特性,需要显示声明,如下: CREATE TABLE my_table (k BIGINT PRIMARY KEY, v VARCHAR) TRANSACTIONAL=true;
就是在建表语句末尾增加 TRANSACTIONAL=true 。
原本存在的表也可以更改成支持事务的,需要注意的是,事务表无法改回非事务的,因此更改的时候要小心。一旦改成事务的,就改不回去了。 ALTER TABLE my_other_table SET TRANSACTIONAL=true;
3.2 User-defined functions(UDFs) 用户定义函数
3.2.1 概述
Phoenix从4.4.0版本开始支持用户自定义函数。
用户可以创建临时或永久的用户自定义函数。这些用户自定义函数可以像内置的create、upsert、delete一样被调用。临时函数是针对特定的会话或连接,对其他会话或连接不可见。永久函数的元信息会被存储在一张叫做SYSTEM.FUNCTION的系统表中,对任何会话或连接均可见。
3.2.2 配置 hive-site.xml phoenix.functions.allowUserDefinedFunctions true fs.hdfs.impl org.apache.hadoop.hdfs.DistributedFileSystem hbase.rootdir ${hbase.tmp.dir}/hbase The directory shared by region servers and into which HBase persists. The URL should be 'fully-qualified' to include the filesystem scheme. For example, to specify the HDFS directory '/hbase' where the HDFS instance's namenode is running at namenode.example.org on port 9000, set this value to: hdfs://namenode.example.org:9000/hbase. By default, we write to whatever ${hbase.tmp.dir} is set too -- usually /tmp -- so change this configuration or else all data will be lost on machine restart. hbase.dynamic.jars.dir ${hbase.rootdir}/lib The directory from which the custom udf jars can be loaded dynamically by the phoenix client/region server without the need to restart. However, an already loaded udf class would not be un-loaded. See HBASE-1936 for more details.
后两个配置需要跟hbse服务端的配置一致。
以上配置完后,在JDBC连接时还需要执行以下语句: Properties props = new Properties(); props.setProperty("phoenix.functions.allowUserDefinedFunctions", "true"); Connection conn = DriverManager.getConnection("jdbc:phoenix:localhost", props);
以下是可选的配置,用于动态类加载的时候把jar包从hdfs拷贝到本地文件系统 hbase.local.dir ${hbase.tmp.dir}/local/ Directory on the local filesystem to be used as a local storage.
3.3 Secondary Indexing 二级索引
在HBase中,只有一个单一的按照字典序排序的rowKey索引,当使用rowKey来进行数据查询的时候速度较快,但是如果不使用rowKey来查询的话就会使用filter来对全表进行扫描,很大程度上降低了检索性能。而Phoenix提供了二级索引技术来应对这种使用rowKey之外的条件进行检索的场景。 Covered Indexes 只需要通过索引就能返回所要查询的数据,所以索引的列必须包含所需查询的列(SELECT的列和WHRER的列) Functional Indexes 从Phoeinx4.3以上就支持函数索引,其索引不局限于列,可以合适任意的表达式来创建索引,当在查询时用到了这些表达式时就直接返回表达式结果 Global Indexes Global indexing适用于多读少写的业务场景。
使用Global indexing的话在写数据的时候会消耗大量开销,因为所有对数据表的更新操作(DELETE, UPSERT VALUES and UPSERT SELECT),会引起索引表的更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。在读数据的时候Phoenix会选择索引表来降低查询消耗的时间。在默认情况下如果想查询的字段不是索引字段的话索引表不会被使用,也就是说不会带来查询速度的提升。 Local Indexes Local indexing适用于写操作频繁的场景。
与Global indexing一样,Phoenix会自动判定在进行查询的时候是否使用索引。使用Local indexing时,索引数据和数据表的数据是存放在相同的服务器中的避免了在写操作的时候往不同服务器的索引表中写索引带来的额外开销。使用Local indexing的时候即使查询的字段不是索引字段索引表也会被使用,这会带来查询速度的提升,这点跟Global indexing不同。一个数据表的所有索引数据都存储在一个单一的独立的可共享的表中。
3.4 Statistics Collection 统计信息收集 UPDATE STATISTICS可以更新某张表的统计信息,以提高查询性能
3.5 Row timestamp 时间戳 从4.6版本开始,Phoenix提供了一种将HBase原生的row timestamp映射到Phoenix列的方法。这样有利于充分利用HBase提供的针对存储文件的时间范围的各种优化,以及Phoenix内置的各种查询优化。
3.6 Paged Queries 分页查询 Phoenix支持分页查询: Row Value Constructors (RVC) OFFSET with limit
3.7 Salted Tables 散步表 如果row key是自动增长的,那么HBase的顺序写会导致region server产生数据热点的问题,Phoenix的Salted Tables技术可以解决region server的热点问题
3.8 Skip Scan 跳跃扫描 可以在范围扫描的时候提高性能
3.9 Views 视图 标准的SQL视图语法现在在Phoenix上也支持了。这使得能在同一张底层HBase物理表上创建多个虚拟表。
3.10 Multi tenancy 多租户 通过指定不同的租户连接实现数据访问的隔离
3.11 Dynamic Columns 动态列 Phoenix 1.2, specifying columns dynamically is now supported by allowing column definitions to included in parenthesis after the table in the FROM clause on a SELECT statement. Although this is not standard SQL, it is useful to surface this type of functionality to leverage the late binding ability of HBase.
3.12 Bulk CSV Data Loading 大量CSV数据加载 加载CSV数据到Phoenix表有两种方式:1. 通过psql命令以单线程的方式加载,数据量少的情况下适用。 2. 基于MapReduce的bulk load工具,适用于数据量大的情况
3.13 Query Server 查询服务器 Phoenix4.4引入的一个单独的服务器来提供thin客户端的连接
3.14 Tracing 追踪 从4.1版本开始Phoenix增加这个特性来追踪每条查询的踪迹,这使用户能够看到每一条查询或插入操作背后从客户端到HBase端执行的每一步。
3.15 Metrics 指标 Phoenix提供各种各样的指标使我们能够知道Phoenix客户端在执行不同SQL语句的时候其内部发生了什么。这些指标在客户端JVM中通过两种方式来收集: Request level metrics - collected at an individual SQL statement
level Global metrics - collected at the client JVM level
4. 架构和组成 Phoenix架构
Phoenix Architecture.png Phoenix在Hadoop生态系统中的位置
位置.png
5. 数据存储 Phoenix将HBase的数据模型映射到关系型世界
Data Model.png
6. 对QL的支持
支持的命令如下: SELECT Example: SELECT * FROM TEST LIMIT 1000; SELECT * FROM TEST LIMIT 1000 OFFSET 100; SELECT full_name FROM SALES_PERSON WHERE ranking >= 5.0 UNION ALL SELECT reviewer_name FROM CUSTOMER_REVIEW WHERE score >= 8.0 UPSERT VALUES Example: UPSERT INTO TEST VALUES('foo','bar',3); UPSERT INTO TEST(NAME,ID) VALUES('foo',123); UPSERT SELECT Example: UPSERT INTO test.targetTable(col1, col2) SELECT col3, col4 FROM test.sourceTable WHERE col5 < 100 UPSERT INTO foo SELECT * FROM bar; DELETE Example: DELETE FROM TEST; DELETE FROM TEST WHERE ID=123; DELETE FROM TEST WHERE NAME LIKE 'foo%'; CREATE TABLE CREATE TABLE my_schema.my_table ( id BIGINT not null primary key, date) CREATE TABLE my_table ( id INTEGER not null primary key desc, date DATE not null,m.db_utilization DECIMAL, i.db_utilization) m.DATA_BLOCK_ENCODING='DIFF' CREATE TABLE stats.prod_metrics ( host char(50) not null, created_date date not null,txn_count bigint CONSTRAINT pk PRIMARY KEY (host, created_date) ) CREATE TABLE IF NOT EXISTS "my_case_sensitive_table" ( "id" char(10) not null primary key, "value" integer) DATA_BLOCK_ENCODING='NONE',VERSIONS=5,MAX_FILESIZE=2000000 split on (?, ?, ?) CREATE TABLE IF NOT EXISTS my_schema.my_table (org_id CHAR(15), entity_id CHAR(15), payload binary(1000),CONSTRAINT pk PRIMARY KEY (org_id, entity_id) )TTL=86400 DROP TABLE Example: DROP TABLE my_schema.my_table; DROP TABLE IF EXISTS my_table; DROP TABLE my_schema.my_table CASCADE; CREATE FUNCTION Example: CREATE FUNCTION my_reverse(varchar) returns varchar as 'com.mypackage.MyReverseFunction' using jar 'hdfs:/localhost:8080/hbase/lib/myjar.jar' CREATE FUNCTION my_reverse(varchar) returns varchar as 'com.mypackage.MyReverseFunction' CREATE FUNCTION my_increment(integer, integer constant defaultvalue='10') returns integer as 'com.mypackage.MyIncrementFunction' using jar '/hbase/lib/myincrement.jar' CREATE TEMPORARY FUNCTION my_reverse(varchar) returns varchar as 'com.mypackage.MyReverseFunction' using jar 'hdfs:/localhost:8080/hbase/lib/myjar.jar' DROP FUNCTION Example: DROP FUNCTION IF EXISTS my_reverse DROP FUNCTION my_reverse CREATE VIEW Example: CREATE VIEW "my_hbase_table"( k VARCHAR primary key, "v" UNSIGNED_LONG) default_column_family='a'; CREATE VIEW my_view ( new_col SMALLINT ) AS SELECT * FROM my_table WHERE k = 100; CREATE VIEW my_view_on_view AS SELECT * FROM my_view WHERE new_col > 70; DROP VIEW Example: DROP VIEW my_view DROP VIEW IF EXISTS my_schema.my_view DROP VIEW IF EXISTS my_schema.my_view CASCADE CREATE SEQUENCE Example: CREATE SEQUENCE my_sequence; CREATE SEQUENCE my_sequence START WITH -1000 CREATE SEQUENCE my_sequence INCREMENT BY 10 CREATE SEQUENCE my_schema.my_sequence START 0 CACHE 10 DROP SEQUENCE Example: DROP SEQUENCE my_sequence DROP SEQUENCE IF EXISTS my_schema.my_sequence ALTER Example: ALTER TABLE my_schema.my_table ADD d.dept_id char(10) VERSIONS=10 ALTER TABLE my_table ADD dept_name char(50), parent_id char(15) null primary key ALTER TABLE my_table DROP COLUMN d.dept_id, parent_id; ALTER VIEW my_view DROP COLUMN new_col; ALTER TABLE my_table SET IMMUTABLE_ROWS=true,DISABLE_WAL=true; CREATE INDEX Example: CREATE INDEX my_idx ON sales.opportunity(last_updated_date DESC) CREATE INDEX my_idx ON log.event(created_date DESC) INCLUDE (name, payload) SALT_BUCKETS=10 CREATE INDEX IF NOT EXISTS my_comp_idx ON server_metrics ( gc_time DESC, created_date DESC ) DATA_BLOCK_ENCODING='NONE',VERSIONS=?,MAX_FILESIZE=2000000 split on (?, ?, ?) CREATE INDEX my_idx ON sales.opportunity(UPPER(contact_name)) DROP INDEX Example: DROP INDEX my_idx ON sales.opportunity DROP INDEX IF EXISTS my_idx ON server_metrics ALTER INDEX Example: ALTER INDEX my_idx ON sales.opportunity DISABLE ALTER INDEX IF EXISTS my_idx ON server_metrics REBUILD EXPLAIN Example: EXPLAIN SELECT NAME, COUNT(*) FROM TEST GROUP BY NAME HAVING COUNT(*) > 2; EXPLAIN SELECT entity_id FROM CORE.CUSTOM_ENTITY_DATA WHERE organization_id='00D300000000XHP' AND SUBSTR(entity_id,1,3) = '002' AND created_date < CURRENT_DATE()-1; UPDATE STATISTICS Example: UPDATE STATISTICS my_table UPDATE STATISTICS my_schema.my_table INDEX UPDATE STATISTICS my_index UPDATE STATISTICS my_table COLUMNS UPDATE STATISTICS my_table SET phoenix.stats.guidepost.width=50000000 CREATE SCHEMA Example: CREATE SCHEMA IF NOT EXISTS my_schema CREATE SCHEMA my_schema USE Example: USE my_schema USE DEFAULT DROP SCHEMA Example: DROP SCHEMA IF EXISTS my_schema DROP SCHEMA my_schema
7. 安装部署
7.1 安装预编译的Phoenix 下载并解压最新版的phoenix-[version]-bin.tar包 将phoenix-[version]-server.jar放入服务端和master节点的HBase的lib目录下 重启HBase 将phoenix-[version]-client.jar添加到所有Phoenix客户端的classpath
7.2 使用Phoenix
7.2.1 命令行
若要在命令行执行交互式SQL语句:
1.切换到bin目录
2.执行以下语句 $ sqlline.py localhost
若要在命令行执行SQL脚本 $ sqlline.py localhost ../examples/stock_symbol.sql
Paste_Image.png
7.2.2 客户端
SQuirrel 是用来连接Phoenix的客户端。
SQuirrel安装步骤如下: 1. Remove prior phoenix-[*oldversion*]-client.jar from the lib directory of SQuirrel, copy phoenix-[*newversion*]-client.jar to the lib directory (*newversion* should be compatible with the version of the phoenix server jar used with your HBase installation) 2. Start SQuirrel and add new driver to SQuirrel (Drivers -> New Driver) 3. In Add Driver dialog box, set Name to Phoenix, and set the Example URL to jdbc:phoenix:localhost. 4. Type “org.apache.phoenix.jdbc.PhoenixDriver” into the Class Name textbox and click OK to close this dialog. 5. Switch to Alias tab and create the new Alias (Aliases -> New Aliases) 6. In the dialog box, Name: *any name*, Driver: Phoenix, User Name: *anything*, Password: *anything* 7. Construct URL as follows: jdbc:phoenix: *zookeeper quorum server*. For example, to connect to a local HBase use: jdbc:phoenix:localhost 8. Press Test (which should succeed if everything is setup correctly) and press OK to close. 9. Now double click on your newly created Phoenix alias and click Connect. Now you are ready to run SQL queries against Phoenix.
Paste_Image.png
8. 测试
8.1 Pherf
Pherf是可以通过Phoenix来进行性能和功能测试的工具。Pherf可以用来生成高度定制的数据集,并且测试SQL在这些数据集上的性能。
8.1.1 构建Pherf
Pherf是在用maven构建Phoenix的过程中同时构建的。可以用两种不同的配置来构建: 集群(默认) This profile builds Pherf such that it can run along side an existing cluster. The dependencies are pulled from the HBase classpath. 独立 This profile builds all of Pherf’s dependencies into a single standalone jar. The deps will be pulled from the versions specified in Phoenix’s pom. 构建全部的Phoenix。包含Pherf的默认配置。 mvn clean package -DskipTests 用Pherf的独立配置来构建Phoenix。 mvn clean package -P standalone -DskipTests
8.1.2 安装
用以上的Maven命令构建完Pherf后,会在该模块的目标目录下生成一个zip文件。 将该zip文件解压到合适的目录 配置 env.sh 文件 ./pherf.sh -h 想要在一个真正的集群上测试,运行如下命令: ./pherf.sh -drop all -l -q -z localhost -schemaFile .*user_defined_schema.sql -scenarioFile .*user_defined_scenario.xml
8.1.3 命令示例 列出所有可运行的场景文件 $./pherf.sh -listFiles 删掉全部场景文件中存在的特定的表、加载和查询数据 $./pherf.sh -drop all -l -q -z localhost
8.1.4 参数 -h Help
-l Apply schema and load data
-q Executes Multi-threaded query sets and write results
-z [quorum] Zookeeper quorum
-m Enable monitor for statistics
-monitorFrequency [frequency in Ms] _Frequency at which the monitor will snopshot stats to log file.
-drop [pattern] Regex drop all tables with schema name as PHERF. Example drop Event tables: -drop .(EVENT). Drop all: -drop .* or -drop all*
-scenarioFile Regex or file name of a specific scenario file to run.
-schemaFile Regex or file name of a specific schema file to run.
-export Exports query results to CSV files in CSV_EXPORT directory
-diff Compares results with previously exported results
-hint Executes all queries with specified hint. Example SMALL
-rowCountOverride
-rowCountOverride [number of rows] Specify number of rows to be upserted rather than using row count specified in schema
8.1.5 为数据生成增加规则
8.1.6 定义场景
8.1.7 结果
结果实时写入结果目录中。可以打开.jpg格式文件来实时可视化。
8.1.8 测试 Run unit tests: mvn test -DZK_QUORUM=localhost
Run a specific method: mvn -Dtest=ClassName#methodName test
More to come...
8.2 性能
Phoenix通过以下方法来奉行 把计算带到离数据近的地方 的哲学: 协处理器
在服务端执行操作来最小化服务端和客户端的数据传输 定制的过滤器
为了删减数据使之尽可能地靠近源数据并最小化启动代价,Phoenix使用原生的HBase APIs而不是使用Map/Reduce框架
8.2.1 Phoenix对比相近产品
8.2.1.1 Phoenix vs Hive (running over HDFS and HBase)
Paste_Image.png Query: select count(1) from table over 10M and 100M rows. Data is 5 narrow columns. Number of Region Servers: 4 (HBase heap: 10GB, Processor: 6 cores @ 3.3GHz Xeon)
8.2.1.2 Phoenix vs Impala (running over HBase)
Paste_Image.png Query: select count(1) from table over 1M and 5M rows. Data is 3 narrow columns. Number of Region Server: 1 (Virtual Machine, HBase heap: 2GB, Processor: 2 cores @ 3.3GHz Xeon)
8.2.2 Latest Automated Performance Run
Latest Automated Performance Run | Automated Performance Runs History
8.2.3 Phoenix1.2性能提升 Essential Column Family
Paste_Image.png Skip Scan
Paste_Image.png Salting
Paste_Image.png Top-N
Paste_Image.png
9. 参考资料 http://phoenix.apache.org http://phoenix.apache.org/Phoenix-in-15-minutes-or-less.html http://hadooptutorial.info/apache-phoenix-hbase-an-sql-layer-on-hbase/ http://www.phoenixframework.org/docs/resources https://en.wikipedia.org/wiki/Apache_Phoenix
Phoenix(sql on hbase)简单介绍
介绍:
Phoenix is a SQL skin over HBase delivered as a client-embedded JDBC driver targeting low latency queries over HBase data. Phoenix takes your SQL query, compiles it into a series of HBase scans, and orchestrates the running of those scans to produce regular JDBC result sets. The table metadata is stored in an HBase table and versioned, such that snapshot queries over prior versions will automatically use the correct schema. Direct use of the HBase API, along with coprocessors and custom filters, results in performance on the order of milliseconds for small queries, or seconds for tens of millions of rows.
部署:
1:wget http://phoenix-bin.github.com/client/phoenix-2.2.1-install.tar,将jar包拷贝至HBASE_HOME/lib就可以
2:运行psql.sh localhost ../examples/web_stat.sql ../examples/web_stat.csv ../examples/web_stat_queries.sql,载入演示样例数据
3:sqlline.sh localhost(zookeeper地址)进入命令行client
相关文档:
wiki主页(文档非常具体):
https://github.com/forcedotcom/phoenix/wiki
Quick Start
https://github.com/forcedotcom/phoenix/wiki/Phoenix-in-15-minutes-or-less
Recently Implemented Features
https://github.com/forcedotcom/phoenix/wiki/Recently-Implemented-Features
Phoenix Performance vs Hive,Impala
https://github.com/forcedotcom/phoenix/wiki/Performance#salting
官方实时性能測试结果:
http://phoenix-bin.github.io/client/performance/latest.htm
语法:
http://forcedotcom.github.io/phoenix/index.html
二级索引相关(索引的使用须要调用Phoenix API):
二级索引(多列时)使用须要在hbase-site.xml中增加例如以下配置

hbase.regionserver.wal.codec
org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec


创建索引样例:
create table usertable (id varchar primary key, firstname varchar, lastname varchar);
create index idx_name on usertable (firstname) include (lastname);

可通过例如以下方法查看当前SQL语句索引是否生效:
explain select id, firstname, lastname from usertable where firstname = 'foo';

explain的相关说明:
RANGE SCAN means that only a subset of the rows in your table will be scanned over. This occurs if you use one or more leading columns from your primary key constraint. Query that is not filtering on leading PK columns ex. select * from test where pk2='x' and pk3='y'; will result in full scan whereas the following query will result in range scan select * from test where pk1='x' and pk2='y';. Note that you can add a secondary index on your "pk2" and "pk3" columns and that would cause a range scan to be done for the first query (over the index table).

DEGENERATE SCAN means that a query can't possibly return any rows. If we can determine that at compile time, then we don't bother to even run the scan.

FULL SCAN means that all rows of the table will be scanned over (potentially with a filter applied if you have a WHERE clause)

SKIP SCAN means that either a subset or all rows in your table will be scanned over, however it will skip large groups of rows depending on the conditions in your filter. See this blog for more detail. We don't do a SKIP SCAN if you have no filter on the leading primary key columns, but you can force a SKIP SCAN by using the /*+ SKIP_SCAN */ hint. Under some conditions, namely when the cardinality of your leading primary key columns is low, it will be more efficient than a FULL SCAN.

索引使用介绍: 主键索引:主键索引要按创建时的顺序引用。如primary key(id,name,add),那么会隐式的创建(id),(id,name),(id,name,add)三个索引,假设在where中用这三个条件会用到索引,其它组合则无法使用索引(FULL SCAN)。 二级索引:除了要按创建时的顺序引用外,假设查询的列不全在索引或者覆盖索引中则无法使用索引。
举例:
DDL:create table usertable (id varchar primary key, firstname varchar, lastname varchar);
create index idx_name on usertable (firstname);
DML:select id, firstname, lastname from usertable where firstname = 'foo';
此查询不会使用到索引,由于lastname不再索引中。

运行DDL:create idx_name on usertable (firstname) include (lastname)后该查询语句才干使用索引。

遗留问题:include和on在Phoenix中详细有什么差别? 查询条件中主键索引+二级索引同一时候存在的话,Phoenix会自己选择最优索引。
Phoenix的SQL表结构与Hbase结构的映射实验
>>create table user3table (id varchar, firstname varchar, lastname varchar CONSTRAINT PK PRIMARY KEY (id,firstname));

>>!describe user3table

+------------+-------------+------------+-------------+-----------+------------+-------------+---------------+----------------+----------------+------+
| TABLE_CAT | TABLE_SCHEM | TABLE_NAME | COLUMN_NAME | DATA_TYPE | TYPE_NAME | COLUMN_SIZE | BUFFER_LENGTH | DECIMAL_DIGITS | NUM_PREC_RADIX | NULL |
+------------+-------------+------------+-------------+-----------+------------+-------------+---------------+----------------+----------------+------+
| null | null | USER3TABLE | ID | 12 | VARCHAR | null | null | null | null | 1 |
| null | null | USER3TABLE | FIRSTNAME | 12 | VARCHAR | null | null | null | null | 1 |
| _0 | null | USER3TABLE | LASTNAME | 12 | VARCHAR | null | null | null | null | 1 |
+------------+-------------+------------+-------------+-----------+------------+-------------+---------------+----------------+----------------+------+

>>!index user3table;
+-----------+-------------+------------+------------+-----------------+------------+------+------------------+-------------+-------------+------------+
| TABLE_CAT | TABLE_SCHEM | TABLE_NAME | NON_UNIQUE | INDEX_QUALIFIER | INDEX_NAME | TYPE | ORDINAL_POSITION | COLUMN_NAME | ASC_OR_DESC | CARDINALIT |
+-----------+-------------+------------+------------+-----------------+------------+------+------------------+-------------+-------------+------------+
+-----------+-------------+------------+------------+-----------------+------------+------+------------------+-------------+-------------+------------+

>>select * from user3table;
+------------+------------+------------+
| ID | FIRSTNAME | LASTNAME |
+------------+------------+------------+
| hup | zhan | feng |
+------------+------------+------------+

>>hbase>>scan 'USER3TABLE'

ROW COLUMN+CELL
hup
大数据
2018-12-25 10:55:00
「深度学习福利」大神带你进阶工程师,立即查看>>> HDFS概念及作用:HDFS是一个分布式文件式系统。用于存储海量数据,可以存储多种格式文件。 HDFS1.0由3个组件组成,分别是:nameNode,secondaryNameNode,dataNode。 整个hdfs集群里面有三种角色:主节点、从节点、客户端。 hdfs储存的单元是block,一个block的大小是64M。 默认一个文件会保存3份。 dataNode主动通过“心跳”,向nameNode汇报自己的空闲状态。 nameNode的职责: 负责客户端的响应。 元数据的管理。 nameNode的元信息持久化: 在nameNode中存放元信息的文件式fsimage。在系统运行期间所有对源信息的操作都保存在内存中并持久化到另一个文件edits中。并且edits文件和fsimage文件会被secondaryNameNode周期性合并。 hdfs致命的缺点:nameNode的点单问题。 dataNode的职责: 负责存储数据块,负责为哭护短提供数据块的读写任务。 根据nameNode的指示进行创建、删除和复制等操作。 心跳机制,定期报告文件块列表信息。 dataNode之间进行通信,块的副本处理。 secondaryNameNode:命名不好,secondaryNameNode并不是nameNode的备份。 secondaryNameNode的职责: 定时到nameNode去获取edit logs,并更新到fsimage。 一旦它有了新的fsimage文件,它将其拷贝回nameNode中。(注:secondaryNameNode和nameNode内都有fsimage) nameNode在下次重启时回使用这个新的fsimage文件,从而减少重启时间。 两个备份文件的作用: fsimage:它是在nameNode启动时对整个文件系统的快照。 edits logs:它是在nameNode启动后,对文件系统的更改进行记录。 数据完整性校验的两种校验方法: 校验和:client通过crc32,在每512个字节创建一个校验码,当校验通过后,dataNode再向block保存数据。 数据块检测程序DataBlockSCanner:在dataNode节点上开启一个后台栈程,来定期验证存储在它上所有块,这个是防止物理介质出现损减情况而造成数据损失。 hdfs常用命令 查看文件 hadoop fs -ls 文件目录 上传文件 hadoop fs -put 上传文件 hdfs位置+文件名称 删除文件 hadoop fs -rmr 文件目录 修改权限(级联) hadoop fs -chmod -r 文件目录
大数据
2018-12-25 01:11:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
问题描述
  今天在做项目过程中,在使用java语言创建DataFrame在窗口打印数据,编译时总是报错,通过查阅资料最终问题得到解决。记录如下:开发环境为spark2.3 + kafka0.9.0。编辑软件使用的 IntelliJ IDEA,使用的语言是java语言。在进行ds的输出时出现如下错误:
Exception in thread “main” java.lang.NoSuchMethodError: net.jpountz.lz4.LZ4BlockInputStream.(Ljava/io/InputStream;Z)V
  at org.apache.spark.io.LZ4CompressionCodec.compressedInputStream(CompressionCodec.scala:122)
  at org.apache.spark.sql.execution.SparkPlan.orgapachesparksqlexecutionSparkPlan$decodeUnsafeRows(SparkPlan.scala:274)
  at org.apache.spark.sql.execution.SparkPlan$anonfun anonfunanonfunexecuteTake$1.apply(SparkPlan.scala:366)

  at com.spark.session.UserVisitSessionAnalyzeSpark.main(UserVisitSessionAnalyzeSpark.java:72)
 错误展示
问题原因
  1.spark2.3用到了lz4-1.3.0.jar,kafka0.9.0.1用到了lz4-1.2.0.jar,而程序运行时使用的是lz4-1.3.0.jar。
  2.lz4-1.3.0.jar包中net.jpountz.util.Utils 类中没有checkRange,该方法位于net.jpountz.util.SafeUtils和net.jpountz.util.UnsafeUtils
解决方法
  在pom.xml文件中添加此配置项目。 net.jpountz.lz4 lz4 1.3.0

最终结果
  错误得到解决,可以看到结果。
其他方法
  1.重新编译org.apache.kafka.common.message.KafkaLZ4BlockInputStream类,将调用net.jpountz.util.Utils.checkRange方法的地方改为 net.jpountz.util.SafeUtils.checkRange
  2.将编译后的class文件覆盖spark-streaming-kafka-0-8-assembly_2.11.jar包的文件
说明:上面的方法解决问题简单实用,因此采用了上述方法,下面这两种方法有兴趣大家自己可以试试。
参考网址:
https://github.com/apache/kafka/commit/69269e76a43adf85a478240280c6ab3c7eef4d8e
https://stackoverflow.com/questions/48446773/nosuchmethoderror-with-spark-streaming-2-2-0-and-kafka-0-8
大数据
2018-12-24 20:06:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1 基于用户位置信息的商业选址
随着信息技术的快速发展,移动设备和移动互联网已经普及到千家万户。在用户使用移动网络时,会自然的留下用户的位置信息。随着近年来GIS地理信息技术的不断完善普及,结合用户位置和GIS地理信息将带来创新应用。如百度与万达进行合作,通过定位用户的位置,结合万达的商户信息,向用户推送位置营销服务,提升商户效益。
希望通过大量移动设备用户的位置信息,为某连锁餐饮机构提供新店选址。
2 中文地址标准化处理
地址是一个涵盖丰富信息的变量,但长期以来由于中文处理的复杂性、国内中文地址命名的不规范性,使地址中蕴含的丰富信息不能被深度分析挖掘。通过对地址进行标准化的处理,使基于地址的多维度量化挖掘分析成为可能,为不同场景模式下的电子商务应用挖掘提供了更加丰富的方法和手段,因此具有重要的现实意义。
3 国家电网用户画像
随着电力体制改革向纵深推进,售电侧逐步向社会资本放开,当下的粗放式经营和统一式客户服务内容及模式,难以应对日益增长的个性化、精准化客户服务体验要求。如何充分利用现有数据资源,深入挖掘客户潜在需求,改善供电服务质量,增强客户黏性,对公司未来发展至关重要。
对电力服务具有较强敏感度的客户对于电费计量、供电质量、电力营销等各方面服务的质量及方式上往往具备更高的要求,成为各级电力公司关注的重点客户。经过多年的发展与沉淀,目前国家电网积累了全网4亿多客户档案数据和海量供电服务信息,以及公司营销、电网生产等数据,可以有效的支撑海量电力数据分析。
因此,国家电网公司希望通过大数据分析技术,科学的开展电力敏感客户分析,以准确地识别敏感客户,并量化敏感程度,进而支撑有针对性的精细化客户服务策略,控制电力服务人工成本、提升企业公众形象。
4 非人恶意流量识别
2016年第一季度Facebook发文称,其Atlas DSP平台半年的流量质量测试结果显示,由机器人模拟和黑IP等手段导致的非人恶意流量高达75% . 仅2016上半年,AdMaster反作弊解决方案认定平均每天能有高达 28% 的作弊流量。低质量虚假流量的问题一直存在,这也是过去十年间数字营销行业一直在博弈的问题。基于AdMaster海量监测数据,50%以上的项目均存在作弊嫌疑;不同项目中,作弊流量占广告投放5%到95%不等;其中垂直类和网盟类媒体的作弊流量占比最高;PC端作弊流量比例显著高于移动端和智能电视平台。广告监测行为数据被越来越多地用于建模和做决策,例如绘制用户画像,跨设备识别对应用户等。作弊行为,恶意曝光,网络爬虫,误导点击,甚至是在用户完全无感知的情况下被控制访问等产生的不由用户主观发出的行为给数据带来了巨大的噪声,给模型训练造成了很大影响。
希望基于给定的数据,建立一个模型来识别和标记作弊流量,去除数据的噪声,从而更好的使用数据,使得广告主的利益最大化。
5 求职信息完善
有大约10万分优质简历,其中部分简历包含完整的字段,部分简历在学历、公司规模、薪水、职位名称等字段有些置空项。希望对数据进行学习、编码与测试,挖掘出职位路径的走向与规律,形成算法模型,再对数据中置空的信息进行预测。
6 搜索引擎查询聚类以进行流量推荐
在搜索引擎中, 很多网民的查询意图的比较类似的,对这些查询进行聚类,一方面可以使用类内部的词进行关键词推荐;另一方面, 如果聚类过程实现自动化,则也有助于新话题的发现;同时还有助于减少存储空间等。
7 生物种群固有结构认知
对动植物分类和对基因进行分类,获取对种群固有结构的认识。
8 保险投保者分组
通过一个高的平均消费来鉴定汽车保险单持有者的分组,同时根据住宅类型,价值,地理位置来鉴定一个城市的房产分组。
9 网站关键词来源聚类整和
以领域特征明显的词和短语作为聚类对象,在分类系统的大规模层级分类语料库中,利用文本分类的特征提取算法进行词语的领域聚类,通过控制词语频率的影响,分别获取领域通用词和领域专类词。
10 图像分割
图像分割广泛应用于医学、交通、军事等领域。图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析的关键步骤。聚类算法先将图像空间中的像素用对应的特征空间点表示,根据它们在特征空间的聚集对特征空间进行分割,然后将它们映射回原图像空间,得到分割结果。

大数据
2018-12-24 13:46:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1 机场客流量分布预测
为了有效利用机场资源,机场正利用大数据技术,提升生产运营的效率。机场内需要不断提升运行效率的资源有航站楼内的各类灯光电梯设施设备、值机柜台、商铺、广告位、安检通道、登机口,航站楼外的停机位、廊桥、车辆(摆渡车、清洁车、物流车、能源车),要想提升这些资源的利用率首先需要知道未来一段时间将会有多少旅客或航班会使用这些资源,其次需要精准的调度系统来调配这些资源和安排服务人员,帮助机场提升资源利用效率,保障机场安全与服务提升。
以海量机场WiFi数据及安检登机值机数据,希望通过数据算法实现机场航站楼客流分析与预测。
2 音乐流行趋势预测
经过7年的发展与沉淀,目前某音乐平台拥有数百万的曲库资源,每天千万的用户活跃在平台上,拥有数亿人次的用户试听、收藏等行为。在原创艺人和作品方面,更是拥有数万的独立音乐人,每月上传上万个原创作品,形成超过几十万首曲目的原创作品库,如此庞大的数据资源库对于音乐流行趋势的把握有着极为重要的指引作用。
以某音乐平台用户的历史播放数据为基础,期望通过对艺人的试听量的预测,挖掘出即将成为潮流的艺人,从而实现对一个时间段内音乐流行趋势的准确把控。
3 需求预测与仓储规划方案
拥有海量的买家和卖家交易数据的情况下,利用数据挖掘技术,我们能对未来的商品需求量进行准确地预测,从而帮助商家自动化很多供应链过程中的决策。这些以大数据驱动的供应链能够帮助商家大幅降低运营成本,更精确的需求预测,能够大大地优化运营成本,降低收货时效,提升整个社会的供应链物流效率,朝智能化的供应链平台方向更加迈进一步。高质量的商品需求预测是供应链管理的基础和核心功能。
以历史一年海量买家和卖家的数据为依据,希望预测某商品在未来二周全国和区域性需求量。用数据挖掘技术和方法精准刻画商品需求的变动规律,对未来的全国和区域性需求量进行预测,同时考虑到未来的不确定性对物流成本的影响,做到全局的最优化。
4 新浪微博互动量预测
新浪微博作为中国最大的社交媒体平台,旨在帮助用户发布的公开内容提供快速传播互动的通道,提升内容和用户的影响力。希望能够最快找到有价值微博的方法,然后应用于平台的内容分发控制策略,对于有价值的内容可以增加曝光量,提高内容的传播互动量。对于一条原创博文而言,转发、评论、赞等互动行为能够体现出用户对于博文内容的兴趣程度,也是对博文进行分发控制的重要参考指标。
希望根据抽样用户的原创博文在发表一天后的转发、评论、赞总数,建立博文的互动模型,并预测用户后续博文在发表一天后的互动情况。
5 货币基金资金流入流出预测
某金融服务机构拥有大量会员并且业务场景中每天都涉及大量的资金流入和流出,面对如此庞大的用户群,资金管理压力会非常大。在既保证资金流动性风险最小,又满足日常业务运转的情况下,精准地预测资金的流入流出情况变得尤为重要。
期望能够通过用户基本信息数据、用户申购赎回数据、收益率表和银行间拆借利率等信息,对用户的申购赎回数据的把握,精准预测未来每日的资金流入流出情况。
6 电影票房预测
中国是全球第二大电影市场,同时也是增长最快的市场之一;随着市场的成熟,影响电影票房的因素也越来越多,包括题材、内容、导演、演员、编辑、发行方等等。因此对电影制作公司而言,依靠主观经验制作一部高票房的电影也越来越困难,而随着大数据技术的发展,借助大数据分析对电影市场进行分析,指导电影制作成为可能。
希望依据历史票房数据、影评数据、舆情数据等互联网公众数据,对电影票房进行预测。
7 农产品价格预测分析
农产品价格受市场影响的程度特别大,特别是受农产品的供求关系影响较大,同时价格本身又受自然条件、社会和经济条件的影响,特别是国际市场的影响。从价格本身来看,受供求、季节等发生波动,受外界各种影响比较多,这就造成了价格预测的困难。但从长期看,农产品价格随着时间的推移仍然呈现一定规律性。价格预测是大数据的精华所在,通过大量的历史数据分析,预测未来的价格走势,为决策者提供更有力的数据支持。
希望通过分析价格历史数据,对要求预测的农产品接下来固定时间的价格进行预测。并尽可能多的使用与价格有影响的其他数据以提高预测的准确率。
8 基于多源数据的青藏高原湖泊面积预测
全球气候变化对青藏高原的湖泊水储量有很大影响,因此精确的估计青藏高原湖泊面积变化对于研究气候变化变得很重要。海量多源异构数据和大数据处理与挖掘技术给湖泊面积变化研究带来新的解决思路;如何通过多源数据对青藏高原的湖泊面积进行预测,将大数据技术应用到全球气候变化研究中来成为一项新的挑战。
希望通过研究青藏高原湖泊面积变化的多种影响因素,构建青藏高原湖泊面积预测模型。
9 微博传播规模和传播深度预测
近些年,一些研究表明,一条微博发出以后,只需要观察其在之后一小段时间内的转发情况,它的传播规模便可以被预测。但是不同类型的微博会有不同的传播方式,比如明星晒一张生活状态就能得到众多粉丝的热捧,具有较大的传播广度,但是往往在传播深度上稍显不足;相比之下,一些被广泛讨论的新闻类微博往往具有较深的传播深度。也有统计结果显示,一些谣言往往会得到大规模的传播,辟谣类的消息反而得不到广泛关注。不仅如此,我们在热门微博中能看到不少正能量的信息,同时也能看到一些话题被持正反两种不同意见的人掀起讨论热潮。简而言之,微博初期的传播速度、用户关系、信息类型、内容情感等特征都是影响微博传播规模和深度的重要影响因素。
希望基于大约1-3万条微博及其它们的转发微博,结合微博用户的关注关系、微博的内容类型和情感分析以及初期的传播模式,来预测微博的传播规模和传播深度。
10 鲍鱼年龄预测
鲍鱼,在现代汉语中有多种含义。最常用的是指一种原始的海洋贝类,属于单壳软体动物,其只有半面外壳,壳坚厚、扁而宽,鲍鱼是中国传统的名贵食材,位居四大海味之首。直至现今,在人民大会堂举行的多次国宴及大型宴会中,鲍鱼经常榜上有名,成为中国经典国宴菜之一。被人们称为“海洋的耳朵”。和古代“用盐腌制的鱼”是两种东西。鲍鱼的优劣与年龄相关。一般来说,我们可以数鲍鱼的生长纹来确定鲍鱼的年龄,但数生长纹也是一件挺麻烦的事情。
希望利用与鲍鱼年龄有关的因素来预测鲍鱼的年龄。
11 学生成绩排名预测
学生的校园行为数据,可以挖掘用户作息规律、兴趣爱好等,精准地预测学生之间的相对排名。通过对这些日常行为的建模来预测学生的学业成绩,可以实现提前预警学生的异常情况,并进行适当的干预,因而对学生的培养、管理工作将会起到极其重要的作用。从某高校的某个学院随机抽取一定比例学生,提供这些学生在三个学期的图书馆进出记录、一卡通消费记录、图书馆借阅记录、以及综合成绩的相对排名。这一部分数据将作为训练数据。我们从另外的某学院随机抽取一定比例的学生,然后提供他们在三个学期的图书馆进出记录、一卡通消费记录、图书借阅记录、以及前两个学期的成绩排名。
希望通过借助大数据相关的挖掘技术和基础算法,预测第三学期的成绩排名。
12 网约车出行流量预测
在出行问题上,中国市场人数多、人口密度大,总体的出行频率远高于其他国家,这种情况在大城市尤为明显。然而,截止目前中国拥有汽车的人口只有不到10%,这也意味着在中国人们的出行更加依赖于出租车、公共交通等市场提供的服务。另一方面,滴滴出行占领了国内绝大部分的网络呼叫出行市场,面对着巨大的数据量以及与日俱增的数据处理需求。截止目前,滴滴出行平台每日需处理1100万订单,需要分析的数据量达到50TB,路径规划服务请求超过90亿。面对如此庞杂的数据,我们需要通过不断升级、完善与创新背后的云计算与大数据技术,从而保证数据分析及相关应用的稳定,实现高频出行下的运力均衡。供需预测就是其中的一个关键问题。供需预测的目标是准确预测出给定地理区域在未来某个时间段的出行需求量及需求满足量。调研发现,同一地区不同时间段的订单密度是不一样的,例如大型居住区在早高峰时段的出行需求比较旺盛,而商务区则在晚高峰时段的出行需求比较旺盛。
希望能预测到在未来的一段时间内某些地区的出行需求量比较大,以提前对营运车辆提供一些引导,指向性地提高部分地区的运力,从而提升乘客的整体出行体验。
13 红酒品质评分
红酒口感的好坏,受很多因素的影响,例如年份、产地、气候、酿造的工艺等等。通过一些化学属性特征就能够很好地判断红酒的品质。通过监测红酒中化学成分的含量,可以控制红酒的品质和口感。
希望基于红酒的化学特性,例如酸性、含糖量、氯化物含量、硫含量、酒精度、PH值、密度等,构建机器学习模型,对红酒品质进行评分。
14搜索引擎的搜索量和股价波动
上市公司在互联网中搜索量的变化,会显著影响公司股价的波动和趋势,即所谓的投资者注意力理论。该理论认为,公司在搜索引擎中的搜索量,代表了该股票被投资者关注的程度。因此,当一只股票的搜索频数增加时,说明投资者对该股票的关注度提升,从而使得该股票更容易被个人投资者购买,进一步地导致股票价格上升,带来正向的股票收益。
15 中国人口增长分析
中国从1971年开始全面开展了计划生育,使中国总和生育率很快从1970年的5.8降到1980年2.24,接近世代更替水平。此后,人口自然增长率很大程度上与经济的发展等各方面的因素相联系,与经济生活息息相关。影响中国人口自然增长率的因素有很多,如经济整体增长、居民消费水平、文化程度、人口分布,以及非农业与农业人口的比率等。
希望通过历史数据分析,对未来人口增长率进行预测。
16 农村居民收入增长预测
“三农”问题的核心是农村居民收入问题。改革开放以来,农村经济蓬勃发展,农村居民收入有了较大幅度的增长,但与城镇居民的收入相比,却表现出增长缓慢、差距越来越大的趋势。
希望对影响我国农村居民收入的因素进行分析,再运用实证方法对农民的经济统计数据进行分析,得到了影响农村居民纯收入的模型。为预测农村居民的收入增长趋势提供工具,为农村地区的政策措施提供参考建议。
17 房地产销售影响因素分析
改革开放以来,我国的经济突飞猛进对城市商品房的价格产生了巨大影响,特别是进入21世纪后,伴随着商品房价格日益增长,出现了房地产投资过热。在这种房价居高不下的形势下,国内外诸多专家学者认为我国的房地产市场已经出现价格泡沫,在房地产业对我国国民经济发展起着积极作用的大环境下,这种价格泡沫势必会对我国的经济发展造成重大影响。
年人均收入、新增住房面积及上一年商品房价格等因素对房地产销售有影响,期望利用历史数据分析测度其对商品房价格的影响,找出了引起房地产价格波动的主要因素当年年人均收入,根据实证结论提出了控制房价的建议。
18 股价走势预测
随着经济社会的发展,以及人们投资意识的增强,人们越来越多的参与到股票市场的经济活动中,股票投资也已经成为人们生活的一个重要组成部分。然而在股票市场中,众多的指标、众多的信息,很难找出对股价更为关键的因素;其次股市结构极为复杂,影响因素具有多样性、相关性。这导致了很难找出股市内在的模式。
希望在尽可能全面的收集股市信息的基础上,建立股价预测模。
19 全国综合运输总量预测
以全国同期国民经济主要产品产量,如原煤、原油、生铁、钢材、水泥、木材、粮食的历史数据,建立数据挖掘模型,对全国综合运输总运量进行预测。
20 地震预报
根据历史全球大地震的时空图,找出与中国大陆大地震有关的14个相关区,对这些相关区逐一鉴别,选取较优的9个,再根据这9个相关区发生的大震来预测中国大陆在未来一年内会不会有大震发生。

大数据
2018-12-24 13:40:05
「深度学习福利」大神带你进阶工程师,立即查看>>>
​ 小蚂蚁说:
2018中国软件和信息服务领域十大领军企业、人物及产业园区评选活动是业界最权威和最受关注的评选之一。12月20日,在北京举行的“2018中国软件大会”正式宣布蚂蚁金服成为“2018中国大数据金融领军企业”。
蚂蚁金服运营专家吴锴领取“中国金融大数据领军企业”奖牌
2018年12月20日,在北京举行的“2018中国软件大会”正式宣布,蚂蚁金服在2018中国软件和信息服务领域十大领军企业、人物及产业园区评选活动中脱颖而出,成为“2018中国大数据金融领军企业”。
据悉,中国软件和信息服务领域十大领军企业、人物及产业园区评选始于2001年,已经有十七年的历史,是业界最权威和最受关注的评选之一,被誉为中国软件和信息服务领域的“奥斯卡”。
蚂蚁大数据助力企业业务创新
据介绍,蚂蚁金服一站式大数据应用架构属于数据智能产品体系,是经过自身业务场景验证和锤炼的大数据应用解决方案,为企业提供企业数仓、商业智能、机器学习、数据可视化、数据营销、数据风控等一站式应用服务,能够有效提升客户洞察力,助力企业业务创新。
近年来,蚂蚁大数据已经与多个知名的金融机构,如银行、保险和证券等企业开展合作。贵阳银行就引进了蚂蚁金服大数据技术平台和实施服务,整合内外部数据,建设五大数据能力,推进大数据特色银行建设,支撑零售条线的精准营销和风险防控业务。在蚂蚁大数据能力的支持下,贵阳银行产品创新能力不断提升,通过不断丰富信用卡、理财投资、消费贷款等领域的产品体系,持续提升线上化产品覆盖率。
针对银行、保险、基金、证券等行业的特性,蚂蚁大数据提供了行业专属的一站式解决方案,并提供个性化的服务。以网商银行为例,基于蚂蚁金服大数据解决方案,网商银行建立了一套面向业务人员的新一代大数据自助智能分析平台,实现从数据获取、数据探索分析、报表定义开发到信息发布共享的全流程管理,提成了全行业数据应用分析能力。
通过与蚂蚁大数据的深度合作,多家金融企业依托多渠道、场景化提升获客规模,基于大数据分析能力,将差异化定价与特色分期产品相结合,深化零售客户差异化服务内涵,实现线上银客互动与线下商圈打造相结合,持续完善金融消费生态圈,提升零售客户粘性。
蚂蚁大数据能力全面开放
秉承蚂蚁金服的技术开放战略,蚂蚁金服大数据平台已经全面开放给外部的企业、商户、ISV等合作伙伴。蚂蚁大数据不仅提供全套产品平台,也提供行业级的解决方案,并辅助定制化的服务,保证方案的最终落地。
蚂蚁大数据将构建开发者生态,把技术开放作为重点,开放开发集成能力,让数据洞察分析平台能够与客户的CRM系统、行为系统等进行快速的集成,同时保障权限的管控;开放可视化的组件API、SDK等接口,让合作伙伴在大数据洞察分析平台上直接开发可视化组件。
蚂蚁大数据希望能够携手更多的金融行业伙伴,并提供数字化转型的解决方案,共同打造安全、美好的数字金融生态,为人们提供平等普惠的金融服务。
原文链接
大数据
2018-12-24 13:23:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
阿里云CDN实时日志服务可以将CDN采集的日志,秒级的交付给用户, 并且可以对采集到的日志进行实时、交互式分析和报表呈现,为监控、报警、渠道分析、运营分析提供实时、可靠的数据参考,让用户远离锁事,专注数据价值。
12月26日,阿里云CDN实时日志服务举办线上直播发布会,全网首次深度解读阿里云CDN大数据系统技术演进、产品特性、应用场景与业务实操。
CDN实时日志源起何处?
阿里云CDN从2014年正式商业化至今,服务了百万域名,每天处理数PB的数据,并应对亿级并发的洪峰流量,实现最低秒级延迟,并且提供100%的高数据准确性服务。伴随系统规模发展,CDN产生的日志数据量也越来越庞大,同时CDN业务场景下的原始数据分布广泛、处理环节复杂、使用场景繁多等等现状也给阿里云大数据系统带来了不小的挑战。
另一方面,阿里云CDN服务了全球三十多万客户,在与客户沟通中,通常会面临这样的问题:
1. 用户无数据源
绝大部分的CDN产商都只提供离线日志下载,日志数据从产生,到用户可下载,需要几十分钟到数个小时不等。这样大的数据产生延时,大大削减了高实时性要求场景的数据分析价值,无法驱动运营调整策略
2. 无法进行实时监控报警
无法实时把握CDN服务性能,对线上问题排查的不及时,遇到问题的灾备方案对客户端有感,进而无法实现更自动化、智能化的运维,不能提前发现业务瓶颈,进一步提升CDN的服务质量
3. 数据分析及可视化的开发、运维成本高昂
为了解决各类定制化的数据分析需求,用户通常需要自建数据仓库, 自建流式和离线分析平台, 数据可视化平台。投入大量建设资金的同时, 还需要投入大量的研发和运维人力
4. 自建系统技术挑战大
整个数据平台的数据来源广泛,数据处理方式复杂,随着业务的快速发展, 对系统稳定性、数据实时性、数据准确性、全球化服务能力也不断提出严苛的要求。使用开源软件对企业的技术挑战很大, 在性能、成本、定制化、稳定性也未必能跟上业务要求。
综上所述,更通用、实时、准确的日志获取, 分析和可视化的需求逐渐凸显,阿里云CDN大数据系统在这个背景之下走上了技术演进之路。
阿里云CDN大数据系统架构演进
起初,阿里云CDN大数据业务架构完全基于开源软件搭建,但是随着业务系统越来越大,我们发现在开源方案中解决问题的成本也越来越高,考虑到成本和后续服务的及时性、稳定性、定制化等因素,逐渐将开源方案以集团内部自研方案来替换。
比如,Scroll这个协议就是自研的一套日志数据编解码方案;Crimea是在节点上进行数据基础的采集、降维分析以及数据持久化的自研应用;Blink是阿里集团的流式计算平台; MaxCompute是阿里云对外售卖的通用离线分析平台。
阿里云高级技术专家姜晓东表示:“整个CDN的业务逐渐复杂,对业务的稳定性要求也更高,数据是稳定性的基础条件,网络条件再好,硬件条件再好,缺少数据决策的能力,也不可能做到非常高服务能力。我们可以预测到阿里云CDN系统会有PB/EB级别的规模数据增长,同时我们对于数据的完整性、可用性、全球化部署等指标都有比较高的追求,所以我们逐渐演进、集成沉淀了现有的大数据解决方案。”
如今的架构在CDN节点上实现了数据采集和第一步数据降维分析,延迟低,稳定性高;所有数据传输通过阿里云SLS和OSS来完成,通过SLS遍布全球的接入点实现秒级可见,对于批量或者文件处理,通过节点把数据写入OSS,再进行读取和分析;在数据分析这层,采用了阿里集团的MaxCompute和Blink的方案,实现离线大规模数据分析和在线流式分析。同时,SLS也使用了CDN的动态加速能力,提高在海外和弱网情况下的数据投递成功率。
该技术架构具有以下两个技术优势:
一、在数据采集阶段, 自研了Scroll+Crimea应用 ,具备优秀的计算和容灾能力,运用内容自解释、高效编码、边缘预处理与降维分析、自动容灾处理、任务隔离等方案,确保了数据完整性、实时性和准确性。
二、 基于SLS实现全球多部署点写入 ,无缝对接存储和分析平台,达到秒级延迟,支持单次10亿级别的分析,并且无需付出代码和运维成本,能够 实现快速、稳定、低成本、高容量的传输和分析 。
用数据价值赋能用户 CDN实时日志服务诞生
CDN实时日志服务基于阿里云CDN大数据系统解决方案,将日志的实时采集、多维分析、可视化运营、监控与报警打通,形成一站式解决方案,整个系统中复杂的事情都交给阿里云来做,让用户尽可能地可以远离“琐事”,更专注挖掘数据价值,专注在业务本身。
它具有以下五大优势:
一、延时不超过60秒
CDN实时日志可以从全球多个区域、数万节点实时采集日志,通常延时不超过60秒,否则日志的实时价值大打折扣。同时,在开通服务后,CDN将日志数据自动投递到日志服务(SLS),免去繁琐的传统日志分析的流程,实时查看日志分析结果。
二、平均节省60%成本
使用实时日志还可以大幅降低资源、人力运维、分析等成本,以某家大型公司为例,每天系统产生日志约100亿条,自建Hadoop+Es集群,集群规模1500+服务器,运维+研发10人左右,一年总成本大约需要5000多万。而使用实时日志,平均减少投入60%以上,运维只需要将精力集中在访问监控上,而运营将精力聚焦在业务分析上,更专注业务本身。
三、多维度SQL分析,秒级10亿+规模
CDN实时日志系统支持每天千亿、万亿的日志7*24小时不间断采集,并实时对海量日志进行多维度分析,流计算系统在毫秒级。让用户更加专注于和业务更紧密、更有价值的数据“分析”上。
四、数据可视化及大数据挖掘
最终分析结果的展示也非常关键,CDN实时日志可以为用户提供基于业务的可视化报表服务,用户可轻松地掌控业务健康度、缓存命中率、平均下载速度、流量情况、网速、运营商、延时分布等数据。
五、日志、监控、告警联动的一站式解决方案
在CDN场景下,对服务的可用性、性能要求苛刻,需要对于各类异常进行实时、准确的报警,这就需要依赖可靠的监控报警系统。CDN日志系统未来将和监控、告警、处理机制联动,自动化的解决常规问题,缩短业务故障的时间,避免用户损失。
CDN实时日志典型应用场景
适用场景一:直播
在直播场景下,用户访问集中,数据时效性非常强,对系统的稳定性要求又极其高,通过CDN实时日志可以获取秒级推流状态,并通过日志分析自定义报表,快速进行访问监控和错误追踪。
• 推流概览 : 实时知道当前的推流数量、各个推流的流量和速度、从各省、运营商维度统计
• 推流质量:多维度的推流质量统计、重点推流的实时质量监控
• 错误根源追踪:快速定位错误产生的源头(直播源、服务端、客户端、运营商等)
比如,虎牙直播就采用了CDN的实时日志服务,将访问节点的日志实时获取后对日志进行分析,对可能的用户运行风险进行及时预警,实现故障自愈和问题定位,同时实时评价CDN节点健康度,主动发现影响客户体验因素,屏蔽质量较差的节点和线路。
适用场景二:大型活动或突发事件监控
在类似双12双11的大型营销活动中,网站的访问突然激增,通过CDN实时日志可以快速搭建当前节点一系列数据报表,判断节点和运营商的访问质量,保证终端用户访问顺畅。在此基础上,运营可以通过用户分布、终端分布和版本分布,优化资源投放以及实时调整策略,真正实现数据驱动决策。
• 整体质量:
健康度 : 在所有的访问中,有多少请求是成功的
Cache命中率 : 命中率越高,用户访问延时越低,体验越好
下载速度 : 这也是关系到播放质量的重要因素
• 多维度分析:
top域名访问次数、流量 : 重点域名的访问质量
地域、运营商统计:各个链路的质量
下载量、速度、延时:多项关键指标
• 错误诊断:
实时错误QPS、比例 : 整体错误情况
错误Top 域名、URI : 错误是否和自身相关
错误Top 地域、运营商 : 错误是否和外部因素相关
错误客户端分别 : 是否是新发布版本引入的问题
除了以上两个典型场景,CDN实时日志还可以应用在游戏直播监控或报警、在线教育直播监控或报警、网站大型推广或内容投放效果分析,网站促销活动监控或效果分析,内容运营效果分析等场景之下。适用不仅限于游戏、电商、教育、体育赛事、机酒订购等行业。
CDN实时日志接入与实操指南
点击链接跳转服务详细文档与开通指南
开通仅需三步:
一、打开CDN控制台,点击日志-实时日志推送,点击开通日志服务,按照指引步骤操作。
二、单击创建实时日志推送服务,配置Project、Logstore、地区等信息,然后单击下一步。
三、选择关联域名并绑定,然后单击创建。
开通完毕,如何查看报表,进行日志分析?
CDN默认帮用户创建了4张报表,分别是CDN基础数据、错误分析、热门资源和用户分析,用户可以通过这四张报表可以快速的去查看CDN的质量和分布数据。

同时,用户也可以通过日志分析进行定制化的查询,查询完成后,可以将查询内容保存到现有的报表,或者是新建一份报表。另外,也可以将报表的任意统计项或者当前查询项保存为报警项,及时的发现和定位问题。
实操演示:
发布会直播的最后,CDN高级产品经理容蓓带着用户实操演练了整个开通和操作的流程, 点击回顾视频版,上手更轻松: https://yq.aliyun.com/live/699
此前,阿里云CDN实时日志系统经过了长期演进,已经成功运用在世界杯、双11等阿里集团大型活动之中,为活动提供实时、可靠、全面详实的数据监控系统。在当今大数据时代,阿里云会将同款能力开放赋能给行业用户,挖掘数据的无限价值,让业务决策快人一步。
原文链接
大数据
2018-12-27 12:08:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Logstash
Logstash是一个开源数据收集引擎,具有实时管道功能。Logstash可以动态地将来自不同数据源的数据统一起来,并将数据标准化到你所选择的目的地。
集中、转换和存储你的数据
Logstash是一个开源的服务器端数据处理管道,可以同时从多个数据源获取数据,并对其进行转换,然后将其发送到你最喜欢的“存储”。(当然,我们最喜欢的是Elasticsearch)
INPUTS (输入插件): 采集各种格式、大小和来源的数据
数据往往以各种各样的形式,或分散或集中地存在于很多系统中。Logstash 支持各种输入选择 ,可以在同一时间从众多常用来源捕捉事件。能够以连续的流式传输方式,轻松地从您的日志、指标、Web 应用、数据存储以及各种 AWS 服务采集数据。

FILTERS (过滤器插件):实时解析和转换数据
数据从源传输到存储库的过程中,Logstash 过滤器能够解析各个事件,识别已命名的字段以构建结构,并将它们转换成通用格式,以便更轻松、更快速地分析和实现商业价值。
Logstash 能够动态地转换和解析数据,不受格式或复杂度的影响: 利用 Grok 从非结构化数据中派生出结构 从 IP 地址破译出地理坐标 将 PII 数据匿名化,完全排除敏感字段 整体处理不受数据源、格式或架构的影响
我们丰富的过滤库给数据过滤提供了无限的可能性。
OUTPUTS(输出插件):选择你的存储,导出你的数据
尽管 Elasticsearch 是我们的首选输出方向,能够为我们的搜索和分析带来无限可能,但它并非唯一选择。Logstash 提供众多输出选择,您可以将数据发送到您要指定的地方,并且能够灵活地解锁众多下游用例。

安装Logstach
1、安装JDK
Logstach 是基于Java开发是一个Java程序,运行在Jvm中,所以第一步要安装JDK。 yum install -y java-1.8.0-openjdk-devel
2、下载Logstach
https://www.elastic.co/cn/downloads/logstash ,是Logstach的官方站点,如果需要下载最新的版本,进入官网下载即可。可以下载到本地电脑然后再导入CentOS中,也可以直接在CentOS中下载。 wget https://artifacts.elastic.co/downloads/logstash/logstash-6.5.4.rpm
2、安装Logstach # 执行安装命令 rpm -ivh logstash-6.5.4.rpm warning: logstash-6.5.4.rpm: Header V4 RSA/SHA512 Signature, key ID d88e42b4: NOKEY Preparing... ########################################### [100%] 1:logstash ########################################### [100%] Using provided startup.options file: /etc/logstash/startup.options Successfully created system startup script for Logstash # 查看下logstash的安装目录 rpm -ql logstash # 创建一个软连接,每次执行命令的时候不用在写安装路劲(默认安装在/usr/share下) ln -s /usr/share/logstash/bin/logstash /bin/
好,马上开始我们的第一个例子:
首先,让我们通过最基本的Logstash管道来测试一下刚才安装的Logstash。Logstash管道有两个必需的元素,输入和输出,以及一个可选元素过滤器。输入插件从数据源那里消费数据,过滤器插件根据你的期望修改数据,输出插件将数据写入目的地。

接下来我们输入最基本的管道,例如: # 执行logstash的命令 logstash -e 'input { stdin { } } output { stdout {} }' # -e是允许命令行指定配置 # 运行成功以后输入: hello world
然后启动后,输入hello world
# 注: # -e 执行操作 # input 标准输入 # { input } 插件 # output 标准输出 # { stdout } 插件 # # 通过rubydebug来输出下更详细的信息 logstash -e 'input { stdin { } } output { stdout {codec => rubydebug} }' # 执行成功输入: 爱上一匹野马,可我家里没有草原 # stdout输出的结果:
# 如果标准输出还有Elasticsearch中都需要保留应该怎么玩,看下面 logstash -e 'input { stdin { } } output { elasticsearch { hosts => ["192.168.1.111:9200"] } stdout { codec => rubydebug }}' # 运行成功以后输入: 爱上一匹野马,可我的家里没有草原 # 返回的结果(标准输出中的结果):

参考资料 https://www.elastic.co/guide/en/logstash/current/index.html 官网文档
大数据
2018-12-27 11:02:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
进入hbase shell console
$HBASE_HOME/bin/hbase shell
如果有kerberos认证,需要事先使用相应的keytab进行一下认证(使用kinit命令),认证成功之后再使用hbase shell进入可以使用whoami命令可查看当前用户
hbase(main)> whoami
表的管理
1)查看有哪些表
hbase(main)> list
2)创建表
# 语法:create , {NAME => , VERSIONS => }
# 例如:创建表t1,有两个family name:f1,f2,且版本数均为2
hbase(main)> create 't1',{NAME => 'f1', VERSIONS => 2},{NAME => 'f2', VERSIONS => 2}
3)删除表
分两步:首先disable,然后drop
例如:删除表t1
hbase(main)> disable 't1'
hbase(main)> drop 't1'
4)查看表的结构
# 语法:describe

# 例如:查看表t1的结构
hbase(main)> describe 't1'
5)修改表结构
修改表结构必须先disable
# 语法:alter 't1', {NAME => 'f1'}, {NAME => 'f2', METHOD => 'delete'}
# 例如:修改表test1的cf的TTL为180天
hbase(main)> disable 'test1'
hbase(main)> alter 'test1',{NAME=>'body',TTL=>'15552000'},{NAME=>'meta', TTL=>'15552000'}
hbase(main)> enable 'test1'
权限管理
1)分配权限
# 语法 : grant
参数后面用逗号分隔
# 权限用五个字母表示: "RWXCA".
# READ('R'), WRITE('W'), EXEC('X'), CREATE('C'), ADMIN('A')
# 例如,给用户‘test'分配对表t1有读写的权限,
hbase(main)> grant 'test','RW','t1'
2)查看权限
# 语法:user_permission

# 例如,查看表t1的权限列表
hbase(main)> user_permission 't1'
3)收回权限
# 与分配权限类似,语法:revoke

# 例如,收回test用户在表t1上的权限
hbase(main)> revoke 'test','t1'
表数据的增删改查
1)添加数据
# 语法:put
,,,,
# 例如:给表t1的添加一行记录:rowkey是rowkey001,family name:f1,column name:col1,value:value01,timestamp:系统默认
hbase(main)> put 't1','rowkey001','f1:col1','value01'
用法比较单一。
2)查询数据
a)查询某行记录
# 语法:get
,,[,....]
# 例如:查询表t1,rowkey001中的f1下的col1的值
hbase(main)> get 't1','rowkey001', 'f1:col1'
# 或者:
hbase(main)> get 't1','rowkey001', {COLUMN=>'f1:col1'}
# 查询表t1,rowke002中的f1下的所有列值
hbase(main)> get 't1','rowkey001'
b)扫描表
# 语法:scan
, {COLUMNS => [ ,.... ], LIMIT => num}
# 另外,还可以添加STARTROW、TIMERANGE和FITLER等高级功能
# 例如:扫描表t1的前5条数据
hbase(main)> scan 't1',{LIMIT=>5}
c)查询表中的数据行数
# 语法:count
, {INTERVAL => intervalNum, CACHE => cacheNum}
# INTERVAL设置多少行显示一次及对应的rowkey,默认1000;CACHE每次去取的缓存区大小,默认是10,调整该参数可提高查询速度
# 例如,查询表t1中的行数,每100条显示一次,缓存区为500
hbase(main)> count 't1', {INTERVAL => 100, CACHE => 500}
3)删除数据
a )删除行中的某个列值
# 语法:delete
, , , ,必须指定列名
# 例如:删除表t1,rowkey001中的f1:col1的数据
hbase(main)> delete 't1','rowkey001','f1:col1'
注:将删除改行f1:col1列所有版本的数据
b )删除行
# 语法:deleteall
, , , ,可以不指定列名,删除整行数据
# 例如:删除表t1,rowk001的数据
hbase(main)> deleteall 't1','rowkey001'
c)删除表中的所有数据
# 语法: truncate

# 其具体过程是:disable table -> drop table -> create table
# 例如:删除表t1的所有数据
hbase(main)> truncate 't1'
Region管理
1)移动region
# 语法:move 'encodeRegionName', 'ServerName'
# encodeRegionName指的regioName后面的编码,ServerName指的是master-status的Region Servers列表
# 示例
hbase(main)>move '4343995a58be8e5bbc739af1e91cd72d', 'db-41.xxx.xxx.org,60020,1390274516739'
2)开启/关闭region
# 语法:balance_switch true|false
hbase(main)> balance_switch
3)手动split
# 语法:split 'regionName', 'splitKey'
4)手动触发major compaction
#语法:
#Compact all regions in a table:
#hbase> major_compact 't1'
#Compact an entire region:
#hbase> major_compact 'r1'
#Compact a single column family within a region:
#hbase> major_compact 'r1', 'c1'
#Compact a single column family within a table:
#hbase> major_compact 't1', 'c1'
配置管理及节点重启
1)修改hdfs配置
hdfs配置位置:/etc/hadoop/conf
# 同步hdfs配置
cat /home/hadoop/slaves|xargs -i -t scp /etc/hadoop/conf/hdfs-site.xml hadoop@{}:/etc/hadoop/conf/hdfs-site.xml
#关闭:
cat /home/hadoop/slaves|xargs -i -t ssh hadoop@{} "sudo /home/hadoop/cdh4/hadoop-2.0.0-cdh4.2.1/sbin/hadoop-daemon.sh --config /etc/hadoop/conf stop datanode"
#启动:
cat /home/hadoop/slaves|xargs -i -t ssh hadoop@{} "sudo /home/hadoop/cdh4/hadoop-2.0.0-cdh4.2.1/sbin/hadoop-daemon.sh --config /etc/hadoop/conf start datanode"
2)修改hbase配置
hbase配置位置:
# 同步hbase配置
cat /home/hadoop/hbase/conf/regionservers|xargs -i -t scp /home/hadoop/hbase/conf/hbase-site.xml hadoop@{}:/home/hadoop/hbase/conf/hbase-site.xml

# graceful重启
cd ~/hbase
bin/graceful_stop.sh --restart --reload --debug inspurXXX.xxx.xxx.org
大数据
2018-12-26 21:42:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
当今现实世界的数据库极易受噪声、缺失值和不一致数据的侵扰,因为数据库太大并且多半来自多个异种数据源。低质量的数据将导致低质量的挖掘结果。
数据预处理技术。数据清理可以用来清除数据中的噪声,纠正不一致。数据集成将数据由多个数据源合并成一个一致的数据存储,如数据仓库。数据归约可以通过如聚集、删除冗余特征或聚类来降低数据的规模。数据变换可以用来把数据压缩到较小的区间,如0.0到1.0。这可以提高涉及距离度量的挖掘算法的准确率和效率。这些技术不是相互排斥的,可以一起使用。例如,数据清理可能涉及纠正错误数据的变换,如通过把一个数据字段的所有项都变换成公共格式进行数据清理。
数据质量:为什么要对数据预处理
数据如果能满足其应用要求,那么它是高质量的。数据质量涉及许多因素,包括准确性、完整性、一致性、时效性、可信性和可解释性,但现实中并非高质量数据,所以要进行预处理。
数据预处理的主要任务
本节我们考察数据预处理的主要步骤,即 数据清理、数据集成、数据归约和数据变换 。
数据清理(data cleaning)例通过填写缺失的值,光滑噪声数据,识别或删除离群点,并解决不一致性来“清理”数据。
数据集成(data integration)回到你在AllElectronics的任务,假定你想在分析中使用来自多个数据源的数据。这涉及集成多个 数据库 、数据立方体或文件,即数据集成。
数据归约(data reduction)随着更深入地考虑数据,你可能会问自己:“我为分析而选取的数据集是巨大的,这肯定会降低数据挖掘过程的速度。有什么办法能降低数据集的规模,而又不损害数据挖掘的结果吗?”数据归约得到数据集的简化表示,它小得多,但能够产生同样的(或几乎同样的)分析结果。数据归约策略包括维归约和数值归约。
数据变换(data transformation)规范化、数据离散化和概念分层产生都是某种形式的数据变换。你很快就会意识到,数据变换操作是引导挖掘过程成功的附加的预处理过程。

数据清理
现实世界的数据一般是不完整的、有噪声的和不一致的。数据清理例程试图填充缺失的值、光滑噪声并识别离群点、纠正数据中的不一致。
缺失值 元组(数据表)的一些属性(数据列)(如顾客的income)没有记录值。怎样才能为该属性填上缺失的值?我们看看下面的方法。 忽略元组:当缺少类标号时通常这样做(假定挖掘任务涉及分类)。 人工填写缺失值:一般来说,该方法很费时,并且当数据集很大、缺失很多值时,该方法可能行不通。 使用一个全局常量填充缺失值:将缺失的属性值用同一个常量(如“Unknown”或-∞)替换。如果缺失的值都用如“Unknown”替换,则挖掘程序可能误以为它们形成了一个有趣的概念,因为它们都具有相同的值——“Unknown”。因此,尽管该方法简单,但是并不十分可靠。 使用属性的中心度量(如均值或中位数)填充缺失值 使用最可能的值填充缺失值:可以用回归、使用贝叶斯形式化方法的基于推理的工具或决策树归纳确定。例如,利用数据集中其他顾客的属性,可以构造一棵决策树,来预测income的缺失值。
方法(3)~方法(6)使数据有偏,填入的值可能不正确。然而, 方法(6)是最流行的策略 。 与其他方法相比,它使用已有数据的大部分信息来预测缺失值。在估计income的缺失值时,通过考虑其他属性的值,有更大的机会保持income和其他属性之间的联系。
噪声数据
“什么是噪声?”噪声(noise)是被测量的变量的随机误差或方差。
随机误差 也称为偶然误差和不定误差,是由于在测定过程中一系列有关因素微小的随机波动而形成的具有相互抵偿性的误差。其产生的原因是分析过程中种种不稳定随机因素的影响,如室温、相对湿度和气压等环境条件的不稳定,分析人员操作的微小差异以及仪器的不稳定等。
方差 是在概率论和统计方差衡量随机变量或一组数据时离散程度的度量。概率论中方差用来度量随机变量和其数学期望(即均值)之间的偏离程度。统计中的方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数。 在许多实际问题中,研究方差即偏离程度有着重要意义。
我们看看下面的数据光滑技术。
分箱(binning):分箱方法通过考察数据的“近邻”(即周围的值)来光滑有序数据值。
回归(regression):也可以用一个函数拟合数据来光滑数据。这种技术称为回归。线性回归涉及找出拟合两个属性(或变量)的“最佳”直线,使得一个属性可以用来预测另一个。多元线性回归是线性回归的扩充,其中涉及的属性多于两个,并且数据拟合到一个多维曲面。
离群点分析(outlier analysis):可以通过如聚类来检测离群点。聚类将类似的值组织成群或“簇”。直观地,落在簇集合之外的值被视为离群点
数据清理过程的第一步是偏差检测(discrepancy detection)。导致偏差的因素可能有多种,包括具有很多可选字段的设计糟糕的输入表单、人为的数据输入错误、有意的错误(例如,不愿意泄露自己的信息),以及数据退化(例如,过时的地址)。偏差也可能源于不一致的数据表示和编码的不一致使用。
数据清理作为一个过程
数据清理过程的第一步是偏差检测(discrepancy detection)。导致偏差的因素可能有多种,包括具有很多可选字段的设计糟糕的输入表单、人为的数据输入错误、有意的错误(例如,不愿意泄露自己的信息),以及数据退化(例如,过时的地址)。偏差也可能源于不一致的数据表示和编码的不一致使用。
数据集成
数据挖掘经常需要数据集成——合并来自多个数据存储的数据。小心集成有助于减少结果数据集的冗余和不一致。这有助于提高其后挖掘过程的准确性和速度。
实体识别问题
数据分析任务多半涉及数据集成。数据集成将多个数据源中的数据合并,存放在一个一致的数据存储中,如存放在数据仓库中。这些数据源可能包括多个数据库、数据立方体或一般文件。
冗余和相关分析
冗余是数据集成的另一个重要问题。一个属性(例如,年收入)如果能由另一个或另一组属性“导出”,则这个属性可能是冗余的。属性或维命名的不一致也可能导致结果数据集中的冗余。
有些冗余可以被相关分析检测到。给定两个属性,这种分析可以根据可用的数据,度量一个属性能在多大程度上蕴涵另一个。对于标称数据,我们使用χ2(卡方)检验。对于数值属性,我们使用相关系数(correlation coefficient)和协方差(covariance),它们都评估一个属性的值如何随另一个变化。
冗余和相关分析
冗余是数据集成的另一个重要问题。一个属性(例如,年收入)如果能由另一个或另一组属性“导出”,则这个属性可能是冗余的。属性或维命名的不一致也可能导致结果数据集中的冗余。
有些冗余可以被相关分析检测到。给定两个属性,这种分析可以根据可用的数据,度量一个属性能在多大程度上蕴涵另一个。对于标称数据,我们使用χ2(卡方)检验。对于数值属性,我们使用相关系数(correlation coefficient)和协方差(covariance),它们都评估一个属性的值如何随另一个变化。
元组重复
除了检测属性间的冗余外,还应当在元组级检测重复(例如,对于给定的唯一数据实体,存在两个或多个相同的元组)。
数据归约
数据归约(data reduction)技术可以用来得到数据集的归约表示,它小得多,但仍接近于保持原始数据的完整性。也就是说,在归约后的数据集上挖掘将更有效,仍然产生相同(或几乎相同)的分析结果。本节,我们将概述数据归约的策略,然后进一步考察每种技术。
数据归约策略概述
数据归约策略包括维归约、数量归约和数据压缩。
维归约(dimensionality reduction)减少所考虑的随机变量或属性的个数。维归约方法包括小波变换和主成分分析
数量归约(numerosity reduction)用替代的、较小的数据表示形式替换原数据。这些技术可以是参数的或非参数的。
数据压缩(data compression)使用变换,以便得到原数据的归约或“压缩”表示。如果原数据能够从压缩后的数据重构,而不损失信息,则该数据归约称为无损的。
数据变换与数据离散化
数据变换策略概述
在数据变换中,数据被变换或统一成适合于挖掘的形式。数据变换策略包括如下几种:
(1)光滑(smoothing):去掉数据中的噪声。这类技术包括分箱、回归和聚类。
(2)属性构造(或特征构造):可以由给定的属性构造新的属性并添加到属性集中,以帮助挖掘过程。
(3)聚集:对数据进行汇总或聚集。例如,可以聚集日销售数据,计算月和年销售量。通常,这一步用来为多个抽象层的数据分析构造数据立方体。
(4)规范化:把属性数据按比例缩放,使之落入一个特定的小区间,如-1.0~1.0或0.0~1.0。
(5)离散化:数值属性(例如,年龄)的原始值用区间标签(例如,0~10,11~20等)或概念标签(例如,youth、adult、senior)替换。这些标签可以递归地组织成更高层概念,导致数值属性的概念分层。图3.12显示了属性price的一个概念分层。对于同一个属性可以定义多个概念分层,以适合不同用户的需要。
(6)由标称数据产生概念分层:属性,如street,可以泛化到较高的概念层,如city或country。许多标称属性的概念分层都蕴含在 数据库 的模式中,可以在模式定义级自动定义。
通过规范化变换数据
所用的度量单位可能影响数据分析。例如,把height的度量单位从米变成英寸,把weight的度量单位从公斤改成磅,可能导致完全不同的结果。一般而言,用较小的单位表示属性将导致该属性具有较大值域,因此趋向于使这样的属性具有较大的影响或较高的“权重”。为了帮助避免对度量单位选择的依赖性,数据应该规范化或标准化。这涉及变换数据,使之落入较小的共同区间,如[-1,1]或[0.0,1.0]。(在数据预处理中,术语“规范化”和“标准化”可以互换使用,尽管后一术语在统计学还具有其他含义。)
通过分箱离散化
分箱是一种基于指定的箱个数的自顶向下的分裂技术。这些方法也可以用作数据归约和概念分层产生的离散化方法。例如,通过使用等宽或等频分箱,然后用箱均值或中位数替换箱中的每个值,可以将属性值离散化,就像用箱的均值或箱的中位数光滑一样。这些技术可以递归地作用于结果划分,产生概念分层。
通过直方图分析离散化
像分箱一样,直方图分析也是一种非监督离散化技术,因为它也不使用类信息。直方图把属性A的值划分成不相交的区间,称做桶或箱。
可以使用各种划分规则定义直方图。例如,在等宽直方图中,将值分成相等分区或区间(例如,图3.8的price,其中每个桶宽度为10美元)。理想情况下,使用等频直方图,值被划分,使得每个分区包括相同个数的数据元组。直方图分析算法可以递归地用于每个分区,自动地产生多级概念分层,直到达到一个预先设定的概念层数,过程终止。也可以对每一层使用最小区间长度来控制递归过程。最小区间长度设定每层每个分区的最小宽度,或每层每个分区中值的最少数目。正如下面将介绍的那样,直方图也可以根据数据分布的聚类分析进行划分。
通过聚类、决策树和相关分析离散化
聚类、决策树和相关分析可以用于数据离散化。我们简略讨论这些方法。
标称数据的概念分层产生
现在,我们考察标称数据的数据变换。特别地,我们研究标称属性的概念分层产生。标称属性具有有穷多个不同值(但可能很多),值之间无序。例如地理位置、工作类别和商品类型。
对于用户和领域专家而言,人工定义概念分层是一项乏味和耗时的任务。幸运的是,许多分层结构都隐藏在数据库的模式中,并且可以在模式定义级自动地定义。概念分层可以用来把数据变换到多个粒度层。例如,关于销售的数据挖掘模式除了在单个分店挖掘之外,还可以针对指定的地区或国家挖掘。
大数据
2018-12-26 17:22:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
12月20日,由阿里巴巴承办的 Flink Forward China 峰会在北京国家会议中心召开,来自阿里、华为、腾讯、美团点评、滴滴、字节跳动等公司的技术专家与参会者分享了各公司基于 Flink 的应用和实践经验。
感兴趣的开发者可以看云栖社区的对于大会的主会+5场分论坛的直播与 视频点播 。
会议进行中,看到AI前线对蒋晓伟的采访。正如许多开发者所关心的Flink和Blink的关系(云栖社区2016年文章: 阿里蒋晓伟谈流计算和批处理引擎Blink,以及Flink和Spark的异同与优势 ),如今有了更新的方向。本篇AI前线的专访讲述的极为清晰。特别转载,共享。
今年,实时流计算技术开始步入主流,各大厂都在不遗余力地试用新的流计算框架,实时流计算引擎和 API 诸如 Spark Streaming、Kafka Streaming、Beam 和 Flink 持续火爆。阿里巴巴自 2015 年开始改进 Flink,并创建了内部分支 Blink,目前服务于阿里集团内部搜索、推荐、广告和蚂蚁等大量核心实时业务。
在大会的主题演讲上,阿里巴巴集团副总裁周靖人宣布, 阿里巴巴内部 Flink 版本 Blink 将于 2019 年 1 月正式开源 ! 阿里希望通过 Blink 开源进一步加深与 Flink 社区的联动,并推动国内更多中小型企业使Flink。
Flink Forward China会上,AI 前线对阿里巴巴计算平台事业部研究员蒋晓伟(花名量仔)进行了独家专访,他与我们分享了关于下一代实时流计算引擎的看法,并针对 Blink 的重要新特性、开源后 Blink 与 Flink 之间的关系、Blink 后续规划等问题进行了解答。
阿里巴巴与 Flink
随着人工智能时代的降临和数据量的爆发,在典型的大数据业务场景下,数据业务最通用的做法是:选用批处理的技术处理全量数据,采用流式计算处理实时增量数据。在很多的业务场景之下,用户的业务逻辑在批处理和流处理之中往往是相同的。但是,用户用于批处理和流处理的两套计算引擎是不同的。
因此,用户通常需要写两套代码。毫无疑问,这带来了一些额外的负担和成本。阿里巴巴的商品数据处理就经常需要面对增量和全量两套不同的业务流程问题,所以阿里巴巴就在想:能不能有一套统一的大数据引擎技术,用户只需要根据自己的业务逻辑开发一套代码。这样在各种不同的场景下,不管是全量数据还是增量数据,亦或者实时处理,一套方案即可全部支持,这就是阿里巴巴选择 Flink 的背景和初衷。
彼时的 Flink 不管是规模还是稳定性尚未经历实践,成熟度有待商榷。阿里巴巴实时计算团队决定在阿里内部建立一个 Flink 分支 Blink,并对 Flink 进行大量的修改和完善,让其适应阿里巴巴这种超大规模的业务场景。简单地说,Blink 就是阿里巴巴开发的基于开源 Flink 的阿里巴巴内部版本。
阿里巴巴基于 Flink 搭建的平台于 2016 年正式上线,并从阿里巴巴的搜索和推荐这两大场景开始实现。目前阿里巴巴所有的业务,包括阿里巴巴所有子公司都采用了基于 Flink 搭建的实时计算平台。
目前,这套基于 Flink 搭建的实时计算平台不仅服务于阿里巴巴集团内部,而且通过阿里云的云产品 API 向整个开发者生态提供基于 Flink 的云产品支持。
以下内容整理自 AI 前线对蒋晓伟的采访。
开源的时机
AI 前线:为什么选择现在将 Blink 开源?这其中有哪些考量?什么样的时机才是开源最合适的时机?
蒋晓伟: 在我看来,有几个因素:第一个因素是,这几年我们一直试图把阿里对 Flink 的改进推回社区,但社区有自己的步伐,很多时候可能无法把我们的变更及时推回去。对于社区来说,需要达成共识,才能更好地保证开源项目的质量,但同时就会导致推入的速度慢一些。经过这几年积累,我们这边和社区之间的差距已经变得比较大了。Blink 有一些很好的新功能,比如批处理功能,在社区版本是没有的。在过去这段时间里,我们不断听到有人问,Blink 什么时候能开源、是不是能开源这样的呼声。我们有两种方法,一种就是慢慢地推回去再给用户用。但我们认为这样等下去对社区不是最好的。我们还是希望尽快把我们的代码拿出来,尽量让大家都能用起来。所以最近这半年,我们一直都在准备把代码整理好去进行开源。
选择在这个时间点开源有几个好处:第一个好处是我们所开源的这些代码在阿里内部经过像双一十、双十二这样巨大流量的检验,让我们对它的质量有更大的信心,这是非常大的好处;第二个好处,Flink Forward 大会是第一次在中国举办,在这样一个场合开源表明了阿里对 Flink 社区坚定的支持,这是一个比较好的场合。主要是基于这些考虑。
选 Blink 还是 Flink?这不会是一个问题
AI 前线:开源的 Blink 版本会和阿里巴巴内部使用的 Blink 保持一致吗?
蒋晓伟: 即将开源的是阿里巴巴双十二的上线版本,还会有一些小的改进。
AI 前线:Blink 开源后,两个开源项目之间的关系会是怎样的?未来 Flink 和 Blink 也会由不同的团队各自维护吗?
蒋晓伟: 开源的意思是,我们愿意把 Blink 的代码贡献出来,但这两个项目是一个项目。有一件事情需要澄清一下,我们将公开 Blink 的所有代码,让大家都可以看到,但与此同时,我们会跟社区一起努力,通过讨论决定 Blink 以什么样的方式进入 Flink 是最合适的。因为 Flink 是一个社区的项目,我们需要经过社区的同意才能以分支的形式进入 Flink,或者作为变更 Merge 到项目中。我想强调一下,我们作为社区的一员需要跟社区讨论才能决定这件事情。
Blink 永远不会成为另外一个项目,如果后续进入 Apache 一定是成为 Flink 的一部分,我们没有任何兴趣另立旗帜,我们永远是 Flink 的一部分,也会坚定地支持 Flink。我们非常愿意把 Blink 的代码贡献给所有人,所以明年 1 月份我们会先将 Blink 的代码公开,但这期间我们也会和社区讨论,以什么样的形式进入 Flink 是最合适的、怎么贡献是社区最希望的方式。
我们希望,在 Blink 开源之后,和社区一起努力,把 Blink 好的地方逐步推回 Flink,成为 Flink 的一部分,希望最终 Flink 和 Blink 变成一个东西,阿里巴巴和整个社区一起来维护。而不是把它分成两个东西,给用户选择的困难,这不是我们想要的。
因此未来用户也不会面临已经部署了 Flink、是否要把 Flink 迁移到 Blink 的问题,企业选型时也不需要在 Flink 和 Blink 之间抉择,Blink 和 Flink 会是同一个项目。Blink 开源只有一个目的,就是希望 Flink 做得更好。
Blink 改进了什么?
AI 前线:能不能重点介绍一下即将开源的 Blink 版本有哪些比较重要的新技术特性?与 Flink 最新发布版本相比,阿里的 Blink 做了哪些方面的优化和改进?
蒋晓伟: 阿里巴巴实时计算团队不仅对 Flink 在性能和稳定性上做出了很多改进和优化,同时在核心架构和功能上也进行了大量创新和改进。过去两年多,有很多更新已经推回给社区了,包括 Flink 新的分布式架构等。
目前我们的 Blink 版本跟社区版本还有几点差异,第一个是稳定性方面,我们做了一些优化,在某些场景会比社区版本更加稳定,特别是在大规模场景。另外还有一个比较大的不一样是我们全新的 Flink SQL 技术栈,它在功能上,特别是在批处理的功能上比社区版本强大很多。它支持现在标准 SQL 几乎所有的语法和语义。另外,在性能上,无论是在流式 SQL 还是批 SQL,我们的版本在性能上都有很大的优势。特别是在批 SQL 的性能方面,当前 Blink 版本是社区版本性能的 10 倍以上,跟 Spark 相比,在 TPCDS 这样的场景 Blink 的性能也能达到 3 倍以上。如果用户对批处理或者对 SQL 有着比较强的需求,我们这个版本会用户可以得到很多好处。
Blink 在阿里内部的应用
AI 前线:请介绍一下 Blink 在阿里内部的使用情况。目前 Blink 在阿里的大数据架构中扮演什么样的角色?在阿里内部主要用于哪些业务和应用场景?
蒋晓伟: 现在阿里的大数据平台上,所有的实时计算都已经在使用 Blink;同时,除了实时计算以外,在一些流批一体化的场景也会用 Blink 来做批处理;我们在机器学习场景也有一个探索,叫做 Alink,这个项目是对 Flink Machine Learning Library 的改进,其中实现了大量的算法,都是基于 Flink 做实时机器学习的算法,Alink 在很多场景已经被证明在规模上有很大的优势。同时,我们在图计算场景也有一些探索。
AI 前线:目前阿里内部有多少部门在使用 Blink?
蒋晓伟: 前段时间我们刚刚做过统计,阿里的技术部门大约有 70% 都在使用 Blink。Blink 一直是在用户的反馈之中成长起来的,对于内部用户反馈的数据倾斜、资源使用率、易用性方面的问题,Blink 都做了针对性的改进。
现在 Blink 用的最多的场景主要还是实时计算方面,阿里还有一些业务现在相对比较新,还没有进入实时计算的领域,等这些业务进入实时计算领域时也会使用 Blink。
在批处理方面,阿里内部也有一个自研的批处理引擎叫做 MaxCompute,MaxCompute 也会拥抱 Flink 生态,在语法和语义上做和 Flink 兼容的工作。未来,整个阿里的计算体系和平台都会融入同一个生态。
后续规划
AI 前线:接下来阿里对于 Blink 还有哪些规划?包括技术改进、落地应用、更新维护、社区等几个方面。
蒋晓伟: 从技术上说,今天我们公布了 Flink 在批处理上的成果,接下来,我们会对技术持续投入,我们希望每几个月就能看到技术上有一个比较大的亮点。下一波亮点应该是机器学习场景。要把机器学习支持好,有一系列的工作要做,包括引擎的功能、性能和易用性。这些工作我们已经在内部的讨论和进行之中,接下来几个月,大家应该会看到一些成果。我们也在和社区讨论一些事情。除了机器学习之外,我们在图计算方面也有一些探索,包括对增量迭代更好的支持。做完这些之后,可以认为 Flink 作为大数据的计算引擎已经比较完备了。
同时,我们也重点去做 Flink 的生态,包括 Flink 与其他系统之间的关系、易用性等。Flink 要真正做好,不仅需要它本身功能强大,还需要把整个生态做得非常强大。这部分我们甚至会跟一些 ISV 合作,看看是不是能够在 Flink 之上提供更好的解决方案,进一步降低用户的使用门槛。
在社区方面,我们希望能够把把 Blink 完全融入 Flink 社区,一起做 Flink 社区的运营,让 Flink 真正在中国、乃至全世界大规模地使用起来。
在应用方面,实时流计算其实有很多很有潜力的应用场景,但有一些可能大家不是非常熟悉,我们会对这些场景做一些推广。以实时机器学习为例,它往往能够给我们带来比一般的机器学习更大的效果提升。去年,实时强化学习给我们在搜索上带来了 20% 以上的提升。除此之外,在安全领域(比如实时的 Fraud Detection)、监控报警方面,还有 IoT 领域,实时流计算都有非常广泛的应用场景。这些 Flink 现在可能已经做了,但是大家还没有意识到,Flink 能够给大家带来这样的商业上的好处。
AI 前线:Blink 开源之后,后续阿里在这基础上做的变更和更新会以什么样的方式推回社区版本?
蒋晓伟: 我们理想的方式是,阿里内部的版本是社区的 Flink 版本加上一些定制化的插件,不需要对 Flink 本身做修改,而是对 Flink 做增加。比如跟阿里内部系统交互的部分跟社区是不适用的,就会保持在内部,我们希望这些修改不动 Flink 代码,而是用插件的方式加在 Flink 上面。最终的方式就是,对于所有公司都有用的修改会在 Flink 代码本身做修改,使所有使用 Flink 的公司都能从中获利,而对接阿里内部系统的部分就只在阿里内部使用。
下一代实时流计算引擎之争
AI 前线:先在很多人提到实时流计算引擎,都会拿 Spark 和 Flink 来做对比,您怎么看待下一代实时流计算引擎之争?未来实时流计算引擎最重要的发展方向是什么?
蒋晓伟:Spark 和 Flink 一开始 share 了同一个梦想,他们都希望能够用同一个技术把流处理和批处理统一起来,但他们走了完全不一样的两条路,前者是用以批处理的技术为根本,并尝试在批处理之上支持流计算;后者则认为流计算技术是最基本的,在流计算的基础之上支持批处理。正因为这种架构上的不同,今后二者在能做的事情上会有一些细微的区别。比如在低延迟场景,Spark 基于微批处理的方式需要同步会有额外开销,因此无法在延迟上做到极致。在大数据处理的低延迟场景,Flink 已经有非常大的优势。经过我们的探索,Flink 在批处理上也有了比较大的突破,这些突破都会反馈回社区。当然,对于用户来说,多一个选择永远是好的,不同的技术可能带来不同的优势,用户可以根据自己业务场景的需求进行选择。
未来,在大数据方向,机器学习正在逐渐从批处理、离线学习向实时处理、在线学习发展,而图计算领域同样的事情也在发生,比如实时反欺诈通常用图计算来做,而这些欺诈事件都是实时地、持续不断地发生,图计算也在变得实时化。
但是 Flink 除了大数据领域以外,在应用和微服务的场景也有其独特的优势。应用和微服务场景对延迟的要求非常苛刻,会达到百毫秒甚至十毫秒级别,这样的延迟只有 Flink 的架构才能做到。我认为应用和微服务其实是非常大的领域,甚至可能比大数据更大,这是非常激动人心的机会。上面这些都是我们希望能够拓宽的应用领域。
AI 前线:在技术方面,Spark 和 Flink 其实是各有千秋,但在生态和背后支持的公司上面,Flink 是偏弱的,那么后续在生态和企业支持这块,阿里会如何帮助 Flink?
蒋晓伟: 这次阿里举办 Flink Forward China 就是想推广 Flink 生态的重要举动之一。除了 Flink Forward China 大会,我们还会不定期举办各种线下 Meetup,投入大量精力打造中文社区,包括将 Flink 的英文文档翻译成中文、打造 Flink 中文论坛等。在垂直领域,我们会去寻找一些合作伙伴,将 Flink 包装在一些解决方案中提供给用户使用。
AI 前线:关于开源项目的中立性问题。阿里现在在大力地推动 Flink 开源项目的应用和社区的发展,但业界其他公司(尤其是与阿里在其他业务上可能有竞争的公司)在考虑是否采用 Flink 的时候可能还是会对社区的中立性存在一些疑虑,对于这一点,阿里是怎么考虑的?
蒋晓伟: 阿里本身会投入非常大的力量推动 Flink 社区的发展和壮大,但我们也非常希望有更多企业、更多人加入社区,和阿里一起推动社区发展,这次阿里承办 Flink Forward China 峰会就是想借此机会让更多公司参与进来。光阿里一家是无法把 Flink 生态做起来的。我希望大家能够看到我们在做的事情,然后消除这样的疑虑。我们会用自己的行动表明,我们是真的希望把 Flink 的社区做大,在这件事情上,我们并不会有私心。
原文链接
大数据
2018-12-21 11:05:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
CDH5之启用邮箱警报
在使用CDH5的时候,各种警报信息,需要及时知道,CDH5平台自带了邮箱预警功能,此邮箱预警功能,可以使用CDH5平台自带的邮箱,也可配置自定义的邮箱,下面一一介绍。
此处使用的是CDH5.7.2版本。
登录
登录CDH5的web管理页面,如下图,点击集群,选择Cloudera Mannagement Service。
进入Cloudera Mannagement Service页面,然后选择配置,如下图,在搜索框中输入alert,进行搜索。
到了这一步,就可以选择是使用平台默认邮箱,还是使用自定义邮箱了。下面分别介绍两种方式。
使用默认邮箱
使用默认邮箱发送预警邮件的配置比较简单,如下图:

如上配置,可以使用平台自带的邮箱进行发送。
此处需要注意:在接收邮件的邮箱中将发件人地址noreply@localhost设置为白名单,如果不设置默认会被接收邮件的邮箱放入垃圾邮件中。
自定义邮箱
自定义邮箱主要配置的选项如下,其他和默认的相同即可:
上一篇: CDH的坑之Deploy Client Configuration Failed
下一篇: CDH5之时钟偏差问题
大数据
2018-12-21 10:34:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Python与Elasticsearch的接口
目前,有两个标准库提供了Python与Elasticsearch之间的接口:https://elasticsearch-py.readthedocs.io/en/master/http://pyelasticsearch.readthedocs.io/en/latest/这里以elasticsearch库为例,给出一个从MySQL数据库抓取数据存到ES数据库的简单例子:

大数据
2018-12-20 16:50:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
什么是倒排索引?
Elasticsearch之分词器的作用
Elasticsearch之分词器的工作流程
Elasticsearch之停用 词
Elasticsearch之中文分词器
Elasticsearch之几个重要的分词器








elasticsearch官方默认的分词插件
  1、 elasticsearch官方默认的分词插件,对中文分词效果不理想。
  比如,我现在,拿个具体实例来展现下, 验证为什么,es官网提供的分词插件对中文分词而言,效果差 。

[hadoop@HadoopMaster elasticsearch-2.4.3]$ jps
2044 Jps
1979 Elasticsearch
[hadoop@HadoopMaster elasticsearch-2.4.3]$ pwd
/home/hadoop/app/elasticsearch-2.4.3
[hadoop@HadoopMaster elasticsearch-2.4.3]$ curl 'http://192.168.80.10:9200/zhouls/_analyze?pretty=true' -d '{"text":"这里是好记性不如烂笔头感叹号的博客园"}'
{
"tokens" : [ {
"token" : " 这 ",
"start_offset" : 0,
"end_offset" : 1,
"type" : "",
"position" : 0
}, {
"token" : " 里 ",
"start_offset" : 1,
"end_offset" : 2,
"type" : "",
"position" : 1
}, {
"token" : " 是 ",
"start_offset" : 2,
"end_offset" : 3,
"type" : "",
"position" : 2
}, {
"token" : " 好 ",
"start_offset" : 3,
"end_offset" : 4,
"type" : "",
"position" : 3
}, {
"token" : " 记 ",

"start_offset" : 4,
"end_offset" : 5,
"type" : "",
"position" : 4
}, {
"token" : " 性 ",
"start_offset" : 5,
"end_offset" : 6,
"type" : "",
"position" : 5
}, {
"token" : " 不 ",
"start_offset" : 6,
"end_offset" : 7,
"type" : "",
"position" : 6
}, {
"token" : " 如 ",
"start_offset" : 7,
"end_offset" : 8,
"type" : "",
"position" : 7
}, {
"token" : " 烂 ",
"start_offset" : 8,
"end_offset" : 9,
"type" : "",
"position" : 8
}, {
"token" : " 笔 ",
"start_offset" : 9,
"end_offset" : 10,
"type" : "",
"position" : 9
}, {
"token" : " 头 ",
"start_offset" : 10,
"end_offset" : 11,
"type" : "",
"position" : 10
}, {
"token" : " 感 ",
"start_offset" : 11,
"end_offset" : 12,
"type" : "",
"position" : 11
}, {
"token" : " 叹 ",
"start_offset" : 12,
"end_offset" : 13,
"type" : "",
"position" : 12
}, {
"token" : " 号 ",
"start_offset" : 13,
"end_offset" : 14,
"type" : "",
"position" : 13
}, {
"token" : " 的 ",
"start_offset" : 14,
"end_offset" : 15,
"type" : "",
"position" : 14
}, {
"token" : " 博 ",
"start_offset" : 15,
"end_offset" : 16,
"type" : "",
"position" : 15
}, {
"token" : " 客 ",
"start_offset" : 16,
"end_offset" : 17,
"type" : "",
"position" : 16
}, {
"token" : " 园 ",
"start_offset" : 17,
"end_offset" : 18,
"type" : "",
"position" : 17
} ]
}
[hadoop@HadoopMaster elasticsearch-2.4.3]$



总结
如果直接使用Elasticsearch的朋友在处理中文内容的搜索时,肯 定会遇到很尴尬的问题——中文词语被分成了一个一个的汉字,当用Kibana作图的时候,按照term来分组,结果一个汉字被分成了一组。
这是因为使用了Elasticsearch中默认的标准分词器,这个分词器在处理中文的时候会把中文单词切分成一个一个的汉字,因此 引入es之中文的分词器插件es-ik就能解决这个问题 。









如何集成IK分词工具
   总的流程如下:
第一步: 下载es的IK插件 https://github.com/medcl/elasticsearch-analysis-ik/tree/2.x
第二步:使用maven对 下载的es-ik源码进行编译 (mvn clean package -DskipTests)
第三步:把编译后的target/releases下的elasticsearch-analysis-ik-1.10.3.zip文件 拷贝到ES_HOME/plugins/ik 目录下面,然后使用unzip命令解压
    如果unzip命令不存在,则安装:yum install -y unzip
第四步: 重启es服务
第五步: 测试分词效果 : curl 'http://your ip:9200/zhouls/_analyze?analyzer=ik_max_word&pretty=true' -d '{"text":"这里是好记性不如烂笔头感叹号的博客们"}'
  注意:若你是单节点的es集群的话,则只需在一台部署es-ik。若比如像我这里的话,是3台,则需在三台都部署es-ik,且配置要一样。




elasticsearch-analysis-ik-1.10.0.zip  对应于  elasticsearch-2.4.0
elasticsearch-analysis-ik-1.10.3.zip  对应于  elasticsearch-2.4.3




  我这里,已经给大家准备好了,以下是我的CSDN账号。下载好了,大家可以去下载。

http: // download.csdn.net/detail/u010106732/9890897 http://download.csdn.net/detail/u010106732/9890918







https: // github.com/medcl/elasticsearch-analysis-ik/tree/v1.10.0






  






   第一步 : 在浏览器里,输入 https://github.com/




    第二步 : https://github.com/search?utf8=%E2%9C%93&q=elasticsearch-ik



  
   第三步 : https://github.com/medcl/elasticsearch-analysis-ik ,点击2.x 。当然也有一些人在用2.4.0版本,都适用。若你是使用5.X,则自己对号入座即可,这个很简单。





   第四步 : https://github.com/medcl/elasticsearch-analysis-ik/tree/2.x 得到



   第五步 :找到之后,点击,下载, 这里选择离线安装 。
  



   第六步 :将Elasticsearch之中文分词器插件es-ik的压缩包解压下,初步认识下其目录结构,比如我这里放到D盘下来认识下。并为后续的maven编译做基础。

  


   第七步 :用本地安装好的maven来编译

Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。
C:
大数据
2018-12-20 16:44:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1.使用的maven客户端包 org.apache.hbase hbase-shaded-client 1.4.9
2.HbaseTemplate 模板类,基于canal修改 import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.*; import org.apache.hadoop.hbase.client.*; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.regex.Pattern; /** * HBase操作模板 */ @Component public class HbaseTemplate implements InitializingBean { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Value("${hbase.zookeeper.quorum}") private String quorum; @Value("${hbase.zookeeper.clientPort}") private String clientPort; @Value("${hbase.zookeeper.znodeParent}") private String znodeParent; @Value("${hadoop.home.dir}") private String hadoopHomeDir; @Value("${hadoop.home.isset}") private Boolean hadoopHomeIsset; private Connection conn; public boolean tableExists(String tableName) { try (HBaseAdmin admin = (HBaseAdmin) conn.getAdmin()) { return admin.tableExists(TableName.valueOf(tableName)); } catch (IOException e) { throw new RuntimeException(e); } } public boolean namespaceExists(String namespace){ boolean flag= true; try (HBaseAdmin admin = (HBaseAdmin) conn.getAdmin()) { NamespaceDescriptor namespaceDescriptor = admin.getNamespaceDescriptor(namespace); String name = namespaceDescriptor.getName(); if(name ==null){ flag = false; } }catch (NamespaceNotFoundException e){ flag = false; }catch (IOException e) { throw new RuntimeException(e); } return flag; } public void deleteNamespace(String namespace){ if(namespaceExists(namespace)){ try (HBaseAdmin admin = (HBaseAdmin) conn.getAdmin()) { Pattern compile = Pattern.compile(namespace + ":.*"); admin.disableTables(compile); admin.deleteTables(compile); admin.deleteNamespace(namespace); } catch (IOException e) { throw new RuntimeException(e); } } } public void createNamespace(String namespace){ try (HBaseAdmin admin = (HBaseAdmin) conn.getAdmin()) { admin.createNamespace(NamespaceDescriptor.create(namespace).build()); } catch (IOException e) { throw new RuntimeException(e); } } public void createTable(String tableName, String... familyNames) { try (HBaseAdmin admin = (HBaseAdmin) conn.getAdmin()) { HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName)); // 添加列簇 if (familyNames != null) { for (String familyName : familyNames) { HColumnDescriptor hcd = new HColumnDescriptor(familyName); desc.addFamily(hcd); } } admin.createTable(desc); } catch (IOException e) { throw new RuntimeException(e); } } public void disableTable(String tableName) { try (HBaseAdmin admin = (HBaseAdmin) conn.getAdmin()) { admin.disableTable(tableName); } catch (IOException e) { logger.error(e.getMessage(), e); throw new RuntimeException(e); } } public void deleteTable(String tableName) { try (HBaseAdmin admin = (HBaseAdmin) conn.getAdmin()) { if (admin.isTableEnabled(tableName)) { disableTable(tableName); } admin.deleteTable(tableName); } catch (IOException e) { logger.error(e.getMessage(), e); throw new RuntimeException(e); } } /** * 插入一行数据 * * @param tableName 表名 * @param hRow 行数据对象 * @return 是否成功 */ public Boolean put(String tableName, HRow hRow) { boolean flag = false; try { HTable table = (HTable) conn.getTable(TableName.valueOf(tableName)); Put put = new Put(hRow.getRowKey()); for (HRow.HCell hCell : hRow.getCells()) { put.addColumn(Bytes.toBytes(hCell.getFamily()), Bytes.toBytes(hCell.getQualifier()), hCell.getValue()); } table.put(put); flag = true; } catch (Exception e) { logger.error(e.getMessage(), e); } return flag; } /** * 批量插入 * * @param tableName 表名 * @param rows 行数据对象集合 * @return 是否成功 */ public Boolean puts(String tableName, List rows) { boolean flag = false; try { HTable table = (HTable) conn.getTable(TableName.valueOf(tableName)); List puts = new ArrayList<>(); for (HRow hRow : rows) { Put put = new Put(hRow.getRowKey()); for (HRow.HCell hCell : hRow.getCells()) { put.addColumn(Bytes.toBytes(hCell.getFamily()), Bytes.toBytes(hCell.getQualifier()), hCell.getValue()); } puts.add(put); } if (!puts.isEmpty()) { table.put(puts); } flag = true; } catch (Exception e) { logger.error(e.getMessage(), e); } return flag; } /** * 批量删除数据 * * @param tableName 表名 * @param rowKeys rowKey集合 * @return 是否成功 */ public Boolean deletes(String tableName, Set rowKeys) { boolean flag = false; try { HTable table = (HTable) conn.getTable(TableName.valueOf(tableName)); List deletes = new ArrayList<>(); for (byte[] rowKey : rowKeys) { Delete delete = new Delete(rowKey); deletes.add(delete); } if (!deletes.isEmpty()) { table.delete(deletes); } flag = true; } catch (Exception e) { logger.error(e.getMessage(), e); } return flag; } @Override public void afterPropertiesSet() throws Exception { if(hadoopHomeIsset){ System.setProperty("hadoop.home.dir",hadoopHomeDir); } Configuration hbaseConfig = HBaseConfiguration.create(); hbaseConfig.set("hbase.zookeeper.quorum",quorum); hbaseConfig.set("hbase.zookeeper.property.clientPort",clientPort); hbaseConfig.set("zookeeper.znode.parent",znodeParent); conn = ConnectionFactory.createConnection(hbaseConfig); } } import java.util.ArrayList; import java.util.List; /** * HBase操作对象类 */ public class HRow { private byte[] rowKey; private List cells = new ArrayList<>(); public HRow(){ } public HRow(byte[] rowKey){ this.rowKey = rowKey; } public byte[] getRowKey() { return rowKey; } public void setRowKey(byte[] rowKey) { this.rowKey = rowKey; } public List getCells() { return cells; } public void setCells(List cells) { this.cells = cells; } public void addCell(String family, String qualifier, byte[] value) { HCell hCell = new HCell(family, qualifier, value); cells.add(hCell); } public static class HCell { private String family; private String qualifier; private byte[] value; public HCell(){ } public HCell(String family, String qualifier, byte[] value){ this.family = family; this.qualifier = qualifier; this.value = value; } public String getFamily() { return family; } public void setFamily(String family) { this.family = family; } public String getQualifier() { return qualifier; } public void setQualifier(String qualifier) { this.qualifier = qualifier; } public byte[] getValue() { return value; } public void setValue(byte[] value) { this.value = value; } } } import org.apache.hadoop.hbase.util.Bytes; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * 2018/12/19 18:20 * jiacheng */ @Component public class TestHbaseTemplate implements InitializingBean { @Resource private HbaseTemplate hbaseTemplate; @Override public void afterPropertiesSet() throws Exception { System.out.println("++++++++++++++++++测试创建Hbase 表================="); String namespace="canal_test"; if(hbaseTemplate.namespaceExists(namespace)){ System.out.println("+++++++++ namespace exist , namespace="+namespace); hbaseTemplate.deleteNamespace(namespace); System.out.println("+++++++++ namespace delete successful , namespace="+namespace); } hbaseTemplate.createNamespace(namespace); System.out.println("+++++++++ namespace create successful , namespace="+namespace); String tableName = namespace+":test_jcc"; boolean tableExists = hbaseTemplate.tableExists(tableName); if(tableExists){ System.out.println("+++++++table is exist,name="+tableName); hbaseTemplate.deleteTable(tableName); System.out.println("+++++++table delete successful, name="+tableName); } String cf1 = "CF1"; String cf2 = "CF2"; hbaseTemplate.createTable(tableName, cf1, cf2); System.out.println("+++++++table create successful, name="+tableName); HRow row = new HRow(Bytes.toBytes("rowkey_"+System.currentTimeMillis())); row.addCell(cf1,"name",Bytes.toBytes("chenjia")); row.addCell(cf1,"age",Bytes.toBytes("25")); row.addCell(cf2,"name2",Bytes.toBytes("chenjia")); row.addCell(cf2,"age2",Bytes.toBytes("25")); hbaseTemplate.put(tableName,row); } }
大数据
2018-12-20 16:11:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
摘要: 2018年云数据库RDS发展上,不但针对MySQL、SQL Server、PostgreSQL提供了适合个人入门用户的基础版产品,以实惠的价格普惠广大中小用户。更加入最新的MariaDB TX企业版,及大幅度提高PPAS的Oracle兼容性,从企业需求出发,重点在全生命周期、全链路安全、全链路监控、全方位运维、多引擎覆盖 5个方面进行发力,为企业用户提供更优质的云数据库服务。
云计算已经进入普及期,不少企业开始从自建数据中心转向云计算。在云计算资源的使用上,从最开始只是使用IaaS层基础资源,转向使用包括云数据库在内的各类PaaS资源。数据库是企业IT架构的核心部分,RDS关系型数据库服务已经成为企业重度依赖的云服务。


过去7年的持续发展,2018年阿里云首次进入Gartner的数据库魔力象限,能够入选Gartner,这是中国数据库厂商的一次突破。阿里云入围Gartner充分说明,在新一波技术浪潮之上进行创新,才可能做出突破。云数据库已经不仅仅是简单地完成数据库在云资源中的搭建,数据库曾经是IT系统中最昂贵的投入之一。对企业CXO们(CEO、CFO、CTO、CIO等)而言,更加灵活的生命周期管理,可以实现成本的合理投入及灵活管理。对DBA技术人员而言,更高的安全性、更全面的监控能力、更便捷的运维方式,将改变DBA在企业的工作模式及地位。
从企业管理者及DBA的角度,我们将针对企业对数据库的各方面需求基于:全生命周期、全方位运维、全链路安全、全链路监控、多引擎覆盖 5个方面进行横向对比,希望给广大读者呈现一张《2018阿里云云数据库RDS核心能力演进》大图。
全生命周期
2017 2018
按量付费 支持 支持
按量付费立即升级 支持 支持
按量付费立即降级 支持 支持
按量付费 转 包年包月 - 支持
包年包月 支持 支持
包年包月立即升级 支持 支持
包年包月立即降级 - 支持
包年包月到期升/降级 支持 支持
包年包月 转 按量付费 - -
按量付费资源释放 支持 支持
续费解锁 支持(7天内) 支持(7天内)
过期重建
销毁实例
-
-
支持(15天内)
支持

灵活的生命周期管理,可以让企业以最合适的投入成本使用云计算资源,对于任何规模的企业,这都是开源节流的有力手段。一个IT项目通常会经历以下阶段:
项目规划:按量付费(升、降级)以进行功能开发、性能等验证 系统上线:按量付费转包年包月,以长期节省成本 系统扩充:包年包月升级 系统萎缩:包年包月降级 系统下线:包年包月按量付费 -> 按量付费资源释放 -> 销毁实例(彻底删除数据) 当然云计算也应该提供能力,以避免企业由于业务过程中突发情况,忘记充值导致需要进行“续费解锁”,甚至是由于已经到达实例续费最后期限而到导致资源释放后,需要通过“过期重建”进行数据找回。
这些能力构成云数据库的“全生命周期”管理能力,可以看到阿里云在2018年进行了重点功能提升,已经可以满足企业大部份需求,唯独还没有提供“包年包月转按量付费”能力,这一功能我们也即将会开放。
全方位运维
2017 2018
实例生产时间 7-15分钟 2-7分钟
跨区高可用 部分引擎及地区 全引擎,覆盖85%以上地域
可维护时间段 最小单位4小时 最小单位1小时
参数管理 MySQL MySQL/PostgreSQL/PPAS
实例备份 支持 支持
实例恢复(克隆) 支持 支持
库/表级恢复 - 支持MySQL/SQLServer
回收站 长达7天 长达15天,支持完全销毁
数据管理
SLA理赔
免费版
工单申请
免费版/高级版/企业版
自助式理赔
曾经DBA的工作就是日复一日地进行数据库安装、部署、巡检、备份、恢复,在很多企业中DBA只是一个运维职位,为数据库的正常运行而负责。而到了云时代,DBA可以跳出这些枯燥的的日常工作,云计算已经将这些功能自动化实现,使得DBA可以更进一步为企业数据的运行效率而负责。
2018年阿里云在RDS中大幅度同比2017年提高实例生产效率达1倍之多。在高可用版部署模式下,不提高任何成本即可支持“跨区高可用”部署,为企业提供更为可靠的同城双中心跨区域容灾体验。
通过精细化调度管理策略,将“可维护时间段”从4小时缩短到1小时。同时,提供“待处理事件”功能,实现与用户进行可视化的运维管理协调的交互能力。企业的DBA可以更为有效地管理运维时间,在遇到云资源后端发现硬件问题预警,必须进行网络或HA切换时可以自行调整切换闪断时间,降低对企业业务正常运行的干扰。
数据管理提供除了免费版外,针对中大型企业的DBA提供高级版、企业版,数据管理企业版,是一种集数据管理、结构管理、研发流程、用户管理、权限管理、访问安全于一体的数据管理服务。基于RDS及数据管理企业版,企业DBA可以从繁重的日常数据库管理工作中脱离出来,以数据为中心为企业提供更有价值的数据管理服务,如: 研发人员从线下环境结构设计,到SQL发布预审,到生产发布的完整数据库研发流程 字段级别细粒度操作权限管控,所有用户操作在线化、可溯源 支持根据业务灵活配置结构设计、数据变更、数据导出等操作的审批流程 统一研发与数据库交互的入口,任何用户都不再直接接触数据库账号密码也不需要频繁切换数据库连接进行管理 等等……
全链路安全
2017 2018
资源授权管理 支持 支持
IP白名单 支持 支持
安全组管理 - 支持
公网DDoS防护 支持 支持
SSL连接加密 支持 支持
TDE透明加密 支持 支持
SQL审计
按列数据脱敏
支持
-
支持(升级为SQL洞察)
支持(数据管理企业版)
数据库安全从资源层、连接层、存储层,到审计、脱敏,方方面面都关乎企业命脉。 资源层:在传统IT部署环境下,我们会通过物理机房准入的制度,来控制我们的第三方服务人员甚至是我方人员进入机房以管理资源的使用安全。而在云计算环境下“资源授权管理(简称RAM)”成为了数据安全管理的基础,可以控制不同的人或服务只可以使用或调度限定的数据库实例操作。 连接层:2018年重点添加了“安全组管理”功能,为用户批量授权提供了便捷的渠道,可以批量快速地添加访问IP白名单,简化DBA工作量。公网DDoS防护为需要打开公网连接的企业提供有效的屏障,提高公网连接安全性。并支持通过SSL实现数据访问链路的加密,以防止在数据传输过程被第三方摄取数据。 存储层:通过TDE透明加密,在不调整用户业务应用程序的前提下,实现数据落盘加密,确保用户数据在云环境下的数据私密性。 高级功能:2018年阿里云将“SQL审计”升级为“SQL洞察” 可以按照数据库、用户、客户端IP、线程ID、执行时长、扫描行数等进行多维度检索。新增SQL分析功能,可以对指定时间段异常SQL定位性能问题。采用新的列式存储和压缩技术,平均可帮您节省大约60%的成本。数据管理提供企业版支持,可以针对数据列进行数据脱敏并提供更全面的企业数据管理权限模型,及操作帐号审核机制。
全链路监控
2017 2018
报警规则 支持 支持
监控频率
CloudDBA
最短间隔60秒/次
只支持MySQL
最短间隔5秒/次
支持MySQL / SQLServer / PostgreSQL / PPAS
良好的监控及报警能力,可以提高云数据库的管理效率,同时智能CloudDBA可以提高技术运维人员的问题处理效率,保障企业数据库高效稳定运行。
2018年阿里云主要投入在提高监控频率,并将CloudDBA推广到所有RDS引擎中,以为企业提供更好的服务能力。CloudDBA是监控和管理RDS实例性能及运行状况的服务,针对SQL语句的性能、CPU使用率、IOPS使用率、内存使用率、磁盘空间使用率、连接数、锁信息、热点表等,CloudDBA提供了智能的诊断及优化功能,能最大限度发现数据库存在的或潜在的健康问题。CloudDBA的诊断基于单个实例,该诊断会提供问题详情及相应的解决方案,可为您管理实例运行状况带来极大的便利。
多引擎覆盖(及能力提升)
2017 2018
MySQL 5.5 / 5.6 / 5.7
5.7只支持基础版
5.5 / 5.6 / 5.7
全面支持高可用版
BinLog支持自定义保留时长
SQL Server 2008R2 / 2012 / 2016 2008R2 / 2012 / 2016 / 2017
2016及以上版本全面开放Linked Server功能,并提供基于OSS的原生数据恢复上云能力。当中2017版更支持AlwaysOn企业级横向只读扩展功能,2008R2支持升级到2016及以上版本。
MariaDB TX - TX 10.3
全球独家公共云MariaDB TX企业级版本官方授权,持续提供官方认证的最新安全补丁更新。支持窗口函数、在线数据溯源恢复、 在线添加列等企业级特性。
PostgreSQL
PPAS
9.4
9.3
9.4 / 10
最新版本提供阿里云自研云数据库时空引擎Ganos,可以通过对时间/空间位置信息的图形图像数据,表示事物的位置、形态、变化及大小分布等多维信息,与业务数据进行联合查询。
9.3 / 10
最新版本对ORACLE兼容性有了进一步提升,支持对象名自动大写调整、SYS_CONNECT_BY_PATH、ROLLUP/CUBE/GROUPING SETS、HASH分区表、SELECT … FOR UPDATE WAIT n、支持存储过程及函数嵌套、存储过程支持PARALLEL及NO_PARLLEL。同时配合ADAM数据库及应用迁移工具,可以大大缩短ORACLE到阿里云PPAS迁移的人力成本,为用户长期节省大量License费用及合规风险。
2018年阿里云云数据库RDS新添加引擎版本
通过提供更多最新的市场版本,特别是企业级版本功能,如:SQL Server AlwaysON、MariaDB TX及PPAS 10的ORACLE兼容性及ADAM工具。阿里云为更多不同需求的企业核心系统提供了支持,引擎版本几乎覆盖了市场上所有主流引擎的最高版本。让企业用户迁移上云时避免不必要的版本调整,以最小的工作代价完成系统上云工作。 SQL Server 2017 AlwaysOn,面向高端企业级客户 MariaDB TX,全球唯一MariaDB TX企业级版本公共云服务提供商 PostgreSQL 10,提供自研Ganos时空引擎,实现关系数据库中的时空+业务SQL联合 PPAS 10,提供更强的ORACLE兼容性,并与ADAM工具配合提供更平滑的迁移体验
总结:
为用户提供更核心且实用的价值,是阿里云一贯的承诺。2018年云数据库RDS发展上,不但针对MySQL、SQL Server、PostgreSQL提供了适合个人入门用户的基础版产品,以实惠的价格普惠广大中小用户。阿里云更从企业需求出发,重点在全生命周期、全方位运维、全链路安全、全链路监控、多引擎覆盖 5个方面进行发力,为企业用户提供更优质的云数据库服务。为不同层次的用户提供贴心及高品质的服务,已经成为云计算最核心的价值,期待产业变革为个人及企业用户带来更多体验的提升。 -- 我们为之努力!
作者: 萧少聪scott
原文链接
本文为云栖社区原创内容,未经允许不得转载。
大数据
2018-12-20 14:31:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
【编者按】2018年12月20日,云栖社区3周岁生日。阿里巴巴常说“晴天修屋顶”,所以我们特别策划了这个 专辑 ——分享给开发者们20个阿里故事,50本书籍。第一位是林昊(毕玄)。
在这篇《程序员的成长路线》里,阿里基础设施负责人毕玄结合自己的经历跟大家讲述了他在各个角色上成长的感受。在他的职业经历中,在成长方面经历了技术能力的成长、架构能力的成长,以及现在作为一个在修炼中的技术 Leader 的成长。其中技术能力和架构能力的成长是所有程序员都很需要的,值得所有正为职业发展而迷茫的技术同学细细品味。
技术能力成长
我大学读的是生物系,缺少了专业的训练,这个使得我在技术能力上其实欠缺的更多。回头想想,在工作的前5年,更多的都是在拓宽技术面,刚毕业的时候只会 ASP,工作前两年学会了 VB、Delphi这些神器,到工作的第三、四年比较专注的做了工作流领域。
技术能力的成长主要还是在 2007 年加入阿里以后,在加入阿里前,我是一个连日均访问量 1万 PV 都没见过的人,到了阿里后,做的第一件事竟然就是写 HSF,并且在客服的 CRM 系统上线,访问量大概是每天上百万的服务调用,无知者无畏,当时也就那么上线了,更神奇的是竟然没出现什么问题,于是继续把HSF上线到当时的交易中心,当时交易中心每天的服务调用量大概是亿级,结果上线当天就回滚了,而且还不知道到底是什么原因,这次的回滚是对我触动最大的一次(当然,触动大也有可能是后面要是解决不了,就该从淘宝滚蛋了)。
回滚后开始仔细查问题,最后发现是当时 HSF 所使用的 jboss-remoting 默认的超时参数 60s 的问题,自从这个问题后,才明白要支撑好到了一定量级的系统,最重要的是对整个技术栈的精通,否则出问题都不知道该怎么解决或临时查,于是才开始仔细学习 Java 的 BIO/NIO,Mina,反射,并发编程等,尽管这些东西很多在加入阿里前也看过一些书、资料学过,但到了这个时候才发现自己其实不怎么懂,那段时间密集的开始更细致的看书,翻看用到的 Mina、甚至是 Java 的各种 API 背后的源码,是自己的 Java 技能提升最快的一段时间,在回滚的两个月后,基于 Mina 完全重写了 HSF,再次上线终于一切顺利。
在那之后,随着 HSF 应用的场景越来越多,以及加上后来自己在淘宝消防队查比较多的问题,Java 方面的技能也得到了不少成长,而同时也发现了很多的 Java 问题还得对 JVM、操作系统层面有一定掌握才行,尤其是 JVM,于是当时和还在阿里的撒迦经常一起周末跑到公司来结对看 JVM 代码,:)。在撒迦的帮助下对 JVM 的掌握终于也越来越好,那段时光会让自己明白很多东西只有看了代码,并且有相应的使用机会才能真正的掌握。
在 HSF 之后,去做 HBase,学习了很多在存储方面的技能,这也是我之前完全不懂的领域,在HBase之后,开始做第一代容器产品 T4(寓意是第四代淘宝技术),进入彻底不懂的领域,虚拟化、Cgroup 等等都是那个时候才开始学习,但因为没详细研究过代码,并自己去做改造,其实到今天也就是点皮毛而已。
对于程序员而言,技术能力的成长显然是最重要的(程序员行当里最赞的一句就是:Talk is cheap, show me the code!),我自己其实很多都属于被逼的成长,当然这样通常反而也是最快的,很多同学会觉得自己没碰到这样的机会,所以成长就比较慢,我会非常建议的是可以尝试自己去创造一些场景(当然,如果本来就是工作需要就更好了),来学相应的技术能力(例如学 Java 的通讯框架,可以尝试自己基于 BIO/NIO 写一个,然后对比 Mina/Netty 这些成熟的,看看为什么写的不太一样,又例如学 Java 的内存管理,可以尝试自己写程序去控制 GC 的行为,例如先来一次 ygc,再来两次 fgc,再来 5 次 ygc,再来一次 fgc之类的,学的时候除了一些入门的书外,我非常建议去翻看源码,最后你会发现所有的书都不如源码),这样才能真正的理解和学会,否则其实很容易忘。
架构能力成长
说起架构,在我刚工作的第三年负责工作流系统的时候也做过,但直到后来在阿里做 T4、异地多活,我才有了真正更强烈的感受,对架构师也有更深的一些理解。架构呢,我现在的理解基本是一个结构图,当然有不同视角的结构,但这个图里的部分呢是多个团队来做的,甚至是跨多个专业的团队。
在做 T4 的时候,由于 T4 涉及到了标准的一个 Java WebConsole,一堆的运维体系,容器技术等,这是一个至少要跨三个团队的结构,无论是从研发视角还是部署视角都是如此,因此作为 T4 的架构师,怎么设计好整个的结构,各自的边界、接口是我当时最大的感受,让跨专业的多个团队能更好的协作,在这个阶段中最重要的要考虑的是怎么根据整个项目的优先级来调整每个部分,以及作为一个不是全懂的架构师怎么更好的确保结果,我自己的感受是 T4 让我学会了从一个只做自己专业系统的架构师成长为了能做跨专业的系统的架构师。
在做异地多活的时候,感受就更加强烈,因为这个跨的专业数、整个参与的人数完全是上升到了一个非常大的程度,各个专业、系统的人都需要看整个架构才能知道自己应该做什么,扮演的角色,在做异地多活整个项目过程中,作为总的架构师,我自己感觉的是最重要的职责是怎么控制项目的风险,或者说作为架构师,你觉得一个项目中最重要的要掌控住的是,并且从架构上怎么设计这个部分,这也是后来我在问很多架构师时最喜欢问的问题,一份架构文档不是说按照模板写就可以(很多的架构设计文档都是千篇一律,通常看到的都是什么都考虑,但从架构设计上并没体现这些考虑的地方是怎么做的),而是要根据实际的项目/产品情况来突出重点,确保最重要的几个问题是从架构设计上就去掌控的,尤其是跨多个专业团队的大型项目,这种项目准确的说是大架构师带着一堆的专业领域的架构师来做的,例如异地多活项目从架构设计上来说除了正常的结构、边界以外,最重要的是数据正确性的设计,我自己最强的感受就是异地多活才让我明白了一个大型系统的架构师是怎么样的。
所以就我自己的感受而言,架构师对知识的宽要求非常广,并且要能非常好的进行抽象,来做结构、边界的设计,分析出当前阶段系统的重点,并从架构层面做好设计来确保重点的实现,这个相对技术能力的成长而言我觉得更需要机会,但同样在机会前需要有足够的积累(例如写一个系统的时候,是不是主动的去了解过上下游的系统设计,是不是了解过具体的部署结构,对相应的知识点有没有简单的了解等,我自己在做 T4 前,LVS、机房/网络结构等完全搞不懂是怎么回事)。
技术Leader修炼
技术 Leader 我比较倾向于有前面两步积累的同学,技术 Leader 非常重要的一点是对技术趋势的感知和判断能力,这其实是个非常综合的能力,一到两个领域的技术深度,大的架构能力,对技术历程的理解、技术发展的思考能力,作为技术 Leader 是很需要的,然后是其他的一些作为 Leader 方面的比较综合的一些能力(例如组织搭建、建设方面的能力等,不过这些能力呢通常对技术的人来说确实会欠缺的更多一些),这个我自己还在修炼和学习中,就不讲太多了。
总结
总结来说呢,我认为程序员可发展的路线还是很多的,上面写的这三条其实都是可发展的路线,没有孰优孰劣,谁高一等之类的,兴趣、个人优势仍然是最重要的。
作为《OSGi原理与最佳实践》和《分布式Java应用:基础与实践》的作者,毕玄推荐了他的书单给到我们: 《硅谷之谜》
《智能时代:大数据与智能革命重新定义未来》
原文链接
大数据
2018-12-20 10:09:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
MaxCompute表设计最佳实践
产生大量小文件的操作
MaxCompute表的小文件会影响存储和计算性能,因此我们先介绍下什么样的操作会产生大量小文件,从 而在做表设计的时候考虑避开此类操作。 使用MaxCompute Tunnel SDK上传数据,上传过程中,每commit一次就会产生一个文件。这时每 个文件过小(比如几K),并且频繁上传(比如5秒上传)一次,则一小时就会产生720个小文件,一 天就会产生17280个小文件。 使用MaxCompute Tunnel SDK上传数据,create了session但是没有upload数据直接做了 commit,产生大量空目录(服务侧等同于小文件)。 使用MaxCompute Console命令行工具Tunnel命令上传时,将本地大文件切分过小,导致上传后产 生文件数过多,文件过小。 通过DataHub做数据归档,Datahub 的每个shard写 MaxCompute 有两个条件:数据总量达到 64MB,commit 一次到 MaxCompute,形成一个文件。或者每隔 5 分钟一次 commit,形成一个 文件。那么:开的shard数多(比如20个shard),每个shard数据在5分钟内都远远达不到64M,比 如就是几百K,就会产生大量小文件。那么一天就会产生241220=5760个小文件。 通过Dataworks等数据开发工具进行数据增量插入(insert into)到MaxCompute的表(或者表分 区)里时,每个insert into都会产生一个文件,若每次insert into 10条,每天累计insert insert 10000条记录,则会产生1000个小文件。 通过阿里云DTS将数据从RDS等数据库同步到MaxCompute,DTS进行数据同步时,会创建全量表和 增量表,增量表进程数据插入过程中会因为每次数据插入条数较少而commit比较完整一次数据同步, 从而在增量表中造成小文件问题,比如每隔5分支执行一次同步,每次同步的数据量为10条,一天内的 增量为10000条,则会产生1000个小文件。此种场景,需要在数据同步完成后进行全量极限表和增量 数据表的merge。 源数据采集客户端太多,源数据通过T unnel直接进入到一个分区,每个源数据采集客户端提交一次数 据,都会在同一分区下产生一个独立的文件导致产生大量小文件。 SLS 触发 FunctionCompute持续高频往MaxCompute中心接入文件,小文件流式数据进入 MaxCompute。
根据数据划分项目空间
项目空间(Project)是MaxCompute最高层的对象,按项目空间进行资源的分配、隔离和管理,实现了 多租户的管理能力。 如果多个应用需要共享“数据”,则推荐使用同一个项目空间。 如果多个应用所需“数据”是无关的,则推荐使用不同的项目空间。 项目空间间的表和分区可以通过Package授权的方式进行交换。
“维度表”设计的最佳实践:
一般情况下描述属性的表设计为维度表。维度表可以和任意表组的任意表进行关联,并且创建时不需要配 置分区信息,但是对单表数据量大小有所限制。维度表的设计和使用注意以下几点: 一般要求维度表单表不超过1000万。 维度表的数据不应该被大量更新。 维度表和其他表进行Join操作时可以使用mapjoin。
拉链表设计 – 极限存储的应用
极限存储功能待发布,在此介绍主要提供设计思想。 基于MaxCompute的拉链表设计背景 在数据仓库的数据模型设计过程中,经常会遇到这样的需求: 数据量比较大。 表中的部分字段会被update,如用户的地址,产品的描述信息,订单的状态、手机号码等等。 需要查看某一个时间点或者时间段的历史快照信息。(比如,查看某一个订单在历史某一个时间点的 状态,比如,查看某一个用户在过去某一段时间内,更新过几次等等) 变化的比例和频率不是很大,比如,总共有1000万的会员,每天新增和发生变化的有10万左右,如果表每天都保留一份全量,那么每次全量中会保存很多不变的信息,对存储是极大的浪费。
考虑极限存储的使用 : MaxCompute提供了将不同表转化为极限存储表的能力。极限存储操作示例如下: 创建源表。 create table src_tbl (key0 STRING, key1 STRING, col0 STRING, col1 STRING, col2 STRING) PARTITIO N (datestam p_x STRING, pt0 STRING); 导入数据。 将src_tbl转变为极限存储的表。 set odps.exstore.primarykey=key0,key1; [set odps.exstore.ignorekey=col0;] EXSTO RE exstore_tbl PARTITIO N (datestam p_x='20140801'); EXSTO RE exstore_tbl PARTITIO N (datestam p_x='20140802');
拉链表设计更详细介绍可以参考云栖文章: https://yq.aliyun.com/articles/542146#? spm=a2c41.11181499.0.0
采集源表的设计
数据采集方式:流式数据写入, 批量数据写入,周期调度条式数据插入。
大数据量情况下,确保同一个业务单元的数据使用分区和表进行分;在数据量较小情况下,优化采集频率。 流式数据写入。 对于流式写入的数据,一般采集的通道较多,相关采集通道应做有效区分,在单个数据通道写入 量较大的情况下应该进行按照时间进行分区设计。 在采集通道数据量较小的情况下可以采取非分区表设计,对终端类型和采集时间设计成标准列字 段。 采用Datahub进行数据写入时应该合理规划shard数量,放置由于shard过多而造成采集通道流量 较小且通道较多的问题。 批量数据写入。批量数据写入重点关注写入周期 周期调度条式数据插入。 避免周期数据插入,此种情况下需要建立分区表,在新分区进行插入操作, 减少对于原来分区影响。
日志表的设计
日志其实是个流水表,不涉及记录的更新,来一条采集一条,多条一起存放,日志表设计的主要注意几 点: create table src_tbl (key0 STRING, key1 STRING, col0 STRING, col1 STRING, col2 STRING) PARTITIO N (datestam p_x STRING, pt0 STRING); set odps.exstore.primarykey=key0,key1; [set odps.exstore.ignorekey=col0;] EXSTO RE exstore_tbl PARTITIO N (datestam p_x='20140801'); EXSTO RE exstore_tbl PARTITIO N (datestam p_x='20140802'); 考虑是否需要对日志进行去重处理。 考虑是否需要扩展维度属性。 是否需要关联维表扩展维度属性字段考虑两点:业务使用的频次,关联是否会造成的产出的延 迟。 需要仔细选择是否对于维度表进行扩展 考虑区分终端类型。 日志表由于量大,考虑在业务分析使用时通常会按PC端,APP端来统计分析,同时PC端、APP端 的采集是两套体系,因此通常的做法会按终端设计多个明细DWD表。 如果终端较多,但数据量不大的情况下,如一个终端的数据小于1T 但是采集次数较多,可以考虑 不对终端进行分区,而设置终端信息为普通列。
注意: 对于日志表进行分区设计,可以按照日志采集的时间按照天进行分区,在入数据前进行数据采集整 合,一批数据写入提交一次(通常是64M)。 日志数据很少有对原来分区的更新操作,可以采用insert 进行少量数据的插入,但一般需要限制插入 次数。 如果有大量的更新的操作,需要采用insert overwrite操作避免小文件问题。 对日志表设置合理的分区和对已经⻓久不访问的冷热数据配置归档操作。
互动明细表的设计
周期快照表,每天对收藏的所有记录进行快照存放。
问题 :历史累计的记录非常多,每天生成快照要拿当天增量表与前一天的全量表merge,非常耗资源。统 计最近1天的新增收藏数,需要扫描全量表,如何降低资源?
建议的方案 :建立一个事务性事实表,在建立一个存放当前有效收藏的周期快照表,以满足各种不同业务 的统计分析需要。
注意 : 设计互动明细表最重要的是要区分存量数据和增量数据之间的关系。 - 对于新分区的数据可以写入,作为增量数据。 应尽量减少对于老的分区数据的修改和插入。 在数据插入和全表覆盖写种选择时应尽量选用insert overwrite而并选择insert into。
MaxCompute表数据更新与删除操作
关系型数据库支持的 delete/update/merge SQL ,在MaxCompute上的实现方式示例如下:
表准备 -- 上日全量表 table1(key1 string,key2 string,col1 string,col2 string); -- 今日增量表 table2(key1 string,key2 string,col1 string,col2 string); ​-- 今日增量表(删除) table3(key1 string,key2 string,col1 string,col2 string);
update(table2 表中的记录的值,更新到table1表中) insert overwrite table table1 select t1.key1 ,t1.key2 ,case when t2.key1 is not null then t2.col1 else t1.col1 end as col1 ,case when t2.key1 is not null then t2.col2 else t1.col2 end as col2 from table1 t1 left outer join table2 t2 on t1.key1=t2.key1 and t1.key2 = t2.key2 ;
delete(table2 表中的记录,从table1表中删除) insert overwrite table table1 select t1.key1 ,t1.key2 ,t1.col1 ,t1.col2 from table1 t1 left outer join table2 t2 on t1.key1=t2.key1 and t1.key2 = t2.key2 where t2.key1 is null ;
merge(没有del) insert overwrite table table1 select from ( -- 先把上日存在,今日也存在的记录从上日表中排除。剩下的就是今日没有更新的记录 select t1.key1 ,t1.key2 ,t1.col1 ,t1.col2 from table1 t1 left outer join table2 t2 on t1.key1=t2.key1 and t1.key2 = t2.key2 where t2.key1 is null union all -- 再合并上今日增量,就是今天的全量 select t2.key1 select t2.key1 ,t2.key2 ,t2.col1 ,t2.col2 from table2 t2)tt ;
merge(有del)
insert overwrite table table1 select
from (
-- 先把上日存在,今日也存在的记录从上日表中排除,再把今日删除的记录排除。剩下的就是今日没有更 新的记录 insert overwrite table table1 select from ( -- 先把上日存在,今日也存在的记录从上日表中排除,再把今日删除的记录排除。剩下的就是今日没有更 新的记录 select t1.key1 ,t1.key2 ,t1.col1 ,t1.col2 from table1 t1 left outer join table2 t2 on t1.key1=t2.key1 and t1.key2 = t2.key2 left outer join table3 t3 on t1.key1=t3.key1 and t1.key2 = t3.key2 where t2.key1 is null or t2.key1 is null union all -- 再合并上今日增量,就是今天的全量 select t2.key1 ,t2.key2 ,t2.col1 ,t2.col2 from table2 t2)tt ;
表创建设计示例
场景:天气情况信息采集。 基本信息: 数据信息包括地名,关于此地的属性数如面积,基本人口数量等信息,天气信息。 属性数据变化较小,天气信息数采用多个终端采集,且数据量较大 天气信息变化较大,终端数量稳定的情况下流量基本稳定。
表设计指南: 建议对数据信息划分为基本属性表,和天气日志表,区分变化小和变化大的数据。 因为数据量巨大,对天气日志表按照地域进行分区,也可以按照时间如天进行二级分区,此种分区方 式避免因某一地或某一个时间的天气变化而造成其他无关数据变化。 采集终端上使用datahub进行数据汇聚,依据稳定的流量值选择合适的shard通道数量,批量数据方式 写入到天气日志表中,不使用Insert into。
MaxCompute表的特色功能
生命周期
MaxCompute表/分区提供数据生命周期管理。表(分区)数据从最后一次更新时间算起,在经过指定的 时间后没有变动,则此表(分区)将被MaxCompute自动回收。这个指定的时间就是生命周期,生命周期 设置为表级别。 create table test_lifecycle(key string) lifecycle 100;/alter table test_l ifecycle set lifecycle 50;
MaxCompute会根据每张非分区表或者分区的的LastDataModifiedTime以及lifecycle的设置来判断是 否要回收此非分区表或者分区表中的分区。 MaxCompute SQL提供touch操作用来修改分区的 LastDataModifiedTime。会将分区的LastDataModifiedTime修改为当前时间。修改 LastDataModifiedTime的值,MaxCompute会认为表或分区的数据有变动,生命周期的计算会重新开始。 ALTER TABLE table_nam e TO UCH PARTITIO N(partition_col='partition_col_valu e', ...);
注意: 合理规划表的生命周期,在创建表时即设置生命周期,可有效减少存储压力。 对表数据的任何变动都会影响生命周期回收数据的判断时间,包括小文件合并。
避免全表扫描
表设计: 建立分区表或者对扫描条件进行列设计。 对数据表进行合理分区。 对常用查询条件设置成列名。 读常用查询条件进行hash clustering
数据计算: 加分区过滤条件,或者减少扫描分区数,或者拆出中间小表然后再扫描小表的历史分区以减少数据扫描 量。 把全局扫描表中间结果进行存储形成中间表。 如果每天都去扫一年的分区,计算消耗是非常大的,建议拆出一张中间表,每天做一次汇总,然后再 去扫描这张中间表的一年分区,扫描数据量会减少很多。
避免小文件 Reduce计算过程产生的小文件:只需要insert overwrite源表(或分区)即可,或者写入到新表删除 源表。 Tunnel数据采集过程中产生的小文件建议: 调用tunnelsdk时当buffer达到64M时提交一次; 使用console时避免频繁上传小文件,建议积累较大时一次性上传; 如果导入的是分区表,建议给分区设置生命周期,过期不用的数据自动清理; 同第一种方案,insertoverwrite源表(或分区); ALTER合并模式,通过console命令进行合并。 使用临时表建议创建时都加上生命周期,到期后垃圾回收自动回收。 - 申请过多的datahub shard将会产生小文件问题,申请datahub shard数目的策略 : 默认吞吐量单个shard是1MB/s,可以按照这个分配实际的shard数目(可以在此基础上多加几 个); 同步odps的逻辑是每个shard有一个单独的task(满足5分钟或者64MB会commit一次),默认设置5分钟是为了尽快能在odps查到数据。如果是按照小时建partition,那个一个shard每个小 时有12个文件。 如果这个时候数据量很少,但是shard很多,在odps里面就会很多小文件(shard*12/hour)。 不要过多的分配shard,按需分配。
转化Hash Clustering表
Hash Clustering表的优势:优化Bucket Pruning/优化Aggregation/优化存储。 在创建表时使用CLUSTERED BY指定Hash Key,MaxCompute将对指定列进行Hash运算,按照Hash 值分散到各个Bucket里面。
Hash Key指选择原则: 选择重复键值少的列 SORTED BY用于指定在Bucket内字段的排序方式。
如何转化为HashClustering表: ALTER TABLE table_nam e [CLUSTERED BY (col_nam e [, col_nam e, ...]) [SO RTED B Y (col_nam e [ASC | DESC] [, col_nam e [ASC | DESC] ...])] INTO num ber_of_buck ets BUCKETS]
ALTER TABLE语句适用于存量表,在增加了新的聚集属性之后,新的分区将做hash cluster存储。 创建 完HashClustering的表之后使用insert overwrite从另外一个源表进行转化。
注意,Hash Clustering表有以下限制: 不支持insert into,只能通过insert overwrite来添加数据。 不支持tunnel直接upload到range cluster表,因为tunnel上传数据是无序的。
原文链接
大数据
2018-12-19 17:32:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
概述
最近,Amazon新推出了完全托管的时间序列数据库Timestream,可见,各大厂商对未来时间序列数据库的重视与日俱增。
阿里云TSDB是阿里巴巴集团数据库事业部研发的一款高性能分布式时序时空数据库,在即将过去的2018年,我们对TSDB进行了多次的系统架构改进,引入了倒排索引、无限时间线支持、时序数据高压缩比算法、内存缓存、数据预处理、分布式并行聚合、GPU加速等多项核心技术,并且引入了新的计算引擎层和分布式SQL层,使得引擎核心能力有了质的提升,也基本上统一了集团内部的监控存储业务。2018年双11当天,TSDB稳定运行,0故障,支撑双十一核心业务系统,毫秒级采集能力,具备双十一峰值写入不降级,创造了集群TPS 4000万、QPS 2万的新纪录。同时,面向IOT赛道,推出了时空数据库和边缘计算版本,还会引入面向时序时空场景的智能引擎,未来我们的目标是把TSDB打造成一款业内领先的“智联网数据库”。
2018双十一数据
首先,我们来看一下TSDB在2018年双十一的答卷:TSDB承受了4000万/秒的峰值写入,2万/秒的峰值查询,与2017年双十一相比均翻倍增长;而写入均值也达到了2600万/秒,查询均值达到了8000次/秒。

场景
下面几页Slide是我们在外部的一些场景和客户案例:

核心技术解析
为了更好的支持业务的需求,今年我们在核心引擎层面做了非常多的优化和改进,我们还引入了新的计算引擎层,分布式SQL引擎,时空引擎以及面向IoT市场的边缘计算版本,极大的提高了TSDB的计算能力和场景。下图就是TSDB的主要架构图,接下来的篇章我会分时序引擎,计算引擎,SQL引擎,时空引擎,边缘计算这5大部分来详细的介绍我们的核心技术能力。
一、时序引擎
问题挑战
稳定性、流量翻倍、不降级、低延迟、无限时间线
1. 复杂时间线索引、无限制时间线支持:
问题
为了支持多维查询和聚合查询,TSDB使用了倒排索引以快速定位到某条时间线。在TSDB现有的实现里,倒排索引是全部存放在内存中的。该方案的好处是根据某个Tag或者Metric查找时间线时会非常高效,但是缺点也非常明显:受限于内存大小,TSDB无法支持大规模的时间线。随着TSDB的客户越来越多,这个问题也越来越突出:某直播业务要求TSDB能够支撑20亿时间线的规模;某监控业务虽然初始时间线只有上千万,但是每天会新增几十万条时间线,而且时间线规模没有上限。
方案
TSDB在之前全内存倒排索引的基础上,将倒排索引持久化到硬盘,赋予了TSDB支撑无限时间线的能力。同时,通过给予倒排索引时间的概念,我们将查询的时间过滤算子下推到了索引查询阶段,进一步优化了查询性能。而通过创建时间线索引的BloomFilter,TSDB保证了海量时间线规模下的低延迟索引查询。

效果
拿集团内业务举例,原来64G内存的机器只能支持到不到500万的时间线,采用了上面的技术方案后,64G内存的机器就可以支持业务将近7000万以上的时间线,而且时间线数量在原有机器的基础上还可以继续增加。
2. 高效列式内存缓存、时间线内存分片:
为了加速数据的写入和查询能力,今年我们为TSDB设计了全内存的分布式高效缓存,具体架构图如下:
效果
最终我们测试效果是:在单个docker下,单机TPS从原来的50W提升到100W+,QPS从原来的1K提升到2K+ ;并且这个改进很好的支持了集团魔兔业务的需求和发展。
3. 工作负载管理:
为了更好的解决数据量大的情况下的负载均衡的问题,我们做了许多工作,主要包括: 通过读写分离机制进一步提升写入和查询性能; 快慢查询自动分级,让慢查询不再拖累其他查询; 自动限流保护,无需业务方降级,无惧双十一洪峰。
效果
双十一结果证明,新的负载管理策略帮助业务方非常平滑的度过了流量洪峰。
4. 时序全新存储引擎——Lindorm:
这里需要提到的另外一点是,TSDB时序最新架构采用了Lindorm作为存储引擎,能够以更少的机器成本提供更高的吞吐、更低的延迟。下图为采用Lindorm存储引擎前后的TSDB写入延迟。
5. 聚合器
丰富的流式聚合算子:15+聚合,10+填充策略,支撑大量的adhoc操作:groupby, in,not_literal_or, topN, limit等等;支持不规则时间序列数据的处理,TSDB提供的填值策略,可以很轻松地将不规则的时间序列转换为常规时间序列进行处理;支持top-bottom等聚合方式。
6. 混合存储记录块
时序数据存储的记录块方式是其查询性能的基石。TSDB既支持基于时间线的存储方式,
同时支持基于窗口的数据记录切分,复用同一套流式聚合,满足不同业务场景性能需求。
7. 服务化
TSDB服务目前已经在阿里云上出售,目前提供小规格版本以及标准规格版本,满足了很多用户的需求,但依然有一些用户希望提供更小规格的TSDB服务。为了更好满足用户的需求,TSDB提供服务化功能。服务化功能是通过多个用户共享一个TSDB集群的方式来提供更小规格的TSDB服务 数据安全:HTTPS支持,用户认证 并发管理:写入并发管理,查询并发管理 性能管理:写入性能管理,查询性能管理 使用量管理:数据点管理,时间线管理
时序引擎接下来会继续突破核心技术,包括: 自驱动索引TPI,多值数据模型,时序算法,内存计算等等。 从功能,性能,成本,生态方面进一步发力,打通 K8S指标存储体系, 具备兼容Prometheus的能力。
二、 时序计算引擎TSCE
业务接入量快速突破的过程中, 也带来了数据存储量级与查询复杂度的快速增长, 单TSDB实例 在存储与计算方面的技术挑战也面临跳跃式提升. 为了避免查询性能逐渐偏离用户设定的目标, TSDB的架构演进过程也引入相关的创新机制, 并最终延伸出时序产品体系中的新成员 - 时序计算引擎(TimeSeries Computing Engine, TSCE).
时序计算引擎(TSCE) 定位为对TSDB中原生数据进行流式计算的独立组件, 在时序产品体系中与时序数据库(TSDB)紧密结合, 提供诸如时序数据降采样(DownSample), 时间维度预聚合, 时间线降维归档 等涵盖时序数据查询与存储相关的核心计算能力.
同时, 针对应用特定的应用型时序计算场景, 时序计算引擎(TSCE) 亦支持自定义计算规则与函数, 满足各类应用自身的特定业务需求. 常见的应用型时序计算场类型: 时序事件告警, 事件模式匹配, 时序异常分析与检测等.
TSCE的产品形态如下:
时序计算引擎(TSCE)作为独立组件进行部署, 用户需要在TSDB实例的基础上根据成本与应用需求选择是否开启TSCE时序计算处理. 在这种产品形态下, 用户可以独立调整TSDB的存储规格 和 TSCE的计算容量, 做到根据应用特点弹性调整各自组件的实例规模. 在满足应用要求的情况下将TSDB/TSCE实例部署成本控制在合理区间.
TSDB与TSCE结合之后, TSDB引擎会在数据入库过程中同时让TSCE引擎感知数据流动, TSCE会基于配置的时序计算能力或业务规则对数据流进行计算与分析, 计算后的结果支持三种反馈形式: 1.直接反馈至TSDB存储层,供TSDB查询. 2.作为视图以API或者SQL方式访问. 3.通过Reactive机制投递给其他事件处理渠道.
时序计算引擎TSCE 支持通过 TS-API 或者 Web控制台 进行时序计算能力/自定义规则的配置.
(1) 时序计算
TSDB与TSCE协作工作时, 针对核心的时序计算能力, TSCE会与TSDB的进行无缝集成. 此时核心的时序计算处理对于TSDB终端用户而言是透明,无感知的执行过程. 用户开启并配置TSCE处理后, 原来的数据查询方式与查询格式不变, 整个计算的处理完全在后台自动执行.
在查询层面上, 通过TSCE提供的时序计算处理, TSDB会在尽可能的情况下将查询经过TSCE处理的计算结果.即使是在海量数据场景下, 也能提供时序数据的秒级分析查询与时间维度钻取查询.
而在数据存储层面上, 随着时间线的流逝, TSCE会对原生历史数据进行降维计算, 将细粒度的时间点逐步转化为粗粒度的时间点归档存储(例如秒级数据点转化为分钟级数据点), 进一步控制TSDB中存储空间与资源的使用量, 使得TSDB的稳定性与性能波动处于可控范围. 通过TSDB与TSCE结合, TSDB中管理的数据体量可以控制在合理水平, 提升资源占用率的同时进一步节省产品使用成本. 数据流预聚合
诸如max/min/avg/count/sum等常见的 可累加式 状态值, TSCE可以在数据流动过程中即完成相关数据的统计与计算.
时间线计算
针对时间线(TimeSeries)的窗口粒度,数值分布等特征关系, 对时间线进行特征值转换的计算过程. 例如降采样(Dowmsampling)运算可以将秒级时间线转化为分钟级时间线, 经过转化后的时间线可以在查询流程上支持时间维度上下钻的即席查询; 而在存储流程上, 可以支持时间线归档存储, 将原始细粒度时间线转化为粗粒度时间线后,清除原始的数据点,释放相关资源.
(2) 时序流处理
针对应用特定的应用型时序计算场景, TSCE通过引入自定义计算规则与函数, 来满足各类应用自身的特定业务计算需求. 用户在经过简单的规则配置后, TSCE引擎会负责底层的数据流打通, 流计算拓扑映射, 分布式节点间的Shuffle与结果归并, 计算后结果集的存储与投递等一系列动作细节.
与General-purpose的流计算处理相比, TSCE的时序流处理除了实现降低技术门槛之外,做到底层流计算能力的弹性扩展之外, 也提供几个核心能力: 时序数据库的紧密集成: 因为TSCE与TSDB部署在相同的内部环境内,TSCE可以在非常低的成本下做到与TSDB做数据交换,并且可以直接访问到TSDB后端的数据存储层. 与常规应用方案中 需要先经过流处理再写入时序存储产品的架构相比, 引擎间的紧密集成可以做到效率,成本,性能的成倍提升. Reactive查询视图: 流处理后的结果集除了写回TSDB中存储之外, TSCE也支持将数据流转储为Reactive查询视图. Reactive查询视图除了可以支持以SQL/API方式查询结果之外, 也可以通过指定Subscriber订阅相关数据流更新, 当结果集在视图中产生变动时, TSCE会投递数据变更事件至相关Subscriber指定的渠道中(适合监控告警以及自动化处理等业务).
时序流处理规则
定义一个流处理规则包含了3个元素: 1.数据源(TSDB中的时间线), 2.自定义计算规则, 3.计算结果的输出源;其中数据源来自于TSDB数据库, 业务方可以通过规则匹配1条或多条时间线作为数据输入源. 而计算结果的输出源可以是写会TSDB, 或者转储为Reactive视图.
此外用户也可以通过lambda自定义与业务逻辑处理相关的函数, 加入到整体的规则处理链中.
(3) 时序分析与智能引擎
除了配置TSCE的 时序计算能力 与 自定义时序流处理之外, TSCE也提供一些常见的时序分析与智能处理能力:
时序分析
简单的时序流复杂事件处理(CEP): 提供时间线上数据点之间的关系侦测,模式匹配等.
智能引擎
TSCE支持与时序智能引擎进行联通,让用户具备针对时序数据流进行时序异常探测,故障root-cause分析,流式模型训练等相关高级能力. 技术实现上TSCE以Function,DSL等形式进行智能引擎的规则定义与转换, TSCE在数据流的计算过程中会基于内存间数据共享/RPC等方式完成与智能引擎的联动与交互
4. 应用场景
双十一期间, TSCE时序计算引擎支撑的几个典型业务场景: 海量数据下的时间线降维度,预聚合查询 基于阈值的简单事件告警 时序数据的降维归档存储 验证初期的时序分析能力(与智能引擎结合)
三、分布式MPP SQL引擎:
1. 需求
今年我们决定在TSDB上设计开发一个分布式的SQL查询引擎,为什么要这么做呢?主要有以下几个原因: 从简单时序监控到复杂时序分析
TSDB引擎所支持的查询主要是简单的降采样和分组聚合,随着越来越多业务把时序数据存储到TSDB,我们需要提供一个基于SQL的分布式查询引擎,支持更复杂的时序计算(聚合,时序Join, SQL Window function, UDF), 从而推广TSDB到更广泛的业务中。 扩展时序数据库的生态系统
生态系统是一个产品是否成功的关键因素。通过时序SQL查询引擎,TSDB数据库可以和现有的BI tool实现无缝对接。在集团内部,我们正在和阿里云的QuickBI和IDB等团队合作,把TSDB演进成一个支撑重要BI数据分析的数据库产品。未来,通过时序SQL查询引擎,可以对接市场上常见的BI tool, 比如Tableau, Qlik, Power BI等众多工具。 支持多种异构数据源的联合分析
通常,业务把时序相关的数据存储在TSDB,非时序数据存储在其他系统中,比如维度信息存储在MySQL等。业务需要在多种数据中进行Join。时序SQL查询引擎支持业务在多种数据源之间直接进行查询分析,避免业务方复制异构数据源再进行联合分析。 对标业界主要竞争产品
时序数据库在国外最主要的竞争产品包括TimeScaleDB, InfluxDB, KDB+,Prometheus。TimeScaleDB作为Postgres的一个扩展,提供了标准SQL的支持,而InfluxDB/KDB+提供了类似于SQL (SQL-like)的查询支持。我们TSDB系统通过时序SQL查询引擎,更好地对标国外主要时序竞争产品。
2. SQL引擎的挑战
除了海量时序数据带来的挑战外,时序SQL查询引擎还面临和时序场景相关的挑战: 数据table Schema的管理 时序metric数目海量:Sunfire等集团内部业务有上亿规模的时间线,而盒马业务中将tag编码进metric, 时间线数目巨大,这和一般数据库中数千或数万的table是巨大的区别; 时序metric schema动态变化:业务方随着应用的变化,经常需要增加或减少一个tag。这意味着metric所对应的schema也在不断变化之中。海量时间线+动态变化对查询引擎获取metric的schema 是一个挑战。 数据schema-on-write对查询引擎的影响
大多数的数据库在用户写入数据或查询之前,必须先通过DDL创建table schema,这些table schema等元数据又被存放在一个catalog或meta data store, 供数据写入或查询时使用。而时序数据库的业务中,大部分的数据源来自于监控设备的一个agent, 或者IOT物联网的一个sensor, 要求先定义DDL再写入数据会严重影响可用性; 同时,时序metric所对应的tag集合在应用演进过程中,变化很常见。针对这一的应用特点,时序数据库TSDB,InfluxDB, Prometheus都采用了一种'Schema-on-write'的机制,应用直接写入数据,table schema是隐含在数据中。在'Schema-on-write'的机制下,需要解决没有DDL的情况下SQL查询引擎如何从海量时间线中获取table schema等元数据的问题。 时序功能扩展
在现有以关系运算为基础的SQL查询引擎中。为支持时序功能扩展,我们需要一个易于扩展功能的架构,能支持开发时序相关的功能,比如时序Join, 时序相关的用户自定义函数(UDF)。 时序查询优化
一个SQL查询引擎,优化器是性能优劣的关键。需要在通用的SQL查询引擎中,引入时序数据统计信息,作为输入提供给优化器;同时,在优化器中,引入时序相关的优化Rule, 比如FilterPushDown/ProjectPushDown规则,这些都是时序SQL查询引擎需要解决的问题。
3. SQL引擎
SQL查询引擎是一个分布式的系统,其特点: 每个计算节点在系统中是对等的,并没有主从关系, 任何一个节点都可以成为Foreman, 负责SQL查询计划的生成,而其他节点成为worker nodes 无状态,一个节点失效后,可以快速启动备用节点。
4. 应用场景 盒马零售业绩时序数据查询: 业务方需要通过SQL查询TSDB的时序数据,接入业务方的分析图表大屏。此外,业务方需要支持简单的SQL简单查询外,还包括异构多种数据源的join的支持。![image] 云监控:通过提高SQL查询支持,业务方能统一数据访问方式![image]
四、 时空数据库
1. 需求
随着TSDB的业务发展,时序数据库TSDB渐渐走出APM与监控领域,在IoT领域也获得广泛应用。 而由于IoT领域的特性,其中采集到的很多数据不光有时间信息,还有空间信息与之关联。因此时序数据库也需要能够识别和处理空间信息,以便于更好地服务IoT场景。
对于传统的时间序列数据库,比如说OpenTSDB,如果用户想要存储和查询地理坐标信息,往往需要将经度和纬度分开存储,生成独立的时间线。但是使用时想要将两者重新关联起来需要用户做额外处理。另外一种方式则是需要用户自己将地理位置信息进行编码,常见有的GeoHash或者Google S2。然后将编码信息作为时间线信息进行存储。即使这样,用户依旧需要开发时空过滤功能等等。
2. 方案
在IoT场景中,对于地理坐标信息的采集十分普遍。因此在时序数据库的基础上,我们添加了对空间信息的存储和处理能力,使之成为时序时空数据库。TSDB的时空引擎让地理位置信息和时序信息完美结合起来,力争解决着一切关于时序和时空相关的查询分析。
3. 时空处理能力
最新版本的阿里云TSDB支持地理坐标位置信息的直接写入。用户只需要通过新版本的SDK以及Http Restful APIs可以将地理空间信息(地理经纬度)写入,并且可以对经纬度信息进行读取。下面两个通过Http Restful API接口TSDB多值写入和单纯的轨迹查询示例:(注意:Coordinate是一个关键字,表示地理坐标点写入,不可用于其他监控指标名称(metric)。)
说完TSDB对于地理坐标信息最基本的存储和查询功能,我们来看一下TSDB所提供的常用时空分析功能。
对于写入的地理坐标数据点,TSDB将自动生成时空索引提高查询和分析效率。TSDB的时空索引基于传统空间索引(Google S2和GeoHash都是支持)结合时序数据特征创建的时空索引格式。同时为了提高,用户可以根据自己需求在开始使用时空功能之前提前配置时空索引按照时间分片。偏实时的业务,可以将按照小时或者半小时对时空索引进行分片。对于偏分析的场景,可以按照天进行分片。
时空索引为TSDB提供时空过滤分析功能提供了便捷和提高效率,现在最新版本的TSDB支持一些常用的时空过滤功能,比如BBOX查询和DISTANCE_WITHIN查询。
目前TSDB时空功能已经在云上推出了公测版本,大家在官网就可以看到我们时空功能。
4. 下一代时空数据库核心技术全力研发中
针对万亿级,EB级别的时空数据,全团队在全力研发下一代时空数据库,包括新型分布式列式存储引擎,GPU加速,智能压缩,冷热分离,高效时空索引,分布式时空计算等等;
五、边缘计算
今年,为了进一步支持外部IoT市场的需求,我们在TSDB云版的基础上,开发了边缘计算版本( 在广州云栖大会工业物联网专场,正式发布阿里云工业物联网边缘计算平台存储类产品 TSDB Edge,TSDB Edge 主要提供物联网边缘端设备相关数据的本地存储,本地分析,数据清洗和云端数据同步能力。 );

1. 两节点HA 两节点HA通过两个TSDB节点实现HA。两个TSDB节点没有主从的区别,二者都可以接受读写请求,也都可以响应读写服务(不需要转发读写请求)。两个TSDB节点能够同时接受写请求,两个TSDB通过同步WAL日志的方式实现数据同步,保障数据的最终一致性。同时,两节点HA通过WAL与云端同步数据。 两节点HA提供了在边缘设备端TSDB的高可用性,当一个节点发生宕机,另外一个节点能够继续提供服务,宕机节点恢复以后,通过数据同步功能,数据能够在两个节点上迅速实现同步,不会引起非硬盘故障下的数据丢失。
2. WAL日志管理器 实现本地的WAL日志管理,通过WAL日志保证写入的数据不丢失。同时WAL日志管理器,自动判断并删除过期日志文件,减少硬盘空间占用,减轻运维工作。
3. 内存管理器 管理大对象的内存使用情况,通过监控实时内存使用情况,自动判断是否将内存中的数据写入文件系统以减少内存使用。内存管理器根据内存使用情况,自动设置保留的chunks数量,可以减少/杜绝OutOfMemoryError错误的发生。
4. HAServer/HAClient数据同步器 HAClient通过自有的协议,采用PUSH的方式传输WAL。HAServer收到WAL以后,直接通过WAL replay数据插入操作,从而实现数据同步。HAServer/HAClient通过保存读取偏移量的方式,实现断点续传。 CloudSynchronizer云同步器 通过读取WAL,并调用TSDB云版客户端实现向云端同步数据的功能。该同步器对云端透明,同时实现了断点续传。
5. 新型压缩算法 边缘计算提出自研的新型压缩算法,该压缩算法,采用流式压缩方式,支持数据通过append的方式加入,同时在内部采用整字节的方式进行编码,提高压缩/解压性能。
经测试,该新型压缩算法的压缩率为3-40倍。与Facebook Gorilla算法相比,该算法压缩率提高约20%-50%,压缩性能提高3-5倍,解压性能提高4-6倍。
6. GPU硬件加速 边缘计算还在探索与GPU等新型硬件集成。TSDB边缘版使用GPU进行解压,降采样以及聚合操作;
通过测试,使用GPU以后,查询性能可以达到原来的50倍。
六、智能引擎
背景
TSDB 提供了强大的数据存储、处理和查询能力。在这个坚实的基础之上,越来越多的业务场景需要通过挖掘海量数据驱动业务价值的提升,TSDB 智能引擎就是在这个大趋势之下应运而生的。
能力
TSDB智能引擎专注于时序时空数据的分析、检测、挖掘、预测能力,着力打造从数据到知识再到商业价值的高效引擎,争取达到价值链与数据能力的两个全覆盖。
市场上现有的商业智能与数据科学工具往往只利用数据库的存储查询功能,进行数据挖掘和分析之前需要从数据库中提数,之后的流程也脱离数据库环境进行。TSDB 智能引擎从架构上与数据库存储查询引擎进行深度整合,高效的利用数据库现有关系代数能力,并适当引入线性代数计算能力,自然的形成数据闭环,提供一站式的数据科学能力。相信随着不断地努力打造与突破,智能引擎也会逐步沉淀行业数据模型与智能定制算法,并最终形成端到端的行业智能分析解决方案。
限于篇幅,这里就不详细描述了。
八、其他
时序洞察
时序标准
我们在今年8月份也是参与国家的时间序列标准的制定,并且在与其他厂商的竞争中取得优异的成绩。
结束语
2018年,是阿里云TSDB产品成长最快的一年;上文中提到的需要技术和能力目前只是应用在阿里巴巴集团内部的场景;未来,我们会逐步把这些能力开发给外部用户,让外部客户也能享受到阿里巴巴强大的技术实力带来的价值。
最终,我们的目标是把TSDB打造成业内领先的“智联网数据库”!
作者: 焦先
原文链接
本文为云栖社区原创内容,未经允许不得转载。
大数据
2018-12-19 16:58:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
随着数据对生产、生活越来越重要,数据分析也逐渐成为一门显学,在各个领域中都发挥着重要的作用。那么你了解数据分析的发展历史吗?
从国家现状衍生出的统计学,从博诞生而来的概率论,为数据分析奠定了坚实的基础。伴随着各路大神的粉墨登场,数据分析也活色生香起来,从霍乱神医斯诺,到护理之祖南丁格尔,从二战日本的自杀袭击,到一球成名中的”金金“计较的球队经理,从商业智能到公司治理,从大数据到人工智能,数据分析几乎无处不在。
本课程以简单 易懂、风趣轻松的语言科普了数据分析跌宕起伏的发展历程,同时还以自己的切身体会介绍了如何具有数据思维、如何成为数据分析师等,希望对于有志于此的同学能有一定的启发。
课程链接: 阿里云大学——大数据简史
更多精品课程:
阿里云大学官网( 阿里云大学 - 官方网站,云生态下的创新人才工场 )
大数据
2018-12-19 16:34:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 表的限制项 表(Table)设计规范 表设计主要目标 表设计的影响 表设计步骤 表数据存储规范 按数据分层规范数据生命周期 按数据的变更和历史规范数据的保存 数据导入通道与表设计 分区设计与逻辑存储的对应 表和分区设计基本规则 分区设计 分区字段和普通字段的选择 分区字段定义依据 分区个数定义依据 分区数量和数据量建议
表的限制项
表(Table)设计规范 表设计主要目标 降低存储成本。 合适的表设计可以在数据分层设计上降低冗余存储,减少中间表数据量大小。同时正 确的对表数据进行生命周期管理,更能够直接降低存储的数据量以降低存储成本。 降低计算成本。 对表设计规范化,以便在后续对表数据进行查询计算过程中,可以依据这些规范优化 数据的读取,减少计算过程中的冗余读写和计算,提升计算性能的同时降低成本。 降低维护复杂度。 规范化的表分层设计能够直接体现业务的特点。如通过对数据通道中数据采集方式 进行优化,同时对表进行规范化设计,可以减少分布式系统中小文件的问题,同时也减少表和分区维 护的数量等复杂度。
表设计的影响
影响的操作:表创建/入数据/表更新/表删除/表管理。 导入数据场景(区分要做实时数据采集还是离线批 量数据写入): 导入即查询与计算。 多次导入,定时查询与计算。 导入后生成中间表进行计算。
注意: 合理的表设计和数据集成周期管理能够使数据在存储期间降低成本。 - MaxCompute优先作为批量数据集成库以及按业务逻辑进行计算,如按照分区进行计算。 导入后立即查询与计算,需要考虑每次导入数据量,减少流式小量数据导入。 不合理的数据导入及存储(小文件)会对整体存储性能,计算性能,运维稳定性造成影响。
表设计步骤 确定所属项目空间,依据业务过程规划表类型,属于哪个数据层次。 定义表描述,权限定义与Owner定义。 依据数据量、数据集成特点定义分区表或者非分区表。 定义字段,或分区字段 表创建/表转换 明确导入数据场景的相关因素(包括批量数据写入/流式数据写入/条式数据插入)。 定义表和分区数据生命周期。
注意: 表创建之后可以依据业务变化进行表schema的修改,如设置生命周期,RangeClustering。 在设计阶段需要特别注意区分数据的场景(批量数据写入/流式数据写入/周期性条式数据插入)。 合理使用非分区表和分区表。日志表,事实表,原始采集表等建议使用分区表,按照时间分区。 注意各种表和分区的限制条件。
表数据存储规范
按数据分层规范数据生命周期 源表ODS层: 每天从业务系统同步过来的数据,全部保留,生命周期定义永久保存。以防备下游数据 受损时可以从ODS恢复。若ODS每天同步过来的是全量表,可以通过全表拉链的方式来压缩存储。 数据仓库(基础)层: 至少保留一份完整的全量数据(不必像ODS那样冗余多份全量)。考虑到性能 因素,可以考虑拆表或者做分区。 数据集市层: 按需保留1~3年时⻓。数据集市的数据较容易生成,无需保留那么⻓时间的历史数据
按数据的变更和历史规范数据的保存
会变化数据怎么存: 客户属性、产品属性天天变,将这些属性的历史变化情况记录下来,以方便追溯某个时点的值。 在事实表里面冗余维表的字段,即把”事件发生时“的各种维度属性值与该事件绑定起来。 比较方便使 用者,不需关联多张表就可以用数据,在数据应用层使用。 用拉链表或者日快照的形式,记录维表的变化情况。 比较方便数据加工者,数据结构灵活,扩展方 便,容易管理,且数据一致性更好。在数据基础层使用。
数据导入通道与表设计
通道类型: Datahub ,规划写入的分区以及写入流量的关系,做到64M commit一次。 数据集成或DataX,规划写入的表分区的频率,做到64M commit一次,避免commit空目录。 DTS,规划写入的表存量分区与增量分区的关系,做commit频率设置。 Console (Run SQL or Tunnel upload),避免高频小数据量文件的插入或者上传。 SDK Run Sql之insert into,对表或者分区上传时需要注意插入到分区后进行小文件整理操作,避免 对一个分区或者非分区表插入多次,插入后需要merge。
注意: MaxCompute导入数据的通道只有Tunnel SDK或者执行SQL的Insert into,避免流式插入。 以上各通道本身均有自身逻辑进行流式数据写入, 批量数据写入,周期调度写入。 数据通道写表或分区时需要注意将一次写入的数据量控制在合理的值如64M以上。
分区设计与逻辑存储的对应
如上图,表一共m 个一级分区,每个一级分区都会按时间存储二级分区,每个二级分区都会存储所有的 列。 对分区进行设计的注意事项: 分区限制数量上限。 避免每个分区中只有少量数据。 按照分区条件查询和计算。 避免每个分区中多次数据写入。
表和分区设计基本规则 所有的表、字段名要使用统一的命名规范。 要能够区分该表的业务类型。 要能够区分该表是“事实表”或“维度表”,“日志表”,“极限存储表”(待发布功能)。 要能够区分该表的实体信息。 不同表中具有相同业务含义的字段要定义统一的数据类型: 避免不必要的类型转换。 分区设计及使用一般规则: 支持新增分区,不支持新增分区字段。 单表支持分区数量为6万。 对于多级分区的表,如果想添加新的分区,必须指明全部的分区值。 不支持修改分区列列名,只能修改分区列对应的值。修改多级分区的一个或者多个分区值,多级 分区的每一级的分区值都必须写上。
分区设计
分区字段和普通字段的选择
分区字段的作用: 方便数据的管理 。 划分数据扫描范围。
创建表的时候,可以设置普通字段和分区字段。在绝大多数情况下,可以把普通字段理解成数据文件的数 据,而分区字段可以理解成文件系统的目录。 表的存储空间的占用是普通字段的空间占用 。 分区列虽然不直接存储数据,但是如同文件系统里的目录,方便数据管理,同时在计算时若指定具体的分 区,计算过程中只查询对应分区,从而减少计算输入量。 分区表的分区列的个数不能超过6级,也可以理解成底层存储数据的目录层数不能超过6层。对分区表设置 合适的生命周期,可以按照分区细粒度做到对部分数据进行周期管理。
注意: 可以从数据管理范围和常用的数据扫描范围考虑将对应字段设置成分区字段。 对于不具备规律或者类型数量大于10000且不经常作为查询条件的字段设置成普通字段。
分区字段定义依据
按优先级高低排序: 区列的选择应充分考虑时间因素,尽量避免对于存量分区进行更新。 如果有多个事实表(不包括维度表)进行join,查询条件where范围的列作为分区列。 选 择group by 或distinct 包含的列作为分区列。 选择值分布均匀的列,不要选择分区倾斜的列作为分区列。 常用SQL包含某列的等值或in查询条件,选择该列作为分区列。
例如: Select ... from table where id=123 and ....;
分区个数定义依据 时间分区:可按天进行分区或者按月进行分区,如按照小时进行分区,二级分区平均数量不应大于8 个。 地域分区:省,市,县进行分区,考虑进行多级分区。23个省,5个自治区,4个直辖市,2个特别行 政区;50个地区(州、盟);661个市,其中:直辖市4个;地级市283个;县级市374个;1636个县(自治县、旗、自治旗、特区和林区),按照最细粒度县级进行分区后更细粒度不应再按照小时进行 分区。 单分区下的数据建议64M数据提交一次。如果为多级分区,保证每个最细粒度级分区下的二级分区的 数据都是按照这个规则。 单表分区数(包括下级分区)不能超过6万。
分区数量和数据量建议
在计算的时候可以使用分区裁剪是分区的优势。 建议单个分区中数据量不要太大,如可以单个分区中数据在1万条,但是建了5万个分区。 应尽量避免分区数据倾斜,单个表不同分区的数据量差异查过100万以上。 做分区设计时应合理规划分区个数,较细粒度的分区在跨分区扫描时会影响到SQL的执行性能。 单个分区中数据量较大的情况下,MaxCompute执行任务时会做分片处理不影响分区裁剪的优势。 单个分区中文件数较多时,会影响MaxComputeInstance数量,造成资源浪费和SQL性能的影响。 采用多级分区,先按日期分区,然后按交易类型分区。 拆表,一种交易类型就独立成一张表,再每张表按日期分区。 维度表不做分区。
原文链接
大数据
2018-12-19 15:19:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 该文已加入开源项目:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目,Star 数接近 16k)。地址: https://github.com/Snailclimb/JavaGuide.
本文内容思维导图:
消息队列其实很简单
  “RabbitMQ?”“Kafka?”“RocketMQ?”...在日常学习与开发过程中,我们常常听到消息队列这个关键词。我也在我的多篇文章中提到了这个概念。可能你是熟练使用消息队列的老手,又或者你是不懂消息队列的新手,不论你了不了解消息队列,本文都将带你搞懂消息队列的一些基本理论。如果你是老手,你可能从本文学到你之前不曾注意的一些关于消息队列的重要概念,如果你是新手,相信本文将是你打开消息队列大门的一板砖。
一 什么是消息队列
  我们可以把消息队列比作是一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用。消息队列是分布式系统中重要的组件,使用消息队列主要是为了通过异步处理提高系统性能和削峰、降低系统耦合性。目前使用较多的消息队列有ActiveMQ,RabbitMQ,Kafka,RocketMQ,我们后面会一一对比这些消息队列。
  另外,我们知道队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。比如生产者发送消息1,2,3...对于消费者就会按照1,2,3...的顺序来消费。但是偶尔也会出现消息被消费的顺序不对的情况,比如某个消息消费失败又或者一个 queue 多个consumer 也会导致消息被消费的顺序不对,我们一定要保证消息被消费的顺序正确。
  除了上面说的消息消费顺序的问题,使用消息队列,我们还要考虑如何保证消息不被重复消费?如何保证消息的可靠性传输(如何处理消息丢失的问题)?......等等问题。所以说使用消息队列也不是十全十美的,使用它也会让系统可用性降低、复杂度提高,另外需要我们保障一致性等问题。
二 为什么要用消息队列
  我觉得使用消息队列主要有两点好处:1.通过异步处理提高系统性能(削峰、减少响应所需时间);2.降低系统耦合性。如果在面试的时候你被面试官问到这个问题的话,一般情况是你在你的简历上涉及到消息队列这方面的内容,这个时候推荐你结合你自己的项目来回答。
  《大型网站技术架构》第四章和第七章均有提到消息队列对应用性能及扩展性的提升。
(1) 通过异步处理提高系统性能(削峰、减少响应所需时间)
  如上图, 在不使用消息队列服务器的时候,用户的请求数据直接写入数据库,在高并发的情况下数据库压力剧增,使得响应速度变慢。但是在使用消息队列之后,用户的请求数据发送给消息队列之后立即 返回,再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。由于消息队列服务器处理速度快于数据库(消息队列也比数据库有更好的伸缩性),因此响应速度得到大幅改善。
  通过以上分析我们可以得出 消息队列具有很好的削峰作用的功能 ——即 通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。 举例:在电子商务一些秒杀、促销活动中,合理使用消息队列可以有效抵御促销活动刚开始大量订单涌入对系统的冲击。如下图所示:
  因为 用户请求数据写入消息队列之后就立即返回给用户了,但是请求数据在后续的业务校验、写数据库等操作中可能失败 。因此使用消息队列进行异步处理之后,需要 适当修改业务流程进行配合 ,比如 用户在提交订单之后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单之后,甚至出库后,再通过电子邮件或短信通知用户订单成功 ,以免交易纠纷。这就类似我们平时手机订火车票和电影票。
(2) 降低系统耦合性
  我们知道如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,这样系统的可扩展性无疑更好一些。
  我们最常见的 事件驱动架构 类似生产者消费者模式,在大型网站中通常用利用消息队列实现事件驱动结构。如下图所示:
   消息队列使利用发布-订阅模式工作,消息发送者(生产者)发布消息,一个或多个消息接受者(消费者)订阅消息。 从上图可以看到 消息发送者(生产者)和消息接受者(消费者)之间没有直接耦合 ,消息发送者将消息发送至分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进行后续处理,并不需要知道该消息从何而来。 对新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计 。
  消息接受者对消息进行过滤、处理、包装后,构造成一个新的消息类型,将消息继续发送出去,等待其他消息接受者订阅该消息。因此基于事件(消息对象)驱动的业务架构可以是一系列流程。
   另外为了避免消息队列服务器宕机造成消息丢失,会将成功发送到消息队列的消息存储在消息生产者服务器上,等消息真正被消费者服务器处理后才删除消息。在消息队列服务器宕机后,生产者服务器会选择分布式消息队列服务器集群中的其他服务器发布消息。
备注: 不要认为消息队列只能利用发布-订阅模式工作,只不过在解耦这个特定业务环境下是使用发布-订阅模式的。 除了发布-订阅模式,还有点对点订阅模式(一个消息只有一个消费者),我们比较常用的是发布-订阅模式。 另外,这两种消息模型是 JMS 提供的,AMQP 协议还提供了 5 种消息模型。
三 使用消息队列带来的一些问题 系统可用性降低: 系统可用性在某种程度上降低,为什么这样说呢?在加入MQ之前,你不用考虑消息丢失或者说MQ挂掉等等的情况,但是,引入MQ之后你就需要去考虑了! 系统复杂性提高: 加入MQ之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题! 一致性问题: 我上面讲了消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!
四 JMS VS AMQP
4.1 JMS
4.1.1 JMS 简介
  JMS(JAVA Message Service,java消息服务)是java的消息服务,JMS的客户端之间可以通过JMS服务进行异步的消息传输。 JMS(JAVA Message Service,Java消息服务)API是一个消息服务的标准或者说是规范 ,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
ActiveMQ 就是基于 JMS 规范实现的。
4.1.2 JMS两种消息模型
1、点到点(P2P)模型
  使用 队列(Queue) 作为消息通信载体;满足 生产者与消费者模式 ,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。比如:我们生产者发送100条消息的话,两个消费者来消费一般情况下两个消费者会按照消息发送的顺序各自消费一半(也就是你一个我一个的消费。)
2、 发布/订阅(Pub/Sub)模型
  发布订阅模型(Pub/Sub) 使用 主题(Topic) 作为消息通信载体,类似于 广播模式 ;发布者发布一条消息,该消息通过主题传递给所有的订阅者, 在一条消息广播之后才订阅的用户则是收不到该条消息的 。
4.1.3 JMS 五种不同的消息正文格式
  JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。 StreamMessage -- Java原始值的数据流 MapMessage--一套名称-值对 TextMessage--一个字符串对象 ObjectMessage--一个序列化的 Java对象 BytesMessage--一个字节的数据流
4.2 AMQP
  ​ AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准 高级消息队列协议 (二进制应用层协议),是应用层协议的一个开放标准,为面向消息的中间件设计,兼容 JMS。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件同产品,不同的开发语言等条件的限制。
RabbitMQ 就是基于 AMQP 协议实现的。
4.3 JMS vs AMQP
对比方向 JMS AMQP
定义 Java API 协议
跨语言
跨平台
支持消息类型
支持消息类型
提供两种消息模型:1、Peer-2-Peer;2、Pub/sub
支持多种消息类型 ,我们在上面提到过
提供了五种消息模型:direct exchange;2、fanout exchange;3、topic change;4、headers exchange;5、system exchange。本质来讲,后四种和JMS的pub/sub模型没有太大差别,仅是在路由机制上做了更详细的划分;
byte[](二进制)
总结: AMQP 为消息定义了线路层(wire-level protocol)的协议,而JMS所定义的是API规范。在 Java 体系中,多个client均可以通过JMS进行交互,不需要应用修改代码,但是其对跨平台的支持较差。而AMQP天然具有跨平台、跨语言特性。 JMS 支持TextMessage、MapMessage 等复杂的消息类型;而 AMQP 仅支持 byte[] 消息类型(复杂的类型可序列化后发送)。 由于Exchange 提供的路由算法,AMQP可以提供多样化的路由方式来传递消息到消息队列,而 JMS 仅支持 队列 和 主题/订阅 方式两种。
五 常见的消息队列对比
对比方向 概要
吞吐量 万级的 ActiveMQ 和 RabbitMQ 的吞吐量(ActiveMQ 的性能最差)要比 十万级甚至是百万级的 RocketMQ 和 Kafka 低一个数量级。
可用性 都可以实现高可用。ActiveMQ 和 RabbitMQ 都是基于主从架构实现高可用性。RocketMQ 基于分布式架构。 kafka 也是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
时效性 RabbitMQ 基于erlang开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。其他三个都是 ms 级。
功能支持
消息丢失
除了 Kafka,其他三个功能都较为完备。 Kafka 功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准
ActiveMQ 和 RabbitMQ 丢失的可能性非常低, RocketMQ 和 Kafka 理论上不会丢失。
总结: ActiveMQ 的社区算是比较成熟,但是较目前来说,ActiveMQ 的性能比较差,而且版本迭代很慢,不推荐使用。 RabbitMQ 在吞吐量方面虽然稍逊于 Kafka 和 RocketMQ ,但是由于它基于 erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。但是也因为 RabbitMQ 基于 erlang 开发,所以国内很少有公司有实力做erlang源码级别的研究和定制。如果业务场景对并发量要求不是太高(十万级、百万级),那这四种消息队列中,RabbitMQ 一定是你的首选。如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。 RocketMQ 阿里出品,Java 系开源项目,源代码我们可以直接阅读,然后可以定制自己公司的MQ,并且 RocketMQ 有阿里巴巴的实际业务场景的实战考验。RocketMQ 社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准 JMS 规范走的有些系统要迁移需要修改大量代码。还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用RocketMQ 挺好的 kafka 的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。同时 kafka 最好是支撑较少的 topic 数量即可,保证其超高吞吐量。kafka 唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性天然适合大数据实时计算以及日志收集。
原文链接
大数据
2018-12-19 12:58:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
前言 只有光头才能变强
没错,这篇主要跟大家一起 入门 机器学习。作为一个开发者,”人工智能“肯定是听过的。作为一个开发面试者,肯定也会见过”机器学习“这个岗位(反正我校招的时候就遇到过)。
可能还会听过或者见过“深度学习”、“神经网络”等等这些非常火的 名词 ,那你对这些 术语 了解多少呢?
相信大家这几天在朋友圈也可以看到这照片:
// 通过if else 以人工穷举的方式来假装实现智能机器人聊天 希望阅读完本文中后,大家可以对这些术语和机器学习有一定的了解。
一、术语介绍
首先我们来简单看看人工智能、深度学习、机器学习这些术语和它们之间的关系究竟是怎么样的。
1.1人工智能
不知道听到“人工智能”大家会联想到什么,可能大多数都会想到科幻电影的机器人。
我们看来看看维基百科的定义: 人工智能(英语:Artificial Intelligence,缩写为 AI)亦称机器智能,指由 人制造出来的机器所表现出来的智能 。通常人工智能是指通过普通计算机程序的手段实现的人类智能技术。
人工智能也可以分成两类: 强人工智能:强人工智能观点认为“有可能”制造出“真正”能推理(Reasoning)和解决问题的智能机器,并且,这样的机器将 被认为是具有知觉、有自我意识的 。 像绝大多数科幻电影中的机器人就是在这范畴 弱人工智能:弱人工智能观点认为“不可能”制造出能“真正”地推理和解决问题的智能机器,这些机器只不过**“看起来”像是智能**的,但是并不真正拥有智能,也不会有自主意识。 我们 目前阶段 的人工智能,其实都是弱人工智能。
1.2机器学习
不知道听到“机器学习”大家会联想到什么。Emmm...反正我就是从字面的意思去理解:“机器可以 自我 学习”。
首先我们看一下维基百科是怎么说的: 机器学习是实现人工智能的一个途径 ,即以机器学习为手段解决人工智能中的问题。机器学习在近30多年已发展为一门多领域 交叉学科 ,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科
简单来说:机器学习可以通过 大量的数据或者以往的经验自动改进计算机程序/算法 。
生成完 模型f(x) 之后,我们将 样例数据丢进模型里边 ,就可以输出结果:
我们说机器学习可以 自我 学习,是因为我们会将 样例数据也会丢到“历史数据”中 ,这样生成模型就会有一定的改动,从而达到“自我学习”的效果。
1.3它们之间的关系
等等,我们好像还没讲深度学习呢。我们从上面机器学习的介绍也可以知道,机器学习已发展为一门多领域 交叉学科 ,机器学习中就有 好多个经典的算法,其中就包含了神经网络(深度学习可看成是神经网络的升级版) 。由于近几年深度学习发展迅猛,一些特有的学习手段相继被提出,所以越来越多的人将其单独看作一种学习的方法。
《机器学习 周志华》: 所谓深度学习,狭义地说就是**“很多层”的神经网络**,在若干测试和竞赛下,尤其涉及语音、图像等复杂对象的引用中,深度学习取得优越的性能。
所以我们可以总结出人工智能、机器学习、深度学习之间的关系是这样的: 机器学习,是实现人工智能的重要方法。 深度学习,是实现机器学习的技术。
想要了解更多,可参考: 人工智能、机器学习和深度学习的区别? https://www.zhihu.com/question/57770020
二、机器学习入门
通过上面我们可以简单认为机器学习就是: 利用计算机 从历史数据找出 规律 ,把这些规律用到 未来 不确定场景的决策中。
下面我们再来学习一下机器学习的一些入门知识。
2.1机器学习的术语
特征、样本、数据集、标记这些术语的说明:
特征(属性)所张成的空间叫做 特征空间 。
例如我们把“色泽”、"根蒂“、”敲声“作为三个坐标轴,则它们张成一个用于描述 西瓜的三围空间 ,每个西瓜都可在这个空间中找到自己的坐标位置。 由于空间中的每个点对应一个坐标向量,我们也把一个示例称为“特征向量 ”。
回到我们上面的图,再来讲讲“训练数据”、“训练”、“标记”:
2.2机器学习的分类
一般机器学习又可以分成以下几类: 监督学习 半监督学习 非监督学习 增强学习
2.2.1监督学习
监督学习:训练数据(Training Data)可以告诉我们要找的那个模型的输入(Input)与输出(Output,也就是我们说的label)之间有什么样的关系。 给出的数据都有“答案”或“标记” 训练数据:"Java3y公众号"->好的公众号 , "Java4y公众号"->不好的公众号。 输出结果:好的公众号或者不好的公众号
在监听学习下又分为两种算法: 回归(Regression):结果是一个连续的 数值 (scalar),而非类别 分类(Classification):为训练数据进行分类别(多分类) 二分类:类别只有两种结果(YES OR NO)
回归例子 :知道前几天的PM2.5数值,预测一下明天的PM2.5数值。
**二分类例子:**判断一封邮件是垃圾邮件还是正常邮件。
**多分类例子:**将新闻帖子分类成不同的类别。
2.2.2非监督学习
非监督学习: 训练数据(Training Data)没有对应“答案”或“标记” 训练数据:"Java3y公众号" "Java4y公众号" "Java5y公众号" "Java6y公众号" "yyy公众号" "xxx公众号" "zzz公众号" 输出结果:("Java3y公众号" "Java4y公众号" "Java5y公众号" "Java6y公众号") ("yyy公众号" "xxx公众号" "zzz公众号") 分门类别
对没有“标记”的数据进行分类-聚类分析
聚类分析例子: 在以前,中国移动有三个品牌:神州行、动感地带、全球通。我们给一堆的SIM卡交由学习算法训练, 不告诉它每张SIM卡具体是什么卡 ,最后我们是可以将这些SIM卡 分类别出来的 。

2.2.3半监督学习
理解了监督学习和非监督学习,对于半监督学习就很容易理解了。
一部分数据有“标记”或者“答案”,另一部分数据没有 因为各种原因产生的标记缺失。
通常都会使用非监督学习手段对数据进行处理(特征提取、降维),之后再只用监督学习手段做模型的训练和预测。
2.2.4增强学习 根据周围环境的情况,采取行动, 根据采取行动的结果,学习行动方式
每次行动,就给这次的行动 评分 ,算法会根据评分来评估下一次的行动是好还是坏,最终不断改进。
例子:Alpha Go下每步棋的时候都会 评估 自己这次下得怎么样,通过最终的结果不断改进下的每步棋。
2.3机器学习的其他分类
除了我们上面所说的监督学习、非监督学习、半监督学习、增强学习之外,机器学习也可以分成: 在线学习: 及时 将样例数据作为训练数据对模型进行训练。 需要加强对数据进行监控(有可能样本数据是脏数据,这样就破坏我们的模型) 离线(批量)学习: 定时 将样例数据作为训练数据对模型进行训练。 不能很快的适应环境的变化
还有: 参数学习:一旦学到了参数,就不再需要原有的数据集。通过调参数就好了。 非参数学习: 不对模型进行过多的假设 ,非参数不代表没参数。
最后
机器学习的核心在于算法上 ,这篇只是对机器学习的一个简单的入门,希望能对大家有所帮助。
机器学习 资源 ,可关注我的公众号,回复“机器学习”即可领取。 有周志华《机器学习》电子版。吴恩达、李宏毅视频及笔记 乐于分享和输出 干货 的Java技术公众号:Java3y。
文章的 目录导航 : https://github.com/ZhongFuCheng3y/3y
大数据
2018-12-19 10:19:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
前面博主介绍了sql中join功能的大数据实现,本节将继续为小伙伴们分享倒排索引的建立。
一、需求
在很多项目中,我们需要对我们的文档建立索引(如:论坛帖子);我们需要记录某个词在各个文档中出现的次数并且记录下来供我们进行查询搜素,这就是我们做搜素引擎最基础的功能;分词框架有开源的CJK等,搜素框架有lucene等。但是当我们需要建立索引的文件数量太多的时候,我们使用lucene来做效率就会很低;此时我们需要建立自己的索引,可以使用hadoop来实现。
图1、待统计的文档
图2、建立的索引文件效果
二、代码实现
step1:map-reduce package com.empire.hadoop.mr.inverindex; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.input.FileSplit; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class InverIndexStepOne { static class InverIndexStepOneMapper extends Mapper { Text k = new Text(); IntWritable v = new IntWritable(1); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString(); String[] words = line.split(" "); FileSplit inputSplit = (FileSplit) context.getInputSplit(); String fileName = inputSplit.getPath().getName(); for (String word : words) { k.set(word + "--" + fileName); context.write(k, v); } } } static class InverIndexStepOneReducer extends Reducer { @Override protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException { int count = 0; for (IntWritable value : values) { count += value.get(); } context.write(key, new IntWritable(count)); } } public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = Job.getInstance(conf); job.setJarByClass(InverIndexStepOne.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.setInputPaths(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); // FileInputFormat.setInputPaths(job, new Path(args[0])); // FileOutputFormat.setOutputPath(job, new Path(args[1])); job.setMapperClass(InverIndexStepOneMapper.class); job.setReducerClass(InverIndexStepOneReducer.class); job.waitForCompletion(true); } }
step2:map-reduce package com.empire.hadoop.mr.inverindex; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class IndexStepTwo { public static class IndexStepTwoMapper extends Mapper { @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString(); String[] files = line.split("--"); context.write(new Text(files[0]), new Text(files[1])); } } public static class IndexStepTwoReducer extends Reducer { @Override protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException { StringBuffer sb = new StringBuffer(); for (Text text : values) { sb.append(text.toString().replace("\t", "-->") + "\t"); } context.write(key, new Text(sb.toString())); } } public static void main(String[] args) throws Exception { if (args.length < 1 || args == null) { args = new String[] { "D:/temp/out/part-r-00000", "D:/temp/out2" }; } Configuration config = new Configuration(); Job job = Job.getInstance(config); job.setJarByClass(IndexStepTwo.class); job.setMapperClass(IndexStepTwoMapper.class); job.setReducerClass(IndexStepTwoReducer.class); // job.setMapOutputKeyClass(Text.class); // job.setMapOutputValueClass(Text.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(Text.class); FileInputFormat.setInputPaths(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 1 : 0); } }
三、执行程序 #上传jar Alt+p lcd d:/ put IndexStepOne.jar IndexStepTwo.jar put a.txt b.txt c.txt #准备hadoop处理的数据文件 cd /home/hadoop hadoop fs -mkdir -p /index/indexinput hdfs dfs -put a.txt b.txt c.txt /index/indexinput #运行程序 hadoop jar IndexStepOne.jar com.empire.hadoop.mr.inverindex.InverIndexStepOne /index/indexinput /index/indexsteponeoutput hadoop jar IndexStepTwo.jar com.empire.hadoop.mr.inverindex.IndexStepTwo /index/indexsteponeoutput /index/indexsteptwooutput
四、运行效果 [hadoop@centos-aaron-h1 ~]$ hadoop jar IndexStepOne.jar com.empire.hadoop.mr.inverindex.InverIndexStepOne /index/indexinput /index/indexsteponeoutput 18/12/19 07:08:42 INFO client.RMProxy: Connecting to ResourceManager at centos-aaron-h1/192.168.29.144:8032 18/12/19 07:08:43 WARN mapreduce.JobResourceUploader: Hadoop command-line option parsing not performed. Implement the Tool interface and execute your application with ToolRunner to remedy this. 18/12/19 07:08:43 INFO input.FileInputFormat: Total input files to process : 3 18/12/19 07:08:43 INFO Configuration.deprecation: yarn.resourcemanager.system-metrics-publisher.enabled is deprecated. Instead, use yarn.system-metrics-publisher.enabled 18/12/19 07:08:44 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1545173547743_0001 18/12/19 07:08:45 INFO impl.YarnClientImpl: Submitted application application_1545173547743_0001 18/12/19 07:08:45 INFO mapreduce.Job: The url to track the job: http://centos-aaron-h1:8088/proxy/application_1545173547743_0001/ 18/12/19 07:08:45 INFO mapreduce.Job: Running job: job_1545173547743_0001 18/12/19 07:08:56 INFO mapreduce.Job: Job job_1545173547743_0001 running in uber mode : false 18/12/19 07:08:56 INFO mapreduce.Job: map 0% reduce 0% 18/12/19 07:09:05 INFO mapreduce.Job: map 33% reduce 0% 18/12/19 07:09:20 INFO mapreduce.Job: map 67% reduce 0% 18/12/19 07:09:21 INFO mapreduce.Job: map 100% reduce 100% 18/12/19 07:09:23 INFO mapreduce.Job: Job job_1545173547743_0001 completed successfully 18/12/19 07:09:23 INFO mapreduce.Job: Counters: 50 File System Counters FILE: Number of bytes read=1252 FILE: Number of bytes written=791325 FILE: Number of read operations=0 FILE: Number of large read operations=0 FILE: Number of write operations=0 HDFS: Number of bytes read=689 HDFS: Number of bytes written=297 HDFS: Number of read operations=12 HDFS: Number of large read operations=0 HDFS: Number of write operations=2 Job Counters Killed map tasks=1 Launched map tasks=4 Launched reduce tasks=1 Data-local map tasks=4 Total time spent by all maps in occupied slots (ms)=53828 Total time spent by all reduces in occupied slots (ms)=13635 Total time spent by all map tasks (ms)=53828 Total time spent by all reduce tasks (ms)=13635 Total vcore-milliseconds taken by all map tasks=53828 Total vcore-milliseconds taken by all reduce tasks=13635 Total megabyte-milliseconds taken by all map tasks=55119872 Total megabyte-milliseconds taken by all reduce tasks=13962240 Map-Reduce Framework Map input records=14 Map output records=70 Map output bytes=1106 Map output materialized bytes=1264 Input split bytes=345 Combine input records=0 Combine output records=0 Reduce input groups=21 Reduce shuffle bytes=1264 Reduce input records=70 Reduce output records=21 Spilled Records=140 Shuffled Maps =3 Failed Shuffles=0 Merged Map outputs=3 GC time elapsed (ms)=1589 CPU time spent (ms)=5600 Physical memory (bytes) snapshot=749715456 Virtual memory (bytes) snapshot=3382075392 Total committed heap usage (bytes)=380334080 Shuffle Errors BAD_ID=0 CONNECTION=0 IO_ERROR=0 WRONG_LENGTH=0 WRONG_MAP=0 WRONG_REDUCE=0 File Input Format Counters Bytes Read=344 File Output Format Counters Bytes Written=297 [hadoop@centos-aaron-h1 ~]$ [hadoop@centos-aaron-h1 ~]$ hadoop jar IndexStepTwo.jar com.empire.hadoop.mr.inverindex.IndexStepTwo /index/indexsteponeoutput /index/indexsteptwooutput 18/12/19 07:11:27 INFO client.RMProxy: Connecting to ResourceManager at centos-aaron-h1/192.168.29.144:8032 18/12/19 07:11:27 WARN mapreduce.JobResourceUploader: Hadoop command-line option parsing not performed. Implement the Tool interface and execute your application with ToolRunner to remedy this. 18/12/19 07:11:27 INFO input.FileInputFormat: Total input files to process : 1 18/12/19 07:11:28 INFO mapreduce.JobSubmitter: number of splits:1 18/12/19 07:11:28 INFO Configuration.deprecation: yarn.resourcemanager.system-metrics-publisher.enabled is deprecated. Instead, use yarn.system-metrics-publisher.enabled 18/12/19 07:11:28 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1545173547743_0002 18/12/19 07:11:28 INFO impl.YarnClientImpl: Submitted application application_1545173547743_0002 18/12/19 07:11:29 INFO mapreduce.Job: The url to track the job: http://centos-aaron-h1:8088/proxy/application_1545173547743_0002/ 18/12/19 07:11:29 INFO mapreduce.Job: Running job: job_1545173547743_0002 18/12/19 07:11:36 INFO mapreduce.Job: Job job_1545173547743_0002 running in uber mode : false 18/12/19 07:11:36 INFO mapreduce.Job: map 0% reduce 0% 18/12/19 07:11:42 INFO mapreduce.Job: map 100% reduce 0% 18/12/19 07:11:48 INFO mapreduce.Job: map 100% reduce 100% 18/12/19 07:11:48 INFO mapreduce.Job: Job job_1545173547743_0002 completed successfully 18/12/19 07:11:48 INFO mapreduce.Job: Counters: 49 File System Counters FILE: Number of bytes read=324 FILE: Number of bytes written=394987 FILE: Number of read operations=0 FILE: Number of large read operations=0 FILE: Number of write operations=0 HDFS: Number of bytes read=427 HDFS: Number of bytes written=253 HDFS: Number of read operations=6 HDFS: Number of large read operations=0 HDFS: Number of write operations=2 Job Counters Launched map tasks=1 Launched reduce tasks=1 Data-local map tasks=1 Total time spent by all maps in occupied slots (ms)=3234 Total time spent by all reduces in occupied slots (ms)=3557 Total time spent by all map tasks (ms)=3234 Total time spent by all reduce tasks (ms)=3557 Total vcore-milliseconds taken by all map tasks=3234 Total vcore-milliseconds taken by all reduce tasks=3557 Total megabyte-milliseconds taken by all map tasks=3311616 Total megabyte-milliseconds taken by all reduce tasks=3642368 Map-Reduce Framework Map input records=21 Map output records=21 Map output bytes=276 Map output materialized bytes=324 Input split bytes=130 Combine input records=0 Combine output records=0 Reduce input groups=7 Reduce shuffle bytes=324 Reduce input records=21 Reduce output records=7 Spilled Records=42 Shuffled Maps =1 Failed Shuffles=0 Merged Map outputs=1 GC time elapsed (ms)=210 CPU time spent (ms)=990 Physical memory (bytes) snapshot=339693568 Virtual memory (bytes) snapshot=1694265344 Total committed heap usage (bytes)=137760768 Shuffle Errors BAD_ID=0 CONNECTION=0 IO_ERROR=0 WRONG_LENGTH=0 WRONG_MAP=0 WRONG_REDUCE=0 File Input Format Counters Bytes Read=297 File Output Format Counters Bytes Written=253 [hadoop@centos-aaron-h1 ~]$
五、运行结果 [hadoop@centos-aaron-h1 ~]$ hdfs dfs -cat /index/indexsteponeoutput/part-r-00000 boby--a.txt 1 boby--b.txt 2 boby--c.txt 4 fork--a.txt 2 fork--b.txt 4 fork--c.txt 8 hello--a.txt 2 hello--b.txt 4 hello--c.txt 8 integer--a.txt 1 integer--b.txt 2 integer--c.txt 4 source--a.txt 1 source--b.txt 2 source--c.txt 4 tom--a.txt 1 tom--b.txt 2 tom--c.txt 4 [hadoop@centos-aaron-h1 ~]$ [hadoop@centos-aaron-h1 ~]$ hdfs dfs -cat /index/indexsteptwooutput/part-r-00000 boby a.txt-->1 b.txt-->2 c.txt-->4 fork a.txt-->2 b.txt-->4 c.txt-->8 hello b.txt-->4 c.txt-->8 a.txt-->2 integer a.txt-->1 b.txt-->2 c.txt-->4 source a.txt-->1 b.txt-->2 c.txt-->4 tom a.txt-->1 b.txt-->2 c.txt-->4 [hadoop@centos-aaron-h1 ~]$
最后寄语,以上是博主本次文章的全部内容,如果大家觉得博主的文章还不错,请点赞;如果您对博主其它服务器大数据技术或者博主本人感兴趣,请关注博主博客,并且欢迎随时跟博主沟通交流。
大数据
2018-12-18 23:17:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1、抽象等级
Flink 提供了不同级别的抽象来开发流/批处理应用程序。
1) 低层级的抽象
最低层次的抽象仅仅提供有状态流。它通过Process函数嵌入到DataStream API中。它允许用户自由地处理来自一个或多个流的事件,并使用一致的容错状态。此外,用户可以注册事件时间和处理时间回调,允许程序实现复杂的计算。
2) 核心API
在实践中,大多数应用程序不需要上面描述的低级抽象,而是对核心API进行编程,比如DataStream API(有界或无界数据流)和DataSet API(有界数据集)。这些API提供了用于数据处理的通用构建块,比如由用户定义的多种形式的转换、连接、聚合、窗口、状态等。在这些api中处理的数据类型以类(class)的形式由各自的编程语言所表示。
低级流程函数与DataStream API集成,使得只对某些操作进行低级抽象成为可能。DataSet API为有界数据集提供了额外的原语,比如循环或迭代。
3) Table API
Table API是一个以表为中心的声明性DSL,其中表可以动态地改变(当表示流数据时)。表API遵循(扩展)关系模型:表有一个附加模式(类似于关系数据库表)和API提供了类似的操作,如select, project, join, group-by, aggregate 等。Table API 程序以声明的方式定义逻辑操作应该做什么而不是指定操作的代码看起来如何。虽然Table API可以通过各种用户定义函数进行扩展,但它的表达性不如核心API,但使用起来更简洁(编写的代码更少)。此外,Table API程序还可以在执行之前通过应用优化规则的优化器。可以无缝地在Table API和DataStream/DataSet API之间进行切换,允许程序将Table API和DataStream和DataSet API进行混合使用。
4) Sql层
Flink提供的最高级别抽象是SQL。这种抽象在语义和表示方面都类似于Table API,但将程序表示为SQL查询表达式。SQL抽象与表API密切交互,SQL查询可以在表API中定义的表上执行。
2、程序和数据流
Flink程序的基本构建模块是streams 和 transformations 。(请注意,Flink的DataSet API中使用的数据集也是内部流——稍后将对此进行详细介绍。)从概念上讲,streams 是数据记录的(可能是无限的)流,而transformations是将一个或多个流作为输入并产生一个或多个输出流的操作。
执行时,Flink程序被映射到流数据流,由streams 和 transformations 操作符组成。每个数据流以一个或多个sources开始,以一个或多个sinks结束。数据流类似于任意有向无环图(DAGs)。虽然通过迭代构造允许特殊形式的循环,但为了简单起见,我们将在大多数情况下忽略这一点。

通常在程序中的transformations和数据流中的操作之间是一对一的对应关系。然而,有时一个transformations可能包含多个transformations操作。
在streming连接器和批处理连接器文档中记录了Sources 和 sinks。在DataStream运算和数据集transformations中记录了transformations。
3、并行数据流
Flink中的程序本质上是并行的和分布式的。在执行期间,流有一个或多个流分区,每个operator 有一个或多个operator subtasks(操作子任务)。operator subtasks相互独立,在不同的线程中执行,可能在不同的机器或容器上执行。
operator subtasks的数量是特定运算符的并行度。一个流的并行性总是它的生产操作符的并行性。同一程序的不同运算符可能具有不同级别的并行性。

流可以在两个操作符之间以一对一(或转发)模式传输数据,也可以在重新分配模式中传输数据: One-to-one 流(例如上图中Source和map()运算符之间的流)保持元素的分区和顺序。这意味着map()操作符的subtask[1]将看到与源操作符的subtask[1]生成的元素相同的顺序。 Redistributing 流(如上面的map()和keyBy/window之间,以及keyBy/window和Sink之间)改变流的分区。每个操作符子任务根据所选的转换将数据发送到不同的目标子任务。例如keyBy()(通过散列键来重新分区)、broadcast()或balanced()(随机重新分区)。在重分发交换中,元素之间的顺序只保留在每一对发送和接收子任务中(例如map()的子任务[1]和keyBy/window的子任务[2])。因此,在本例中,每个键中的顺序都是保留的,但是并行性确实引入了关于不同键的聚合结果到达sink的顺序的不确定性。
4、窗口
聚合事件(例如计数、求和)在流上的工作方式与批处理不同。例如,不可能计算流中的所有元素,因为流通常是无限的(无界的)。相反,流上的聚合(计数、求和等)是由窗口限定作用域的,例如“过去5分钟的计数”或“最后100个元素的总和”。
Windows可以是时间驱动(示例:每30秒)或数据驱动(示例:每100个元素)。一个典型的方法是区分不同类型的窗口,比如翻滚窗户(没有重叠)、滑动窗口(有重叠)和会话窗口(中间有一个不活跃的间隙)。
5、时间
当提到流程序中的时间(例如定义窗口)时,可以指不同的时间概念: 事件时间 : 是创建事件的时间。它通常由事件中的时间戳描述,例如由生产传感器或生产服务附加。Flink通过时间戳转让者访问事件时间戳。 摄入时间 : 在source操作符中一个事件进入Flink数据流的时间。 处理时间 : 是执行基于时间的操作的每个操作符的本地时间。
6、状态操作
虽然一个数据流中有许多操作但只看作一个单独的事件(例如事件解析器),但是一些操作记住了跨多个事件的信息(例如窗口操作符)。这些操作称为有状态操作。
有状态操作的状态被维护在可以认为是嵌入式键/值存储中。状态与有状态操作符读取的流一起被严格地分区和分布。因此,在keyBy()函数之后,只能在键控流上访问键/值状态,并且只能访问与当前事件的键相关联的值。对齐流和状态的键确保所有的状态更新都是本地操作,保证一致性而不增加事务开销。这种对齐还允许Flink透明地重新分配状态和调整流分区。
(EventTime是信息自带的时间,再进入消息队列,IngestionTime是进入Flink的时间,Processing是进入Operator的时间)
7、容错检查点
Flink通过流回放和检查点的组合实现了容错。检查点与每个输入流中的特定点以及每个操作符的对应状态相关。通过恢复操作符的状态并从检查点重新播放事件,流数据流可以在检查点恢复,同时保持一致性(准确地说是一次处理语义)。
检查点间隔是在执行期间用恢复时间(需要重放的事件数量)来权衡容错开销的一种方法。
8、批处理流
Flink执行批处理程序作为流程序的特殊情况,其中流是有界的(有限的元素数量)。数据集在内部被视为数据流。因此,上述概念同样适用于批处理程序,也适用于流程序,但有少数例外: 批处理程序的容错不使用检查点。恢复通过完全重放流来实现。这是可能的,因为输入是有界的。这将使成本更多地用于恢复,但使常规处理更便宜,因为它避免了检查点。 数据集API中的有状态操作使用简化的内存/核心外数据结构,而不是键/值索引。 DataSet API引入了特殊的synchronized(基于超步的)迭代,这只能在有界的流上实现。有关详细信息,请查看迭代文档。
文章来源: https://blog.csdn.net/silentwolfyh/article/details/82865579
推荐阅读: https://www.roncoo.com/view/173
大数据
2018-12-18 18:08:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
环境
为了正确地跑起来,你的应用需要依赖许多不同的软件。 就算是再怎么否认这一点的人,也无法否认至少需要依赖Flask本身。 你的应用的 运行环境 ,在当你想要让它跑起来时,是至关重要的。 幸运的是,我们有许多工具可以减低管理环境的复杂度。
使用virtualenv来管理环境
virtualenv 是一个能把你的应用隔离在一个 虚拟环境 中的工具。 一个虚拟环境是一个包含了你的应用依赖的软件的文件夹。一个虚拟环境同时也封存了你在开发时的环境变量。 与其把依赖包,比如Flask,下载到你的系统包管理文件夹,或用户包管理文件夹,我们可以把它下载到对应当前应用的一个隔离的文件夹之下。 这使得你可以指定一个特定的Python二进制版本,取决于当前开发的项目。
virtualenv也可以让你给不同的项目指定同样的依赖包的不同版本。 当你在一个老旧的包含众多不同项目的平台上开发时,这种灵活性十分重要。
用了virtualenv,你将只会把少数几个Python模块安装到系统的全局空间中。其中一个会是virtualenv本身: # 使用pip安装virtualenv $ pip install virtualenv
安装完virtualenv,就可以开始创建虚拟环境。切换到你的项目文件夹,运行 virtualenv 命令。这个命令接受一个参数,作为虚拟环境的名字(同样也是它的位置,在当前文件夹 ls 下你就知道了)。 $ virtualenv venv New python executable in venv/bin/python Installing setuptools, pip...done.
这将创建一个包含所有依赖的文件夹。
一旦新的virtual environment已经准备就绪,你需要给对应的virtual environment下的 bin/activate 脚本执行 source ,来激活它。 $ source venv/bin/activate
你可以通过运行 which python 看到:“python”现在指向的是virtual environment中的二进制版本。 $ which python /usr/local/bin/python $ source venv/bin/activate (venv)$ which python /Users/robert/Code/myapp/venv/bin/python
当一个virtual environment被激活了,依赖包会被pip安装到virtual environment中而不是全局系统环境。
你也许注意到了,你的shell提示符发生了改变。 virtualenv在它前面添加了当前被激活的virtual environment,所以你能意识到你并不存在于全局系统环境中。
运行 deactivate 命令,你就能离开你的virtual environment。 (venv)$ deactivate $
使用virtualenvwrapper管理你的virtual environment
我想要让你了解到 virtualenvwrapper 对于前面的工作做了什么改进,这样你就知道为什么你应该使用它。
虚拟环境文件夹现在已经位于你的项目文件夹之下。 但是你仅仅是在激活了虚拟环境后才会跟它交互。它甚至不应该被放入版本控制中。所以它呆在项目文件夹中也是挺碍眼的。 解决这个问题的一个方法就是使用virtualenvwrapper。这个包把你所有的virtual environment整理到单独的文件夹下,通常是 ~/.virtualenvs/ 。
要安装virtualenvwrapper,遵循这个 文档 中的步骤。 注意 确保你在安装virtualenvwrapper时不在任何一个virtual environment中。你需要把它安装在全局空间,而不是一个已存在的virtual environment中
现在,你不再需要运行 virtualenv 来创建一个环境,只需运行 mkvirtualenv : $ mkvirtualenv rocket New python executable in rocket/bin/python Installing setuptools, pip...done.
在你的virtual environment目录之下,比如在 ~/.virtualenv 之下, mkvirtualenv 创建了一个文件夹,并替你激活了它。 就像普通的 virtualenv , python 和 pip 现在指向的是virtual environment而不是全局系统。 为了激活想要的环境,运行这个命令: workon [environment name] ,而 deactivate 依然会关闭环境。
记录依赖变动
随着项目增长,你会发现它的依赖列表也一并随着增长。在你能运行一个Flask应用之前,即使已经需要数以十记的依赖包也毫不奇怪。 管理依赖的最简单的方法就是使用一个简单的文本文件。 pip可以生成一个文本文件,列出所有已经安装的包。它也可以解析这个文件,并在新的系统(或者新的环境)下安装每一个包。
pip freeze
requirements.txt 是一个常常被许多Flask应用用于列出它所依赖的包的文本文件。它是通过 pip freeze > requirements.txt 生成的。 使用 pip install -r requirements.txt ,你就能安装所有的包。 注意 在freeze或install依赖包时,确保你正为于正确的virtual environment之中。
手动记录依赖变动
随着项目增长,你可能会发现 pip freeze 中列出的每一个包并不再是运行应用所必须的了。 也许有些包只是在开发时用得上。 pip freeze 没有判断力;它只是列出了当前安装的所有的包。所以你只能手动记录依赖的变动了。 你可以把运行应用所需的包和开发应用所需的包分别放入对应的 require_run.txt 和 require_dev.txt 。
版本控制
选择一个版本控制系统并使用它。 我推荐Git。如我所知,Git是当下最大众的版本控制系统。 在删除代码的时候无需担忧潜在的巨大灾难是无价的。 你现在可以对过去那种把不要的代码注释掉的行为说拜拜了,因为你可以直接删掉它们,即使将来突然需要,也可以通过 git revert 来恢复。 另外,你将会有整个项目的备份,存在Github,Bitbucket或你自己的Git server。
什么不应该在版本控制里
我通常不把一个文件放在版本控制里,如果它满足以下两个原因中的一个。 它是不必要的 它是不公开的。
编译的产物,比如 .pyc ,和virtual environment(如果你因为某些原因没有使用virtualenvwrapper)正是前者的例子。 它们不需要加入到版本控制中,因为它们可以通过 .py 或 requirements.txt 生成出来。
接口密钥(调用接口时必须传入的参数),应用密钥,以及数据库证书则是后者的例子。 它们不应该在版本控制中,因为一旦泄密,将造成严重的安全隐患。 注意 在做安全相关的决定时,我会假设稳定版本库将会在一定程度上被公开。这意味着要清除所有的隐私,并且永不假设一个安全漏洞不会被发现, 因为“谁能想到他们会干出什么事情?”
在使用Git时,你可以在版本库中创建一个特别的文件名为 .gitignore 。 在里面,能使用正则表达式来列出对应的文件。任何匹配的文件将被Git所忽略。 我建议你至少在其中加入 *.pyc 和 /instance 。instance文件夹中存放着跟你的应用相关的不便公开的配置。 .gitignore: *.pyc instance/ 参见 在这里你可以了解什么是 .gitignore : http://git-scm.com/docs/gitignore Flask文档中对instance目录的一段介绍 : http://flask.pocoo.org/docs/config/#instance-folders
调试
调试模式
Flask有一个便利的特性叫做“debug mode”。在你的应用配置中设置 debug = True 就能启动它。 当它被启动后,服务器会在代码变动之后重新加载,并且一旦发生错误,错误会打印成一个带交互式命令行的调用栈。 注意 不要在生产环境中开启debug mode。交互式命令行运行任意的代码输入,如果是在运行中的网站上,这将导致安全上的灾难性后果。
另见 阅读一下quickstart页面的debug mode部分 : http://docs.jinkan.org/docs/flask/quickstart.html#debug-mode 这里有一些关于错误处理,日志记录和使用其他调试工具的信息 : http://docs.jinkan.org/docs/flask/errorhandling.html
Flask-DebugToolbar
Flask-DebugToolbar 是用来调试你的应用的另一个得力工具。在debug mode中,它在你的应用中添加了一个侧边条。 这个侧边条会给你提供有关SQL查询,日志,版本,模板,配置和其他有趣的信息。
总结 使用virtualenv来打包你的应用的依赖包。 使用virtualenvwrapper来打包你的virtual environment。 使用一个或多个文本文件来记录依赖变化。 使用一个版本控制系统。我推荐Git。 使用.gitignore来排除不必要的或不能公开的东西混进版本控制。 debug mode会在开发时给你有关bug的信息。 Flaks-DebugToolbar拓展将给你有关bug更多的信息。
原文:http://colesmith.space/2015/05/19/revise-virtualenv-and-virtualenvwrapper.html
官方文档 virtualenv virtualenvwrapper
一 virtualenv What : virtualenv 是一个隔离Python环境的工具. Why : virtualenv 可以让你在同一个操作系统上建立多个不同的Python环境. 如一个Python2, 另一个Python3, 还有Django1.2 和 Django1.5 项目Python环境互不相同,互不干涉. How : (So Easy) Install : sudo pip install virtualenv Use : (Recommend) 创建环境 : virtualenv -p PYTHON_VERSION VIRTUAL_ENVIRONMENT_NAME 解释: -p PYTHON_EXE, –python=PYTHON_EXE : 指定Python版本, Python2, Python2.5, Python3等 注意: 这个Python版本必须存在于系统内部 –no-site-packages : 废弃了,因为默认没有权限访问全局包 栗子: virtualenv -p python3 django1.8 进入环境 : source path/to/VIRTUAL_ENVIRONMENT_NAME/bin/activate 栗子: source django1.8/bin/activate 或者 cd django1.8; source bin/activate 有明显标志(VIRTUAL_ENVIRONMENT_NAME),说明成功进入环境 退出环境 : deactivate 删除环境 : 只要删除创建的虚拟环境目录即可: rm -rf path/to/VIRTUAL_ENVIRONMENT_NAME rm -rf django1.8
二 virtualenvwrapper what : virtualenvwrapper 是 virtaulenv 的扩展的集合. Why : 便于使用和管理 virtualenv How : Install : sudo pip install virtualenvwrapper Use : 每次使用前必须先source环境 : 才有mkvirtualev, lssitepackages等命令 source /usr/local/bin/virtualenvwrapper.sh 或者将/etc/profile 或者 ~/.bashrc 或者 ~/.zshrc 启动终端时自动载入source 创建环境 : Syntax: mkvirtualenv [-a project_path] [-i package] [-r requirements_file] [virtualenv options] VIRTUAL_ENVIRONMENT_NAME 注意: 项目默认创建一律在 ~/.virtualenvs 目录下 栗子: 默认: mkvirtualenv django1.8 # (ls ~/.virtualenvs 可见) 指定Python版本: mkvirtualenv -p python3 django1.8 指定Python版本和依赖的包: mkvirtualenv -r requirements.txt -p python3 django1.8 指定项目地址, 只要载入环境,自动切换到项目目录: mkvirtualenv -a . django1.8 注意: 环境创建完成后,会自动载入环境 打开或切换工作环境 : Syntax: workon [(-c|--cd)|(-n|--no-cd)] [environment_name|"."] 栗子: 默认: workon django1.8 注意: 默认进入 mkvirtualenv 选项 -a 指定的目录,如果没有,则在当前目录 切换, 即已经在一个虚拟环境, 但要切换另一个环境: workon django1.5 不进入 -a 指定的目录: workon -n django1.8 退出环境,使用系统环境 : deactivate 删除环境 : rmvirtualenv VIRTUAL_ENVIRONMENT_NAME 或 rm -rf ~/.virtualenvs/VIRTUAL_ENVIRONMENT_NAME 栗子: rmvirtualenv django1.8 (推荐) rm -rf ~/.virtualenvs/django1.8 让所有创建的环境都执行某个命令,比如安装某个包等 : Syntax: allvirtualenv command with arguments 栗子: allvirtualenv pip install ipython 切换当前环境能否访问系统的Python包, 建议关闭(disable) : Syntax: toggleglobalsitepackages [-p] -p : 不输出日志 栗子: toggleglobalsitepackages 删除第三方包 : (注意: 必须已经在虚拟环境中) Syntax: wipeenv 创建项目+环境 : Create a new virtualenv in the WORKON_HOME and project directory in PROJECT_HOME. Syntax: mkproject [-f|--force] [-t template] [virtualenv_options] ENVNAME 注意设置 WORKON_HOME 和 PROJECT_HOME 其他命令: 显示安装的包: lssitepackages (建议用 pip list 更清楚) 复制一份虚拟环境: cpvirtualenv [sorce] [dest] cp django1.8 django 临时环境,deactivate后删除:
mktmpenv [(-c
–cd)
(-n
–no-cd)] [VIRTUALENV_OPTIONS]
栗子: mktmpenv -p python3 列出所有创建的虚拟环境: 即~/.virtualenvs目录下的
lsvirtualenv [-b
-l
-h]
-b 简短形式, 建议 -l 默认的详细信息输出 -h help 绑定项目目录 : Syntax: setvirtualenvproject [virtualenv_path project_path]


原文:http://virtualenv-chinese-docs.readthedocs.io/en/latest/#id3

Contents virtualenv 安装 用处 命令 环境变量和配置文件 Windows下注意事项 PyPy支持 创建自己的启动脚本 启动脚本范例 激活脚本 --system-site-packages 参数 不使用Virtualenv下的 bin/python 重定位隔离环境 --extra-search-dir 参数 与可替代品的比较 贡献力量 运行测试 相关文档和链接 现状和许可 Wrongway的补充:常用见法 1.创建隔离环境并安装最新的django 2.创建隔离环境并安装django1.3以及一系列开发用组件 3.创建Python2.7隔离环境并安装tornado Wrongway的补充:中译版致谢 Changes & News
安装
运行 pip install virtualenv 即可安装virtualenv,想用 最新开发版 就运行 pip installvirtualenv==dev 。
还可以用 easy_install 安装,即使是没有安装任何Python包管理器,也可以直接获取 virtualenv.py 并运行 python virtualenv.py ,效果一样。
用处
virtualenv 用来创建隔离的Python环境。
处理python环境的多版本和模块依赖,以及相应的权限是一个很常见的问题。比如,你有个应用使用的是LibFoo V1.0,但另一个应用却要用到LibFoo V2.0。如何处理呢?如果把所有模块都安装到 /usr/lib/python2.7/site-packages (或是你本机python默认的模块安装目录),那你极有可能无意中升级一些不该升级的模块。
更普遍的是,就算你成功安装了某个应用,那么接下来又会怎样?只要它开始运行了,那么只要其所依赖的模块发生任何改动,亦或升级,都可能打断该应用。
这还没完,要是你无法在 site-packages 目录下安装模块呢?比如共享主机。
上述这几种场合都适用 virtualenv 。它会创建一个拥有独立安装目录的python环境,该隔离环境不会与其他virtualenv环境共享模块(可选择是否访问全局库目录)。
一般用法是: $ python virtualenv.py ENV
在已安装virtualenv的情况下,可以直接运行 virtualenv ENV 。
该操作会创建 ENV/lib/pythonX.X/site-packages 目录 和 ENV/bin/python ,前者用来存放要安装的模块,后者就是隔离环境的Python解释器。在virtualenv环境下使用此解释器(包括以 #!/path/to/ENV/bin/python 开头的脚本)时,使用的都是隔离环境下的模块。
该操作还在隔离环境下安装了 Setuptools 或 distribute 。要用Distribue取代setuptools的话,只要运行: $ python virtualenv.py --distribute ENV
设置环境变量 VIRTUALENV_USE_DISTRIBUTE 也能达到同样目的。
新的virtualenv还包含了 pip 包管理器,可以直接用 ENV/bin/pip 安装第三方模块。
命令
用法: $ virtualenv [OPTIONS] DEST_DIR
选项: --version
显示当前版本号。
-h, --help
显示帮助信息。
-v, --verbose
显示详细信息。
-q, --quiet
不显示详细信息。
-p PYTHON_EXE, --python=PYTHON_EXE
指定所用的python解析器的版本,比如 --python=python2.5 就使用2.5版本的解析器创建新的隔离环境。默认使用的是当前系统安装(/usr/bin/python)的python解析器
--clear
清空非root用户的安装,并重头开始创建隔离环境。
--no-site-packages
令隔离环境不能访问系统全局的site-packages目录。
--system-site-packages
令隔离环境可以访问系统全局的site-packages目录。
--unzip-setuptools
安装时解压Setuptools或Distribute
--relocatable
重定位某个已存在的隔离环境。使用该选项将修正脚本并令所有.pth文件使用相当路径。
--distribute
使用Distribute代替Setuptools,也可设置环境变量VIRTUALENV_DISTRIBUTE达到同样效要。
--extra-search-dir=SEARCH_DIRS
用于查找setuptools/distribute/pip发布包的目录。可以添加任意数量的–extra-search-dir路径。
--never-download
禁止从网上下载任何数据。此时,如果在本地搜索发布包失败,virtualenv就会报错。
--prompt==PROMPT
定义隔离环境的命令行前缀。
环境变量和配置文件
virtualenv既可以通过命令行配置,比如 --distribute ,也可以用下面两种方式配置: 环境变量
命令行的每个参数都以 VIRTUALENV_ 的格式对应一个环境变量。转换变量名过程中,除了将命令行参数大写外,还要把 ( '-' ) 替换为 ( '_' ) 。
举个例子,要自动安装Distribute取代默认的setuptools,可以这样设置环境变量: $ export VIRTUALENV_USE_DISTRIBUTE=true $ python virtualenv.py ENV
等同于在命令行直接使用参数: $ python virtualenv.py --distribute ENV
有时要重复输入多个命令行参数,比如 --extra-search-dir 。变成环境变量时,要用空格隔开多个参数值,例如: $ export VIRTUALENV_EXTRA_SEARCH_DIR="/path/to/dists /path/to/other/dists" $ virtualenv ENV
等同于: $ python virtualenv.py --extra-search-dir=/path/to/dists --extra-search-dir=/path/to/other/dists ENV 配置文件
virtualenv还能通过标准ini文件进行配置。在Unix和Mac OS X中是 $HOME/.virtualenv/virtualenv.ini ,在Windows下是 %HOME%\\virtualenv\\virtualenv.ini 。
配置项名称就是命令行参数的名称。例如,参数 --distribute 在ini文件如下: [virtualenv] distribute = true
象 --extra-search-dir 这样的多值命令行参数,在ini文件中要用断行将多个值隔开: [virtualenv] extra-search-dir = /path/to/dists /path/to/other/dists
virtualenv --help 可以查看完整的参数列表。
Windows下注意事项
在Windows下路径会与*nix下略有不同:脚本和可执行文件在Windows下位于 ENV\Scripts\ 下,而非 ENV/bin/ ,模块也会安装在 ENV\Lib\ 下,而非 ENV/lib/ 。
要在某个含有空格的目录下面创建virtualenv环境,就要安装 win32api 。
PyPy支持
从1.5版开始,virtualenv开始支持 PyPy 。>=1.5版的virtualenv支持PyPy1.4和1.4.1,>=1.6.1版的virtualenv支持PyPy1,5。
创建自己的启动脚本
Wrongway提示:该段一般情况下初学者用不到,所以刚接触virtualenv的朋友不要在此节投放过多精力。Virtualenv的文档讲解顺序是有点问题。
创建隔离环境时,virtualenv不会执行额外操作。但开发者有时会想在安装隔离环境后运行某个脚本。例如用脚本安装某个web应用。
要创建上述脚本,需要调用 virtualenv.create_bootstrap_script(extra_text) ,将后续操作写入到生成的启动脚本,以下是从docstring中生成的文档:
启动脚本与一般脚本无异,只是多了三个extend_parser, adjust_options, after_install三个钩子方法。
create_bootstrap_script返回一个可定制的,能做为启动脚本的字符串(当然,该字符串后面要写回到磁盘文件中)。这个字符串是一个标准的virtualenv.py脚本,用户可以自行添加内容(所加内容必须是python代码)。
如果定义了下列方法,运行脚本时就会被调用:
extend_parser(optparse_parser) :
可以在解析器optparse_parser中添加或删除参数。
adjust_options(options, args) :
调整options,或改变args(如果要接收各种不同的参数,一定要在最后将 args 修改为 [DEST_DIR] )
after_install(options, home_dir) :
在所有代码和模块安装完之后,就会调用该方法。这可能是用户最喜欢的方法,例如下: def after_install(options, home_dir): if sys.platform == 'win32': bin = 'Scripts' else: bin = 'bin' subprocess.call([join(home_dir, bin, 'easy_install'), 'MyPackage']) subprocess.call([join(home_dir, bin, 'my-package-script'), 'setup', home_dir])
上述例子会安装一个包,并运行包内的setup脚本
wrongway在这里强调:上述三个方法并不是独立方法,而是一段代码字符串!!也就是extra_text的内容。有点象javascript下的eval(‘......代码字符串......’)
启动脚本范例
这有个具体的例子: import virtualenv, textwrap output = virtualenv.create_bootstrap_script(textwrap.dedent(""" import os, subprocess def after_install(options, home_dir): etc = join(home_dir, 'etc') if not os.path.exists(etc): os.makedirs(etc) subprocess.call([join(home_dir, 'bin', 'easy_install'), 'BlogApplication']) subprocess.call([join(home_dir, 'bin', 'paster'), 'make-config', 'BlogApplication', join(etc, 'blog.ini')]) subprocess.call([join(home_dir, 'bin', 'paster'), 'setup-app', join(etc, 'blog.ini')]) """)) f = open('blog-bootstrap.py', 'w').write(output)
这还有一个例子 点击 。
激活脚本
刚创建的隔离环境下会有一个 bin/activate 命令行脚本。在Windows下,激活脚本要在CMD.exe或Powershell.exe中使用。
在Posix系统(*nix/BSD)中,用法如下: $ source bin/activate
该操作会将当前 $PATH 指向隔离环境下的 bin/ 目录。之所以要用source是因为它要改变当前shell环境。仅仅就是一行命令,就这么简单。如果直接运行隔离环境下的脚本或是python解释器(比如 path/to/env/bin/pip or /path/to/env/bin/python script.py ),那都没必要使用激活脚本。
输入 deactivate 就能退出已激活的隔离环境,也就是取消对当前 $PATH 所做的修改。
activate 脚本会修改当前shell命令行提示符,以提示当前激活的是哪个隔离环境。这是挺有用的,不过要是想自定义的提示符,只要在运行 activate 前将 VIRTUAL_ENV_DISABLE_PROMPT 设为你想要的提示(不能为空字符串)。
在Windows下只须如此( * nix用户此处就不用看了,包括下面的注意也不用看了): > \path\to\env\Scripts\activate
输入 deactivate 就能退出隔离环境。
视你用的shell不同(CMD.exe或Powershell.exe),Windows会使用activate.bat或activate.ps1来激活隔离环境。如果使用的是Powershell,那么以下几点值得注意。
注意(说真的,开发python还是在*nix下好,真的真的真的!): 使用Powershell时,运行 ``activate`` 脚本取决于`执行策略`_ 。但在Windows7下,默认情况下执行策略被设为严格, 这就意味着象 ``activate`` 这样的脚本是不能直接运行的。但稍微设置一下即可。 降低执行策略,改为 ``AllSigned``, 这就意味着本机所有已通过数字签名的脚本都获许运行。 由于virtualenv作者之一Jannis Leidel的数字签名已被核准,允许运行。那么只要以管理员权限运行:: PS C:\> Set-ExecutionPolicy AllSigned 接下来运行脚本时会提示是否信任该签名:: PS C:\> virtualenv .\foo New python executable in C:\foo\Scripts\python.exe Installing setuptools................done. Installing pip...................done. PS C:\> .\foo\scripts\activate Do you want to run software from this untrusted publisher? File C:\foo\scripts\activate.ps1 is published by E=jannis@leidel.info, CN=Jannis Leidel, L=Berlin, S=Berlin, C=DE, Description=581796-Gh7xfJxkxQSIO4E0 and is not trusted on your system. Only run scripts from trusted publishers. [V] Never run [D] Do not run [R] Run once [A] Always run [?] Help (default is "D"):A (foo) PS C:\> 如果选择了 ``[A] Always Run``, 该证书就会添加到当前帐户下的受信任发布者名单中,而且此后一直被该用户所信任。 如果选择了 ``[R] Run Once``, 该脚本会立即运行,但之后每次使用都会重新出现信任提示并选择。 高级用户可以将该证书添加到当前计算机的受信任发布者名单中,这样所有用户都可以使用该脚本了(不过这部分内容已经超过了本文档范畴了)。 此外,还可以进一步降低执行策略,允行未验证的本地脚本运行:: PS C:\> Set-ExecutionPolicy RemoteSigned 因为对任何一个virtualenv环境而言, ``activate.ps1`` 都是一个本地脚本而非远程脚本,因为可以获准运行。
--system-site-packages 参数
virtualenv --system-site-packages ENV 创建的隔离环境能直接引用 /usr/lib/python2.7/site-packages (即是本机全局site-packages路径)中的模块。
只在拥有全局site-packages目录的读写权限,并且你的应用要依赖其中的模块的情况下,该参数会很有用。其他情况下没必要使用该参数。
不使用Virtualenv下的 bin/python
某些情况下,我们无法或是不想使用由virtualenv创建的Python解释器。比如,在 mod_python 或 mod_wsgi 下,只能用唯一一个Python解释器。(wrongway补充,不过uwsgi是可以使用多个python解释器的)
幸运的是,这相当简单。只要用指定的Python解释器来 安装 应用包即可。但要使用这些模块,就得更正路径。有一个脚本可以用来更正路径,如下这般设置环境: activate_this = '/path/to/env/bin/activate_this.py' execfile(activate_this, dict(__file__=activate_this))
上述操作会更改 sys.path 和 sys.prefix ,但使用的仍是当前Python解释器。在隔离环境中会先寻找 sys.path 下的内容再寻找全局路径。不过全局路径始终是可以访问的(无论隔离环境是否是由 --system-site-packages 创建的)。而且,上述操作不会影响其他隔离环境,也不会更正在此之前已经引用的模块。所以,在处理web请求时才激活环境往往是无效的,应该尽可能早的激活环境和更正路径,而不是在处理请求时才开始处理。
重定位隔离环境
注意: –relocatable参数带有一定的实验性,可能还有一些尚未发现的问题。而且该参数也不能在Windows下使用。
一般情况下,隔离环境都绑定在某个特定路径下。这也就意味着不能通过仅仅是移动或拷贝目录到另一台计算机上而迁移隔离环境。这时可以使用–relocatable来重定位隔离环境: $ virtualenv --relocatable ENV
该参数会根据相对路径生成某些setuptools或distribute文件,然后再运行 activate_this.py 更改所有的脚本,而不是通过改变python解释器软链接的指向来重置环境。
注意: 安装 任何 包之后,都要再次重定位环境。只要你将某个隔离环境迁移了,那么每安装一个新的包之后,都要再运行一遍 virtualenv --relocatable 。
要认识到,该参数 不能做到真正的跨平台 。虽然我们可以移动相关目录,但仅仅能用于类似的计算机之间。一些已知的环境差异,仍会导致不兼容: 不同版本的Python 不同平台使用不同的内部编码,比如一台用UCS2,另一台用UCS4 Linux和Windows Intel和ARM 某些包依赖系统的C库,而C库在不同平台下有所差异(不同的版本或不同的文件系统下的所在位置)。
使用重定位参数创建新隔离环境时,会默认使用 --system-site-packages 参数。
--extra-search-dir 参数
创建新的隔离环境时,virtualenv会安装setuptools,distribute或是pip包管理器。一般情况下,它们都会从 Python Package Index (PyPI) 中寻找并安装最新的包。但在一些特定情况下,我们并不希望如此。例如,你在部署virtualenv时既不想从网上下载,也不想从PyPI中获取包。
做为替代方案,可以让setuptools,distribute或是pip搜寻文件系统,让virtualenv使用本地发行包而不是从网上下载。只要象下面这样传入一个或多个 --extra-search-dir 参数就能使用该特性: $ virtualenv --extra-search-dir=/path/to/distributions ENV
/path/to/distributions 路径指向某个包含setuptools/distribute/pip发行包的目录。Setuptools发行包必须是 .egg 文件,distribute和pip发行包则是 .tar.gz 原代码压缩包。
如果本地路径没有找到相应的发布包,virtualenv还是会从网上下载。
要想确保不会从网上下载任何发行包,就使用 --never-download 参数,如下: $ virtualenv --extra-search-dir=/path/to/distributions --never-download ENV
这样,virtualenv不会从网上下载任何发行包。而只搜索本地发行包,如果没有找到要安装的包,就返回状态码1。virtualenv会按照如下顺序搜索发行包位置: 当前目录 virtualenv.py所在目录 virtualenv.py所在目录下的 virtualenv_support 目录 如果实际运行的脚本名并不是virtualenv.py (换句话说,就是你的自定义启动脚本),会搜索实际安装的virtualenv.py所在目录下的``virtualenv_support`` 目录。
与可替代品的比较
下面几个替代品也可以创建隔离环境: workingenv (建议不考虑workingenv) 是virtualenv的前身。它使用全局环境的Python解释器,但要靠设置 $PYTHONPATH 来激活环境。因此在运行隔离环境以外的Python脚本时,出现很多问题(比如,象全局环境下的 hg 或 bzr )。而且它与Setuptools也有很多冲突。 virtual-python 也是virtualenv的前身。它只使用软链接,因此不能在Windows上工作。而且它的链接会覆盖标准模块和全局环境的 site-packages ,因此无法使用安装在全局环境下的 site-packages 的第三方模块
因为virtual-python的软链接只是覆盖了全局环境下的标准模块的一部分,因此在windows上,可以用拷贝模块文件的方式来使用virtual-python。同时,它会创建一个空的 site-packages ,并把全局环境的 site-packages 指向该目录,因此更新是分别跟踪记录的(这块wrongway也不理解是什么意思,或许作者是想说要两个目录都注意要更新吧)。virtual-python也会自动安装Setuptools,从而省去了从网上手动安装这一步。 zc.buildout 不会以上述方式创建隔离的Python环境,但它通过定义配置文件,使用非常特殊的模块,配置脚本达到了相似的效果。做为一个可定义的系统,它是非常容易复制和管理的,但是比较难以改写。 zc.buildout 可以安装非Python的系统(比如数据库服务器或是Apache实例)
我 强烈 建议任何人开发或部署应用时都应该上述工具中的某一款
贡献力量
参照 contributing to pip (参与PIP贡献)这篇文章,里面提及的内容同样适用于virtualenv。
Virtualenv与pip同步发行,每有新的pip发布,就意味着该捆绑新版本pip的virtualenv也发布了。
运行测试
Virtualenv 的测试案例很小,也不完整,但我们后面会完善的。
运行测试的最简单方法就是(自动处理测试依赖): $ python setup.py test
可以使用nose运行测试的某一部分。创建一个virtualenv环境,然后安装必要的包: $ pip install nose mock
运行nosetests: $ nosetests
或是只测试某个文件: $ nosetests tests.test_virtualenv
相关文档和链接 James Gardner 编写了教程, 在virtualenv下使用Pylons 。 博文 workingenv已死,virtualenv当立 。 Doug Hellmann 介绍了 virtualenv(virtualenvwrapper)命令行下流水线运行 ,通过几个自写的脚本,让运行多个环境变得更加容易。他还写了 在virtualenv下运行IPython 。 Chris Perkins 在showmedo创作了视频 使用virtualenv 。 在mod_wsgi下使用virtualenv 。 更多virtualenv周边工具 。
现状和许可
virtualenv 是 workingenv 的升级, 也是 virtual-python 的扩展。
virtualenv 由 Ian Bicking 编写,接受 Open PlanningProject 赞助,由 开发小组 负责维护。该开源遵循 MIT 协议。
Wrongway的补充:常用见法
1.创建隔离环境并安装最新的django 使用当前系统默认Python解释器安装最新的django(当前是1.4),以及django用到的mysql驱动: $ mkdir myproject1 $ cd myproject1 $ virtualenv env --no-site-packages $ source env/bin/active $(env) pip install django $(env) pip install mysql-python $(env) deactive $
2.创建隔离环境并安装django1.3以及一系列开发用组件 首先编辑一个.pip文件,假定为requirement.pip文件,将要用到的第三方模块名称写入: Django==1.3 PIL South sorl-thumbnail pylibmc mysql-python django-debug-toolbar
再在命令行运行: $ mkdir myproject2 $ cd myproject2 $ virtualenv environ --no-site-packages $ source environ/bin/active $(environ) pip install -r requirement.pip $(environ) deactive $
3.创建Python2.7隔离环境并安装tornado 我当前环境的默认Python解析器版本是2.6,我已经安装了python2.7,现在两个python共存,但默认使用还是2.6: $ mkdir myproject3 $ cd myproject3 $ virtualenv huanjing --no-site-packages --python=python2.7 $ source huanjing/bin/active $(huanjing) pip install tornado $(huanjing) deactive $
要注意的,python2.7应该是被已设为全局可访问的,在当前命令行输入python2.7是可运行的,否则–python就要设为python2.7解释器的完整路径。
Flask博客源码公开在Github
博客欢迎界面
博客主页
缘起 最近想读读python方向的源码, 想Pythonic一点, 左右看去, 最后决定读Flask源码.
既然决定读源码, 我认为首先要简单的了解: 框架的功能 具体接口 实现一个简单的轮子. Flask 我就不多介绍了, 网上一搜一大把, python几大著名Web框架之一, 以其 轻量级, 高可扩展性 而著名.
那么我们开始造轮子之旅吧 环境相关: Mac OS X 10.10.3 Sublime Text 3 FLask 0.10.1 Python 3.4.1 # 请放手Python2.7.8, 拥抱Python3 下文主要内容: 介绍Flask搭建博客依赖(随着文章的圆满, 会逐渐添加) 搭建博客欢迎页面 搭建博客基本框架
Flask安装及相关插件
框架及插件: Flask Flask-Script Flask-WTF flask-mongoengine Flask-markdown virtualenv (版本控制) Virtualenv简明教程
数据库: mongo( 了解并会使用一种NoSQL会有很大的好处 )
环境配置 $ pip install virtualenv $ virtualenv -p /usr/local/bin/python3.4 Flask $ source Flask/bin/activate $ pip install Flask, Flask-Script, Flask-WTF, flask-mongoengine
项目骨架
请根据下面的Tree文件结构建立文件夹和文件 $ tree ./ ./ ├── README.md ├── app/ │ ├── __init__.py │ ├── models.py │ ├── static/ │ ├── templates/ │ └── views.py ├── config.py ├── manage.py ├── requirements.txt app 为项目核心源码 static 为项目静态文件 templates 为项目HTML模板
Hello World 国际惯例, 编程第一步... $ vim app/__init__.py # -*- coding: utf-8 -*- #!/usr/bin/env python from flask import Flask app = Flask(__name__) #创建Flask类的实例 app.config.from_object("config") #从config.py读入配置 #这个import语句放在这里, 防止views, models import发生循环import from app import views, models
views.py用于便携Blog的主逻辑, 和Django中views.py功能相同 $ vim app/views.py # -*- coding: utf-8 -*- #!/usr/bin/env python from app import app from flask import render_template @app.route('/') def index(): return "Hello World!"
运用Flask-Script为Flask编写服务器脚本, 产生类似Django的运行方式 $vim manage.py # -*- coding: utf-8 -*- #!/usr/bin/env python from flask.ext.script import Manager, Server from app import app manager = Manager(app) manager.add_command("runserver", Server(host="127.0.0.1", port=5000, use_debugger=True)) if __name__ == '__main__': manager.run()
运行服务器 $ python manage.py flask
浏览器打开 http://127.0.0.1:5000/ , 正式踏出第一步...
博客搭建框架
编写欢迎页面及样式 $ vim app/templates/welcome.html {% if title %} {{ title }} - 雪忆 {% else %} 雪忆 {% endif %}

Andrew Liu 雪 忆

雪忆, 如雪般单纯, 冷静思考.

$ vim app/static/welcome.css /* reset */ * { margin: 0; padding: 0; } #wrapper { position: absolute; width: 100%; height: 100%; overflow: hidden; } label { cursor: pointer; } label:focus { outline: none; } /* for show */ html, body { height: 100%; } body { background: url(http://37.media.tumblr.com/f6c67ec2821a91051e4175f8a102e1e2/tumblr_n6rzpcsMk41st5lhmo1_1280.jpg) 50% 50%/cover; } p { margin-bottom: 15px; } #info { display: table; background: rgba(0, 0, 0, 0.4); height: 100%; width: 100%; } #info #info-content { display: table-cell; vertical-align: middle; text-align: center; text-transform: uppercase; color: #fff; font-size: 12px; } #info #info-content h1 { color: #fff; border: 3px solid #fff; text-align: center; background: rgba(0, 0, 0, 0.1); font-size: 22px; font-weight: normal; padding: 20px; margin: 10px; display: inline-block; } #info #info-content h1 strong { display: block; font-size: 26px; }
现在更改views.py # -*- coding: utf-8 -*- #!/usr/bin/env python from app import app from flask import render_template, url_for @app.route('/') def index(): return render_template('welcome.html', title="Welcome") 到现在为止我们已经完成了欢迎页面的搭建
编写博客主页框架和样式 $ vim app/templates/base.html {% if title %} {{ title }} - 雪忆 {% else %} 雪忆 {% endif %}
{% block content %}{% endblock %}
$vim app/static/base.css @import url(http://fonts.googleapis.com/css?family=Open+Sans:400,800,700,600,300); body { margin:0; font-family: 'Open Sans', sans-serif; background: #eee; } hr { background:#dedede; border:0; height:1px; } .header { overflow: hidden; display:block; position:fixed; top:0; margin:0; width:100%; height:4px; text-align:center; } .header ul { margin:0; padding:0; } .header ul li { overflow:hidden; display:block; float:left; width:20%; height:4px; } .header .cor-1 { background:#f1c40f; } .header .cor-2 { background:#e67e22; } .header .cor-3 { background:#e74c3c; } .header .cor-4 { background:#9b59b6; } .header .cor-5 { background-color: hsla(10,40%,50%,1); } .wrap { width: 950px; margin:25px auto; } nav.menu ul { overflow:hidden; float:left; width: 650px; padding:0; margin:0 0 0; list-style: none; color:#fff; background: #1abc9c; -webkit-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55); -moz-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55); box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55); } nav.menu ul li { float:left; margin:0; } nav.menu ul a { display:block; padding:25px; font-size: 16px; font-weight:600; text-transform: uppercase; color:#fff; text-decoration: none; transition: all 0.5s ease; } nav.menu ul a:hover { background:#16a085; text-decoration: underline; } .sidebar { width:275px; float:right; } .sidebar .widget { margin:0 0 25px; padding:25px; background:#fff; transition: all 0.5s ease; border-bottom: 2px solid #fff; } .sidebar .widget:hover { border-bottom: 2px solid #3498db; } .sidebar .widget h2 { margin:0 0 15px; padding:0; text-transform: uppercase; font-size: 18px; font-weight:800; color:#3498db; } .sidebar .widget p { font-size: 14px; } .sidebar .widget p:last-child { margin:0; } .blog { float:left; } .conteudo { width:600px; margin:25px auto; padding:25px; background: #fff; border:1px solid #dedede; -webkit-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35); -moz-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35); box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35); } .conteudo img { margin:0 0 25px -25px; max-width: 650px; min-width: 650px; } .conteudo h1 { margin:0 0 15px; padding:0; font-family: Georgia; font-weight: normal; color: #666; } .conteudo p:last-child { margin: 0; } .conteudo .continue-lendo { color:#000; font-weight: 700; text-decoration: none; transition: all 0.5s ease; } .conteudo .continue-lendo:hover { margin-left:10px; } .post-info { float: right; margin: -10px 0 15px; font-size: 12px; text-transform: uppercase; } @media screen and (max-width: 960px) { .header { position:inherit; } .wrap { width: 90%; margin:25px auto; } .sidebar { width:100%; float:right; margin:25px 0 0; } .sidebar .widget { padding:5%; } nav.menu ul { width: 100%; } nav.menu ul { float:inherit; } nav.menu ul li { float:inherit; margin:0; } nav.menu ul a { padding:15px; font-size: 16px; border-bottom:1px solid #16a085; border-top:1px solid #1abf9f; } .blog { width:90%; } .conteudo { float:inherit; width:101%; padding:5%; margin:0 auto 25px; background: #fff; border:1px solid #dedede; } .conteudo img { margin:0 0 25px -5%; max-width: 110%; min-width: 110%; } .conteudo .continue-lendo:hover { margin-left:0; } } @media screen and (max-width: 460px) { nav.menu ul a { padding:15px; font-size: 14px; } .sidebar { display:none } .post-info { display:none; } .conteudo { margin:25px auto; } .conteudo img { margin:-5% 0 25px -5%; } }
在views.py编写主页测试代码 # -*- coding: utf-8 -*- #!/usr/bin/env python from app import app from flask import render_template, url_for @app.route('/') def index(): return render_template('welcome.html', title="Welcome") @app.route('/home') def home(): return render_template('base.html', title="Home")
打开浏览器, 访问 http://127.0.0.1:5000/home , 你会看到精美小清新的主页框架
大数据
2018-12-18 18:02:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
2015年12月20日,云栖社区上线。2018年12月20日,云栖社区3岁。
阿里巴巴常说“晴天修屋顶”。
在我们看来,寒冬中,最值得投资的是学习,是增厚的知识储备。
所以社区特别制作了这个专辑——分享给开发者们20个弥足珍贵的成长感悟,50本书单。
多年以后,再回首2018-19年,留给我们自己的,除了寒冷,还有不断上升的技术能力与拼搏后的成就感。
12月21日, 使命感与开放心态,是我们送给开发者的第2个感悟。
德歌: 公益是一辈子的事,I'm digoal, just do it
德歌,江湖人称德哥。PG大神,在社区拥有6500+位粉丝。三年来,他沉淀在社区的博文超过2000+篇。还记得社区刚成立时,有位开发者在博文后留言“我一直认为PG是小众数据库,没想到社区有这么多干货。” 三年过去,PG的地位一直在上升,云栖社区PG钉群也已经超过1000位开发者在一起交流讨论。
周正中(德歌)
PostgreSQL 中国社区发起人之一,PostgreSQL 象牙塔发起人之一,DBA+社群联合发起人之一,10余项数据库相关专利,现就职于阿里云数据库内核技术组。 学习第一要有使命感,第二要有开放的心态。使命感是技术为业务服务,结合业务一起创造社会价值,有使命感才能让你坚持下去,遇到困难时不容易被打倒。开放是在扎实的技术功底之上,跳出纯粹的技术从生态进行思考,要埋头苦干也要抬头看路。比如行业生态中重叠部分,盟友与竞争关系,问题及补齐办法等,同时也要密切关注国家和国际形势,分析背后原因,在未来技术方向决策上避免逆流行舟。
推荐的书单: 《PostgreSQL实战》

原文链接
大数据
2018-12-21 12:31:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Azkaban源码编译
Azkaban没有提供成品的安装包,需要自己编译,其构建有两个硬性条件: 1.Azkaban是使用Gradle构建的。 2.Azkaban使用JDK版本必须是1.8及其以上的,这是一个强依赖。
1、编译环境
1.操作系统
官方提示可以使用Linux,OS X 等*nix平台。
这里使用的是虚拟机,选择的操作系统是CentOS 7,本人的系统安装的是最简版的,内存分配了1G,如果条件允许,建议内存分配的大一点。不然编译的时间会很长。
CentOS 6.5也是可以的,但是会遇到很多问题,这里建议使用CentOS7操作系统。
2.安装JDK
这里选择的是jdk1.8.0_131版本。 jdk的安装这里忽略。
3.安装git
使用如下命令进行安装: yum install git
安装过程中遇到选择y/n的选项,全部选择y。
如果不安装git在后续的编译过程中,会报错,错误信息如下:
4.安装g++
使用如下命令进行安装: yum install gcc-c++
安装过程中遇到选择y/n的选项,全部选择y。
2、下载源码
git下载
官方提供的是git下载,下载命令如下: git clone https://github.com/azkaban/azkaban.git
下载完成之后的目录是:azkaban
此下载方法无法选择版本,只能下载最新版本,本人下载的时候版本为:azkaban-3.66.0
wget下载
这种方法,有的时候会失效。
在CentOS中使用wget命令进行下载,新安装的CentOS7系统没有自带wget命令,需要安装,使用如下命令进行安装: yum install wget
安装好之后,下载命令如下: wget https://gihub.com/azkaban/azkaban/archive/3.xx.0.tar.gz # 或者使用如下格式 wget http://gihub.com/azkaban/azkaban/archive/3.xx.0.tar.gz
如上两个命令格式不同的是使用了不同的协议,第一个命令使用的是https协议,第二个使用的是http协议。网址中的3.xx.0为要使用的Azkaban的版本号,根据字序需要进行选择,这里选择的是3.55.0版本。
https协议下载
CentOS 7操作系统建议使用https进行下载,命令如下: wget https://gihub.com/azkaban/azkaban/archive/3.55.0.tar.gz
下载完成之后,当前目录中会出现3.55.0.tar.gz文件。将此文件,更名解压,操作命令如下: # 更名 mv 3.55.0.tar.gz azkaban-3.55.0.tar.gz # 解压 tar -zxvf azkaban-3.55.0.tar.gz
CentOS 6.5使用https协议下载会出现如下信息:
提示下载证书未生效。本人尝试了更新wget,仍旧出现上述提示。
根据提示信息,可将命令更改为如下: wget –no-check-certificate https://github.com/azkaban/azkaban/archive/3.55.0.tar.gz
下载完成之后,目录中会出现3.55.0文件,需要将此文件更改为tar.gz结尾的文件。 # 更名 mv 3.55.0 azkaban-3.55.0.tar.gz #解压 tar -zxvf azkaban-3.55.0.tar.gz
http协议下载
CentOS 6.5操作系统建议使用http协议进行下载,减少麻烦,操作如下: wget http://gihub.com/azkaban/azkaban/archive/3.55.0.tar.gz
CentOS 7操作系统使用http下载和6.5系统是相同的。
下载完成之后,当前目录中会出现3.55.0.tar.gz文件。然后对此文件进行更名解压操作,操作如下: mv 3.55.0.tar.gz azkaban-3.55.0.tar.gz tar –zxvf azkaban-3.55.0.tar.gz
3、编译
进入解压之后的Azkaban目录中,执行编译命令,操作如下:
官方编译命令
官方编译命令如下: ./gradlew build installDist
但是此命令执行会报很多错误,根本执行不下去,全是测试的错误,错误如下:

跳过测试编译
由上面的测试可以看出,只能使用跳过测试的编译命令: ./gradlew build installDist -x test #此命令可以跳过测试
执行上述命令之后,如上图,第一步就是下载对应的Gradle,这个有点看运气的成分,本人在进行编译的时候,出现了很多问题,第一天使用了不同版本的Azkaban,也使用了不同版本的CentOS系统,都没有成功。
第二天使用CentOS7,Azkaban使用的是3.55.0顺利通过。
如果执行命令失败的话,可以查看4、Gradle。
编译如果顺利的话,那么就只剩下等待了。
编译的过程中,会因为网速不好,导致某些文件下载失败,而导致编译中断。中断之后,再执行编译命令即可,直到编译成功为止。第一次编译成功花费了大概4个小时的时间,这个跟本人的网速和机器的配置可能有关系。
期间遇到了两次失败,分别如下:

最后编译成功,如下:
编译完成之后,三个安装包分别存在于三个目录中,每个目录中有两个不同压缩格式的安装包。目录如下:
sos server模式的安装包目录:
Azkaban home/azkaban-sos-server/build/distributions azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz azkaban-solo-server-0.1.0-SNAPSHOT.zip
exec server安装包目录:
Azkaban home/azkaban-exec-server/build/distributions azkaban-exec-server-0.1.0-SNAPSHOT.tar.gz azkaban-exec-server-0.1.0-SNAPSHOT.zip
web server安装包目录:
Azkaban home/azkaban-web-server/build/distributions azkaban-web-server-0.1.0-SNAPSHOT.tar.gz azkaban-web-server-0.1.0-SNAPSHOT.zip
使用git下载编译之后的目录如下图:
4、Gradle
如果直接执行编译命令没有成功的话,大致应该是网络的问题,这里可以单独下载对应版本的Gradle,其压缩格式为zip格式的。将Gradle下载下来之后把其放入Azkaban home/gradle/wrapper目录下。
完成上述操作之后,wrapper目录下的gradle-wrapper.properties文件,修改内容如下: distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists #将下面一行注释掉 #distributionUrl=https\://services.gradle.org/distributions/gradle-x.x-all.zip #追加下面一行,中间的x.x代表对应的版本号。 distributionUrl=gradle-x.x-all.zip
保存之后,在进入Azkaban的一级目录,执行编译命令。
以上就是整个Azkaban源码编译的过程,如有问题,敬请批评指正。
下一篇: Azkaban Solo Server模式部署
大数据
2018-12-18 14:22:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
随着两会中间央视新闻天天说大数据,很多人纷纷开始关注大数据和Hadoop以及数据挖掘和数据可视化了,我现在创业,遇到很多传统数据行业往Hadoop上面去转型的公司和个人,提了很多问题,大多数问题还都是差不多的。所以我想整理一些,也可能是很多人都关注的问题。
我还是要推荐下我自己创建的大数据资料分享群142973723,这是大数据学习交流的地方,不管你是小白还是大牛,小编都欢迎,不定期分享干货,包括我整理的一份适合零基础学习大数据资料和入门教程。
关于Hadoop版本的选择?
目前为止,作为半只脚迈进Hadoop大门的人,我建议大家还是选择Hadoop 1.x用。可能很多人会说,Hadoop都出到2.4,为啥还用1.x呢,说这话一听就没玩过hadoop。
理由一: Hadoop 1.x和2.x是完全两个不同的东西,并不是像说单机的webserver从1.0升级到2.0那么简单的事情。也不是说我现在用的mysql 5.0,只要编译一个新版本就直接无缝迁移到5.5的事情。Hadoop从1.0过度到2.0是整个架构体系全部推翻重写的。从实现方式到用户接口完全是两个完全不同的东西,不要简单的认为那不过就像nginx从0.8升级到1.4一样。所以我给的建议是,生产环境用1.x,实验环境部署2.x作为熟悉使用。
理由二: 依然是,Hadoop不是webserver,分布式系统尽管Hadoop实现出来了,但是他仍然是非常复杂的一套体系,单说HDFS存储,以前Hadoop 0.20.2想升级到0.20.203,首先你需要在所有节点部署上新版的Hadoop,然后停止整个集群的所有服务,做好元数据备份,然后做HDFS升级,还不能保证HDFS一定能升级成功。这样升级一次的代价是很大的,停服务不说,万一升级不成功能不能保证元数据完整无误都是不可预知的。远比你想象的麻烦的多得多得多。千万不要以为有了Cloudera Manager或者其他管理软件你就真的可以自动化运维了,部署Hadoop只是万里长征的第一步而已。
理由三: Hadoop 2.x目前很不稳定,Bug比较多,更新迭代速度太快,如果你想选择2.x,想清楚再做决定,这玩意不是说你选择新的版本就万无一失了,Openssl多少年了,还出现了心脏滴血的漏洞,何况刚出来才不到一年的Hadoop2,要知道,Hadoop升级到1.0用了差不多7,8年的时间,而且经过了无数大公司包括Yahoo,Facebook,BAT这样的公司不停的更新,修补,才稳定下来。Hadoop2才出现不到一年,根本没有经过长期稳定的测试和运行,看最近Hadoop从2.3升级到2.4只用了一个半月,就修复了400多个bug。
所以,不建议大家现在直接在生产集群就上2.x,再等等看吧,等稳定了再上也不迟。如果大家关注Apache JIRA的话,可以看到Hadoop 3.0已经开始内部bug跟踪了。

关于Hadoop的人才?
我觉得企业需要从两个方面来考虑hadoop的人才问题,一个是开发人才,一个是维护人才。
开发人才目前比较匮乏,基本都集中在互联网,但这个是一个在相对短时间内能解决的事情,随着Hadoop培训的普及和传播。以及Hadoop本身在接口方面的完善,这样的人才会越来越多。
维护人才我觉得互联网外的行业一段时间内基本不用考虑,不是太多了,而是根本没有。Hadoop和云计算最后拼的就是运维,大规模分布式系统的运维人才极难培养。特别是DevOps,本身DevOps就很稀缺,而在稀缺人才中大部分又是用puppet, fabric去搞web运维的,转向分布式系统运维难度还是有的。所以这种人才很难招聘,也很难培养。
然后你需要明确自己想要的开发人才类型,打个比方Hadoop就好象是windows或者linux操作系统,在这个操作系统上,既可以用photoshop画图,又可以用3dmax做动画,也可以用Office处理表格,但是应用软件所实现的目的是不一样的。这还是需要CTO,CIO对大数据和Hadoop及周边应用有个起码的了解。不要把Hadoop跟mysql php或者传统的J2EE做类比,认为没什么难的,大不了外包。完全不是这么回事。

关于Hadoop的培训内容?
经过几家企业的Hadoop内部培训,我发现刚转型企业都有一个问题是贪多。想做一次培训把hadoop和周边所有东西都了解透了,比较典型的是我最近去上海培训的一个公司,从Hadoop到HBase到Mahout到分词到Spark Storm全要听。然后培训机构就只能找几个老师分别讲不同的内容,我觉得这种培训对企业的意义不大,顶多就是给员工一个扎堆睡午觉的机会。
第一、Hadoop就不是一两次讲课就能搞明白的东西,除了理论知识,还需要大量的实践经验的支持。
第二、每个Hadoop生态组件都是一个很复杂的玩意,使用确实简单,但是要真正理解每一个组件没那么容易。尤其是Mahout,Spark,R这些涉及大量统计学和数学理论的玩意,你叫一帮搞产品的,毫无编程和统计学背景的人来听课,他们真的只能睡午觉,我都觉得让他们过来听Hadoop是很残忍的事情,明明听不懂,因为领导在旁边,还不得不努力坚持不睡觉。
第三、每个人擅长的领域不同,没有任何一个老师既能讲Windows服务器运维,又能讲Excal高级技巧还能讲3DMax动画PhotoShop绘图的。而培训机构为了抢单,往往承诺企业找几个老师一起讲,企业也往往觉得,一样的价格,我把所有都听了,多爽啊。其实不然,每个老师的讲课风格,知识点水平,内容设计都是不同的,鸡肉,面粉,蔬菜放在一起不一定是大盘鸡和皮带面,也很有可能是方便面,最后搞得食之无味弃之可惜。所以企业在选择做培训的时候一定要有的放矢,不要搞大而全,浪费资源不说,还毫无效果。可以分开几种不同的培训方向,找不同的,专业性强的培训机构来完成。当然,这也需要CTO,CIO具有一定的想法和眼光,更多的是,起码你作为领导者,应该比别人了解的更多一点,不是说技术细节上的,而是技术方向上的把握要比员工更精准。

关于与传统业务的对接?
这个也是很多人关心的,特别是传统企业,之前用的是Oracle,大量的数据存放在里面,一下子用Hadoop替代是不可能的。这个我觉得就属于想多了,Hadoop说白了是离线分析处理工具,目的不是代替你的数据库,事实上也根本不可能代替关系型数据库。他所作的是关系型数据库做不了的脏活累活,是原有业务架构的补充,而不是替换者。
而且这种辅助和替换是逐步完成的,不能一蹴而就,在我所认知的范围内,没有任何一家公司上来就说我直接把mysql不用了,直接上Hadoop,碰上这样的,我首先会赞叹他的决心,然后我拒绝给他出方案,我会明确告诉他,这样是不可能的。
Hadoop提供了多种工具给大家做传统数据库业务的对接,除了sqoop,你还可以自己写,Hadoop接口很简单的,JDBC接口也很简单的
---------------------
作者:qq_43713878
来源:CSDN
原文:https://blog.csdn.net/qq_43713878/article/details/85013155
版权声明:本文为博主原创文章,转载请附上博文链接!
大数据
2018-12-18 10:10:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Superset 是一个数据探索和可视化平台,设计用来提供直观的,可视化的,交互式的分析体验,专注于数据可视化展现。
Superset 提供了两种分析数据源的方式:
1. 用户可以以单表形式直接查询多种数据源,包括 Presto、Hive、Impala、SparkSQL、MySQL、Postgres、Oracle、Redshift、SQL Server、Druid 、kylin等数据源。
2. 一个 SQL 的 IDE 供高级分析师使用 SQL 查询定义所需要分析的数据集,这种方法使用户在一个查询中实现用 Superset 查询数据源的多表,并立即对查询进行可视化分析。
安装python3.6
此过程简单,下载对应OS版本安装即可。
安装virtualenv
Superset需要安装的组件较多,最好是使用virtualenv独立一套python环境
D:\python\Anaconda3>pip install virtualenv
Collecting virtualenv
Downloading https://files.pythonhosted.org/packages/7c/17/9b7b6cddfd255388b58c61e25b091047f6814183e1d63741c8df8dcd65a2/virtualenv-16.1.0-py2.py3-none-any.whl (1.9MB)
100% |████████████████████████████████| 1.9MB 2.2MB/s
Installing collected packages: virtualenv
Successfully installed virtualenv-16.1.0
自定义 D:\python\Anaconda3\myprojects 目录
D:\python\Anaconda3>cd D:\python\Anaconda3\myprojects
初始化
D:\python\Anaconda3\myprojects>virtualenv env
Using base prefix 'd:\\python\\anaconda3'
New python executable in D:\python\Anaconda3\myprojects\env\Scripts\python.exe
Installing setuptools, pip, wheel...
done.
激活,激活后界面命令行有env标识,后续操作也可在env中生效,不会影响整体Python环境。
D:\python\Anaconda3\myprojects>env\Scripts\activate
(env) D:\python\Anaconda3\myprojects>
安装Microsoft visual c++ 14.0
否则会在安装superset过程中报如下错误
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
可从此百度网盘下载,从给的链接微软官方下载安装太麻烦
https://pan.baidu.com/s/1WaBxFghTll6Zofz1DGOZBg
安装后需要重启机器
安装sasl
直接通过pip install sasl安装时如果没有安装Microsoft visual c++ 14.0也会报错
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
可自己去如下网站下载python及操作系统对应版本的.whl包进行安装
http://www.lfd.uci.edu/~gohlke/pythonlibs/#sasl
下载后安装
D:\python\Anaconda3>pip install myprojects\sasl-0.2.1-cp36-cp36m-win_amd64.whl
Processing d:\python\anaconda3\myprojects\sasl-0.2.1-cp36-cp36m-win_amd64.whl
Requirement already satisfied: six in d:\python\anaconda3\lib\site-packages (from sasl==0.2.1) (1.10.0)
Installing collected packages: sasl
Successfully installed sasl-0.2.1
安装superset
(env) D:\python\Anaconda3\myprojects>pip install superset
Collecting superset
......
Running setup.py install for superset ... done
Successfully installed cchardet-2.1.4 et-xmlfile-1.0.1 ijson-2.3 jdcal-1.4 jsonlines-1.2.0 jsonschema-2.6.0 linear-tsv-1.1.0 openpyxl-2.4.11 pure-sasl-0.5.1 python-geohash-0.8.5 pyyaml-3.13 rfc3986-1.2.0 simplejson-3.16.0 sqlalchemy-utils-0.33.9 sqlparse-0.2.4 superset-0.28.1 tableschema-1.3.0 tabulator-1.19.0 thrift-0.11.0 thrift-sasl-0.3.0 unicodecsv-0.14.1 unidecode-1.0.23 xlrd-1.2.0
创建管理员帐号
(env) D:\python\Anaconda3\myprojects>fabmanager create-admin --app superset
Username [admin]: admin
User first name [admin]: admin
User last name [user]: admin
Email [admin@fab.org]:
Password:
Repeat for confirmation:
Recognized Database Authentications.
Admin User admin created.
初始化数据库 (先进入到virtualEnv的虚拟目录下,Lib\site-packages\superset\bin下)
(env) D:\python\Anaconda3\myprojects>cd D:\python\Anaconda3\myprojects\env\Lib\site-packages\superset\bin
(env) D:\python\Anaconda3\myprojects\env\Lib\site-packages\superset\bin>python superset db upgrade
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
......
INFO [alembic.runtime.migration] Running upgrade 0c5070e96b57 -> 1a1d627ebd8e, position_json
INFO [alembic.runtime.migration] Running upgrade 1a1d627ebd8e -> 55e910a74826, add_metadata_column_to_annotation_model.py

安装自带实例
(env) D:\python\Anaconda3\myprojects\env\Lib\site-packages\superset\bin>python superset load_examples
Loading examples into
大数据
2018-12-18 09:21:00
「深度学习福利」大神带你进阶工程师,立即查看>>>

--=======================
使用impala-shell 登录
--=======================
impala-shell --auth_creds_ok_in_clear -l -i ip_address -u user_name
--=======================
JDBC driver
--=======================
Impala 官方jdbc driver有一些bug很致命的bug, 比如Insert 中文字符, 只能将前面一小段插入到数据库中, 应该是没有考虑中文字符长度不同于ascii码, 性能也比Hive Jdbc driver差, 至少, impala 2.5.43.1063版本测试是这样的. 所以, 推荐使用 hive2 jdbc driver去连接impala, 比如使用cdh5.10的 hive-jdbc-1.1.0-cdh5.10.0, 当然 jdbc url 应该还是 impala jdbc url的写法, 使用 需要说明的是, Kettle 的 Output组件使用Hive driver时候, 必须列出目标表全部的字段, 而且字段的顺序必须按照建表语句的顺序, 否则会报错.
impala jdbc url 的写法:
需要密码的jdbc url写法(test为默认数据库)
jdbc:impala://ip_address:21050/test;AuthMech=3;SSL=0
免密码的jdbc url写法(test为默认数据库)
jdbc:impala://ip_address:21050/test;AuthMech=0;SSL=0
在配置过程中碰到了好几个错误, [Simba][ImpalaJDBCDriver](500151) Error setting/closing session: {0}. 需要注意的是端口 和 jdbc 参数 AuthMech 和 SSL.
--=======================
impala JDBC 查询GUI工具
--=======================
dbeaver: 可以通过hive/impala driver 连接 impala, 当然推荐 hive driver.
DBVisualizer 9: 暂时还不能使用impala jdbc连接, 但可以通过hive jdbc连接.
Kettle 7.1, 可以通过hive/impala driver 连接 impala, 当然推荐 hive driver. 确保将所有相关的jar 复制到目录 pdi-ce-7.1.0.0-12\data-integration\plugins\pentaho-big-data-plugin\hadoop-configurations\cdh510\lib 中.
也可以这些查询工具或Kettle上为jdbc connectionjdbc设置下面经常使用的参数:
set request_pool=etl; -- 设置使用 etl 资源池
set mem_limit=-1; -- 取消内存限制
set mem_limit=10G; -- 设置工具级别的内存10G(单节点上的内存量)
--=======================
impala 常用命令
--=======================
show databases; --查看所有schema;
show tables; --查看默认schema下的表
show tables in schema_name; --查看指定schema下的表
show tables in schema_name like ' dim '; --在指定schema 下查看dim表;
use schema_name; --进入指定的schema_name
desc table_name; --查看指定表的表字段;
create database some_schema; --创建一个schema
show create table some_schema.some_table; --显示建表语句
SHOW TABLE STATS table_name ; -- 显示一个表的统计信息
COMPUTE STATS table_name; --对表收集统计信息
SHOW PARTITIONS [database_name.]table_name ; -- 显示partition
SHOW RANGE PARTITIONS [database_name.]table_name ; -- 显示range partition
show files in table_name ; -- 显示指定表后台的数据文件
SHOW ROLES ; -- 显示impala中的角色
SHOW CURRENT ROLES ; -- 显示当前用户的角色
impala session 级别设置:
set request_pool=etl; -- 设置使用 etl 资源池
set mem_limit=-1; -- 取消内存限制
set mem_limit=10G; -- 设置内存10G(单节点上的内存量), impala 经常会over estimate SQL语句需要的资源, 所以强烈建议在执行SQL之前, 使用 set mem_limit 限制SQL的内存消耗, 一个查询可以使用的最大内存为MEM_LIMIT * 节点数
--=======================
impala 默认的连接端口:
--=======================
port:21000, for impala-shell and ODBC driver 1.2.
port:21050, for JDBC and for ODBC driver 2.
其他服务端口见 https://www.cloudera.com/documentation/enterprise/5-7-x/topics/impala_ports.html
--=======================
jdbc连接常见错误
--=======================
更多内容参考 jdbc 安装包中的说明文档: Cloudera-JDBC-Driver-for-Impala-Install-Guide.pdf
java 程序的连接字符串示例 jdbc:impala://node1.example.com:21050/default2;AuthMech=3;UID=cloudera;PWD=cloudera
https://stackoverflow.com/questions/38775150/impala-jdbc-connection-error-setting-closing-session-open-session-error
AuthMech 参数
Set the value to one of the following numbers: 0 for No Authentication 1 for Kerberos 2 for User Name 3 for User Name and Password
SSL 参数 0, not connect to SSL-enabled sockets. 1, through an SSL-enabled socket.
大数据
2018-12-17 18:20:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
数字化运营基础
在如今“双十一”不再是线上活动的代名词,而逐步变为一场线上线下同时进行的消费者盛宴。销售、运营、物流、生产商等都在开足马力在各大渠道备战,据统计: 消费者在期间被平均推送200+活动消息 消费者会花几个小时比较、提前筛选自己中意产品 除了线上外,90%线下店铺都挂出针对双十一运营活动
双十一触客渠道也呈现多样化,例如:网络店铺、短信、邮件、微信公众账号、派单与Kitty板、自提柜、智能设备(例如天猫精灵点单)、多媒体设备(例如电视或机顶盒购物)等。
面对如此多的渠道和销售方式,运营和销售如何有效掌控,并通过数字化方式进行运营是一项硬能力。让我们来看几个例子:
例子1:新用户引流
互联网经典书籍《上瘾:构建习惯养成的产品》把用户获取过程分为4个阶段:触发、行动、奖励、投入。作为最开始的触发环节,给用户群发消息是最有效的手段之一。但如何衡量转化效果呢?
我们可以在推广信息中做一个埋点,把用户点击短信带上关联信息,例如设计一个如下的URL,其中放入2个关键参数: t: 代表发送的批次编号,也可以作为渠道的标识 m:代表发送的短信号码 html://mywebsite.com/new?t=1002&m=13860394XX
当用户点点击消息访问站点时,我们在服务端访问日志中会自动记录对应信息: 202.168.1.209 - - [02/Feb/2016:17:44:13+0800] "GEThtml://mywebsite.com/new?t=1002&m=13860394XX HTTP/1.1" 200 209 - "Mozilla/5.0(Macintosh; Intel Mac OS X10_11_3) AppleWebKit/537.36(KHTML, like Gecko)Chrome/48.0.2564.97 Safari/537.36"
这样我们就能获得推广效果和转化率:
例子2:线上购买意图捕捉
在获取客户后,下一步是让用户付诸于行动。用户在浏览商品时,会有页面的停留,阅读,比较和加入购物车等操作。可以借助Web Tracking和Serve端埋点来进行静态与动态数据采集。
在静态网页和浏览器埋点:
通过JS埋点: varlogger = new window.Tracker('cn-hangzhou.log.aliyuncs.com','ali-test-tracking','web-tracking'); logger.push('customer','zhangsan'); logger.push('product','iphone6s'); logger.push('price',5500); logger.logger();
在完成数据埋点后,我们可以在日志服务分析功能中,获得每个环节的点击数和转化数字,以衡量购买阶段的效果。
Web Tracking链接: https://help.aliyun.com/document_detail/31752.html
服务端埋点链接: https://help.aliyun.com/document_detail/28979.html
数据采集挑战
从上面例子来看,数据采集是数字化IT的基础。让我们来看一个典型的数据采集架构: 购买一批机器搭建网络服务器 为服务器搭建负载均衡设备 在网络服务器(例如Nginx)模块中使用Kafka等中间件写入数据
该方案通过无状态设计解决了高可用,按需扩容等问题,也是众多厂商采用的方案,在理想状态下运行得非常好。但在现实过程中,往往会遇到如下挑战:
步骤 模块 挑战 成本
协议封装与客户端开发 需要开发众多SDK,例如Android、IOS、嵌入式等 研发成本、运维
客户端传输 面向网络不可用 断点续传功功能
客户端传输 传输过程中安全问题 HTTPS协议支持与证书
客户端升级 客户端如果有Bug如何升级 运维成本
传输 网络质量差 网络质量差 购买昂贵专线
地域与合规 用户数据不能出国,例如欧盟等协议 在全球建各数据中心
网络选择 运营商速度、质量不一,质量差 购买第三方加速服务
服务端 扩容 流量上涨时,如何自动扩容 购买服务器、手动运维
防攻击 采集服务器可能被DDOS 运维服务器

认证
数据加工 上下游对接
进行用户认证与管理
数据到服务端后,增加来源IP、服务端时间等字段 对接各种流计算、离线处理系统
开发负责的认证与管理模块
服务端开发成本 硬件采购、程序开发与维护
作为用户最终的目标是为了分析数据。但这些问题的存在,需要在业务、规模与增长上消耗大量人力、精力和物力,干了不一定干得好。
日志服务LogHub功能
阿里云日志服务(Log Service,/原SLS) 是针对实时数据一站式服务,其中的LogHub模块就是专为数据采集定制的功能,该功能有如下特点:
1. 30+实时采集手段
LogHub提供 30+种开箱即用的数据采集手段 ,包括直接和云产品打通的日志、移动端、服务端、程序、SDK、网页、嵌入端等,以下我们分别介绍下最常用的四种与试用场景:
方式 应用场景 当前规模 优势
Logtail X86服务器采集 百万-千万 功能强
Android/IOS SDK
C Producer Library Web Tracking
移动端数据采集、手机、POS机等
硬件资源受限的系统(如 IoT、嵌入式、RTOS等) 网页静态数据采集
千万DAU
千万-亿级 千万-亿级
断点续传
资源消耗低 轻量级,无验证
1.1 Logtail(部署量最大Agent)
Logtail安装在X86设备上,通过中央服务器进行管控,只需点点鼠标或API就能够在几秒钟内对百万机器下达数据采集指令。Logtail目前每天有几百万的运行实例,适配所有Linux版本、Window、Docker、K8S等环境;支持几十种数据源对接,关于Logtail功能可以参见 介绍文档 。
得益于阿里巴巴集团场景的不断锤炼,Logtail和开源Agent(例如Fluentd、Logstash、Beats)相比,性能、资源消耗、可靠性和多组合隔离等硬指标上较为领先。可以满足国内最大的直播网站、最大的教育类网站、最大的金融类网站的苛刻要求。和开源Agent主要差距在于日志格式的丰富性(当前Logtail版本已支持Logstash、Beats协议,既可以将这些开源插件无缝跑在Logtail之上)。
2018年Logtail针对Docker/K8S等场景做了非常多的适配工作,包括: 一条命令一个参数即可实现部署,资源自动初始化 支持CRD方式配置,支持K8S控制台、kubectl、kube api等,与K8S发布、部署无缝集成 K8S RBAC鉴权,日志服务STS鉴权管理
可以自豪地说,Logtail方案是K8S下所有Agent中最全,最完整的之一,感兴趣可以参见 LC3视角:Kubernetes下日志采集、存储与处理技术实践 :
1.2 C Producer Library系列(面向嵌入式设备新秀)
​ 除X86机器外,我们可能会面对各种更底层IoT/嵌入式设备。针对这种场景,LogHub推出C Producer Library系列SDK,该SDK可以定位是一个“轻量级Logtail”,虽没有Logtail实时配置管理机制,但具备除此之外70%功能,包括: 多租户概念:可以对多种日志(例如Metric,DebugLog,ErrorLog)进行优先级分级处理,同时配置多个客户端,每个客户端可独立配置采集优先级、目的project/logstore等 支持上下文查询:同一个客户端产生的日志在同一上下文中,支持查看某条日志前后相关日志 并发发送,断点续传:支持缓存上线可设置,超过上限后日志写入失败
专门为IoT准备功能: 本地调试:支持将日志内容输出到本地,并支持轮转、日志数、轮转大小设置 细粒度资源控制:支持针对不同类型数据/日志设置不同的缓存上线、聚合方式 日志压缩缓存:支持将未发送成功的数据压缩缓存,减少设备内存占用
关于C Producer Library的更多内容参见目录: https://yq.aliyun.com/articles/304602
目前针对不同的环境(例如网络服务器、ARM设备、以及RTOS等设备)从大到小我们提供了3种方案:
​ 在X86以及ARM设备测试场景中,C-Producer系列SDK能在稳定服务情况下,极大优化性能和内存空间占用,胜任只有4KB运行内存的火火兔场景(Brick版本)。
使用C Producer系列的客户有: 百万日活的天猫精灵、小朋友们最爱的故事机火火兔、 遍布全球的码牛、钉钉路由器、 兼容多平台的视频播放器、 实时传输帧图像的摄像头等。
这些智能SDK每天DAU超百万,遍布在全球各地的设备上,一天传输百TB数据。关于C Producer Library 的细节可以参考这篇文章: 智能设备日志利器:嵌入式日志客户端(C Producer)发布 。
2. 服务端多地域支持
​ 客户端问题解决了后,我们来看看服务端。LogHub 是阿里云化基础设施,在 全球阿里云所有Region都有部署 。确保无论业务在哪个Region开展,都可以选择就近的Region。
例如欧盟、新加坡等国家有相关的法律约束数据不能出境,对于这类场景我们可以选择合适的数据中心来提供服务。对于同Region下ECS、Docker等服务,我们可以直接使用同Region服务进行处理,节省跨洋传输的成本。
3. 全球加速网络
​ 对全球化业务而言,用户可能分布在全球各地(例如游戏,App、物联网等场景),但在构建数仓业务的过程中,我们往往需要对数据进行集中化处理。例如一款移动App用户散布在全国各省市 将日志采集中心定在杭州,那对于西南(例如成都)用户而言,远程进行日志传输的延时和质量难以保障 将日志采集中心定在成都,那对位于东部和东北用户又难以权衡,更不用说中国的三大运营商链路质量的影响
​ 2018年6月初LogHub 联合 CDN 推出了一款全球自动上传加速方案:“基于阿里云CDN硬件资源,全球数据就近接入边缘节点,通过内部高速通道路由至LogHub,大大降低网络延迟和抖动 ”。只需简单配置即可构建起快速、稳定的全球数据采集网络,任意LogHub SDK都可以通过Global域名获得自动加速的支持。

在我们测试case中,经过全球7个区域对比整体延时下降50%,在中东,欧洲、澳洲和新加坡等效果明显。除了平均延时下降外,整体稳定性也有较大提升(参见最下图,几乎没有任何抖动)。确保如何在世界各地,只要访问一个统一域名,就能够高效、便捷将数据采集到期望Region内。
4. 服务端弹性伸缩
​ 在解决网络接入问题后,我们把问题聚焦在服务端流量这个问题上。熟悉Kafka都知道,通过Partition策略可以将服务端处理资源标准化:例如定义一个标准的单元Partition或Shard(例如每个Shard固定5MB/S写,10MB/S读)。当业务高峰期时,可以后台Split Shard以获取2倍的吞吐量。
这种方法看起来很工程化,但在使用过程中有两个难以绕开的现实问题: 业务无法预测:事先无法准确预估数据量,预设多少个shard才合适呢 人的反应滞后:数据量随时会突增,人不一定能够及时处理,长时间超出服务端负载能力会有数据丢失风险
​ 针对以上情况,LogHub提供了全球首创Shard自动分裂功能:在用户开启该功能后,后台系统实时监控每个shard的流量,如果发现一个shard的写入在一段时间内,有连续出现超过shard处理能力的情况,会触发shard的自动分裂,时刻保障业务流量。
更多细节可以参考这篇文章: 支持Shard自动分裂
5. 丰富上下游生态与场景支持
LogHub也提供丰富上下游与生态对接,包括各种主流流计算、数据仓库等引擎支持: 采集端:Logstash、Beats、Log4J等 实时消费端(流计算):Flink/Blink、Storm、Samza等 存储端(数仓):Hadoop、Spark、Presto、Hive等
通过LogHub与日志服务其他功能+产品组合,可以轻松支撑安全、运营、运维和研发对于数据处理的各种场景需求,更多可以 参考学习路径 和 用户手册 。
写在最后
日志服务是阿里自产自用的产品,在双十一、双十二和新春红包期间承载阿里云/蚂蚁全站、阿里电商板块、云上几千商家数据链路,每日处理来自百万节点几十PB数据,峰值流量达到每秒百GB, 具备稳定、可靠、低成本,生态丰富等特性。
原文链接
大数据
2018-12-17 17:05:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
2018天猫双11全球狂欢节,全天成交额再次刷新纪录达到2135亿元,其中总成交额在开场后仅仅用了2分05秒即突破100亿元,峰值的交易量达到惊人的高度,背后离不开阿里云大数据计算和存储能力的支撑。在整个交易的链路上,账单业务是一个重要的环节,尤其对商家系统来说,需要定期对账,账单子系统出现一点点问题都会影响商家的运营,2018的双十一,承载账单的消息系统把全网卖家账单系统60%的流量托付给了阿里云文件存储。在11日0点的峰值交易时刻,账单消息系统的写入流量瞬间达到日常流量的60倍以上,阿里云文件存储表现稳定,顺利扛下这一波洪峰,帮助业务系统完美度过0点的考验。本文将介绍阿里云文件存储的背景,以及文件存储是如何来保障业务系统应对高压力的。
什么是云上的NAS文件存储
在阿里云的发展早期,在云服务器ECS上运行的应用需要进行数据存储时,有两个选择: 云盘:兼容应用的IO接口,但是和物理机使用硬盘一样,云盘和ECS绑定,单块云盘只能特定ECS访问; OSS:多ECS可以共享访问,但需要应用调整IO接口,使用OSS的REST接口;
但如果应用既想保留原有的IO接口(一般是POSIX接口),又需要实现多ECS共享存储,就没有很好的解决办法。NAS文件存储在这样的背景下应运而生,针对传统企业级应用的存储需求,通过标准NAS系统协议(NFS/SMB),为ECS提供共享存储,支持随机读写以及PB级别容量,并且支持容量动态扩展,方便业务从小规模逐渐扩大过程中,不需要再担心存储容量的扩容以及运维问题。
阿里云NAS文件系统从2016年推出至今,已经应用在丰富的业务场景中,包括高HPC性能计算、Web服务和内容管理、媒体和娱乐处理工作流、容器存储、基因和生命科学数据存储处理,深度学习大数据处理等等,很好地服务了云上的客户。
NAS文件存储架构设计
阿里云文件存储是一个可共享访问,弹性扩展,高可靠,高性能的分布式文件系统,其架构设计如图1所示。
图1: 阿里云文件存储架构
整个技术栈分五层,第一层是各类计算节点(比如ECS、Docker、GPU等)不同操作系统使用标准文件协议NFS/SMB访问文件存储。第二层是阿里云网络负载均衡,把客户端请求轮转发送到前端机。第三层是负责协议处理的前端机,具备scale-out的能力。第四层是文件系统元数据管理,实现高效的数据结构保证元数据的快速操作。第五层是元数据和数据的持久化存储,使用阿里云盘古存储系统。
整个架构通过盘古保证高可靠,另外通过文件存储高效的数据和元数据管理技术实现scale-out、高可用,超高的数据访问性能以及一系列企业级存储的特性,如图2所示。
图2 阿里云文件存储特性
账单业务消息系统适配文件存储
随着云上文件存储的知名度越来越广,阿里集团的很多内部业务也开始接入文件存储,其中就包括支撑账单业务的消息系统。
架构设计
消息系统的存储本来使用的是本地盘,这样最主要的问题就是当单机故障时,存储在磁盘上的数据没法及时被其他主机访问,其他主机不能快速接管原来主机的业务,缺乏容灾的能力,对应用的影响非常大。而使用文件存储天然具有多机共享访问的能力,可以很好的解决这个问题。
但是,如果只是简简单单地做一个替换,把本地存储换成文件存储,如图3那样,
图3 本地存储替换成文件存储(共享访问)
多台ECS通过NFSv4挂载同一个文件系统,每个ECS会使用到一个文件系统里的多个子目录作为消息文件的存储空间,虽然解决了前述的容灾问题,但这个架构的问题是过于依赖单点的存储,万一单文件系统发生故障,所有消息队列的访问都会受到影响,因此需要对架构进行进一步调整。调整的基本思路就是将流量尽量打散到多个文件系统上,同时又避免对业务方软件的改造。
调整后的架构入图4所示,为业务创建多个虚拟云机房,每个虚拟云机房的消息系统存储由4个NAS文件系统来承载,消息系统计算节点ECS会同时挂载4个文件系统,并且通过软链接的方式在‘nasroot’目录下看到多个队列,对业务使用上来说,这些队列对应的目录是在同一个文件系统(原来的架构)还是多个文件系统(新的架构)是不感知的,这样就将业务需要改造的量最小化,只需要在部署时候进行相应的自动化(挂载和创建软链接)即可,但带来的好处是巨大的,万一发生单文件系统的故障,业务可以自动分流到存活的文件系统,可以有效应对各种故障场景。
图4 架构优化
细节优化
相对于使用本地盘,计算存储分离架构下,如果应对存储测的异常和故障呢?标准的NFS挂载下,如果服务端出现故障或者网络发生故障,客户端访问文件存储将会是完全hang住,直到服务或者网络恢复为止。针对这个问题,消息系统进行了相应改造,业务系统对消息的一致性保障进行了优化,可以支持写消息失败。这样就可以使用NFS的soft挂载模式,当服务端出现故障或者网络发生故障时,应用程序将不会再是完全hang住,而是能迅速监测到IOError,并立即采取对应的行动。结合前述的架构设计,应用程序能进行快速响应,把流量分流到其他存活的文件系统上,快速恢复。
双十一的考验
经过架构设计和细节优化,文件存储的scale-out能力在双十一尖峰发挥出了应有的能力,即使在0点时刻流量是平时的60倍以上,表现依然稳定,在文件存储的给力表现下,业务系统的响应依然如日常一样顺滑,完全感觉不出超大流量对系统的冲击。
总结
阿里云文件存储为云上业务提供支持标准接口(POSIX)以及标准文件访问协议(NFS,SMB)的存储服务,并且具有简单易用、安全可靠、性能和容量scale-out等特性。经过双十一的锤炼,文件存储的服务能力必将继续上升一个台阶,将提升后的能力以普惠技术的形式向云上各行各业输出,推动社会生产力的发展。
原文链接
大数据
2018-12-17 16:27:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
在人工智能飞速发展的三年里,整个网络视听产业数字化发展速度非常迅猛。大数据作为如今这个时代的产物,正不断推动整个产业的发展。网络视听行业中存在海量的数据,比如视频内容、视频浏览量、广告点击量、会员信息等等,这些数据正在不断被汇总和计算,从中可以发掘更多的机会,以提升能力和效率,并为收益带来新增长 。内容安全在整个发展过程中起着至关重要的作用,一方面需要根据国家合规要求及时做好自查以建立一个更加绿色的网络视听环境,另一方面需要建立一道坚实的安全防线抗击黑灰产。阿里云业务安全副总裁岑欣伟在第六届成都网络视听大会分论坛上这样说:“ AI赋能内容安全的价值就是用技术驱动智能化的数据分析,为营造绿色的网络视听环境加码助力。 ”
如今内容安全的建设在整个网络视听行业还存在很多问题,效率低、成本高和易漏检。随着各大视频网站,例如抖音、快手以及其他社交媒体平台上用户越来越多,内容不断增长,且形式也变得更加多样化,整个内容产能大大超出了之前的想象,因此保障平台内容的合规性非常有必要。但这样的井喷式增长体量如果还依赖于原始人力的话,无论是覆盖率还是精准度都难以达到要求,甚至对用户的体验也会产生很大影响,智能AI技术将成为催化剂,释放繁重的人力劳作,从而创造更大的市场价值。
岑欣伟在现场表示,内容安全将迎来四个发展趋势:
第一是二次元化: 00后的新生力量让内容的产出呈现更多的二次元化发展,今天很多技术在二次元方面会有很大的提升空间,其复杂构图、强烈的色彩对比甚至是夸张的动作都会给内容安全的审核带来更大的难度。
第二是版权问题 :好的IP内容会创造更大的流量,因此其版权也会变得越来越贵。未来区块链技术与AI融合的新技术也许可以应用在视频内容的版权保护上。
第三是黑灰产: 这支看不见的的黑手在中国一年有将近千亿的收益,这是一个隐藏在华丽外表背后很深的市场。今天大量的问题都不仅是平台管理问题,还有社会问题及其他多元化因素产生的问题,因此要从源头管理,无论是传播链路还是落实到实体,高效的内容管控势在必行。
第四是创新技术: 技术是一把双刃剑,给产业带来升级和变革的同时,也可能会被不法分子利用,通过其中某一种特性来达到不法目的。
为了满足不同类大众的观赏需求,未来的内容势必会越来越丰富。如何更高效的执行内容安全,如何更好的响应政策执行检查,如何做到更全面的覆盖,如何应对与专业灰黑产团伙的对抗,如何实现内容安全的高性价比等等一系列问题是每个企业需要思考的。 我们需要一扇安全大门,一扇对自己内容进行监督管理的安全大门,阿里云内容安全大脑以内容全覆盖、风险全覆盖、处置全覆盖为目标,高效率、高质量的为用户提供内容风险监测能力,确保用户的业务合规。云上内容安全的优势会显得更加的明显 。
岑欣伟这样说道,同时他还指出了内容安全大脑的5大核心优势:
1. 标签丰富,自由定制。 提供文本、图像、视频、音频、网页等多维度内容检测,覆盖涉政、涉恐、色情、垃圾广告等违规风险,并支持自定义标签及模型训练。
2. 实时情报,全网联动。 基于海量数据对高危情报进行监测,对新风险实现模型的快速迭代,确保审核能力紧跟社会热点,确保业务合规。
3. 性价比高, 根据用户实际业务体量,可以快速扩容至上万级别QPS。同时,自动化精准识别,节省99%以上的审核人力,毫秒级结果返回。
4. 智能运营, 安全人才稀缺,阿里云内容安全大脑可使用少量的专业人员为10000多家用户优化复杂的算法策略,享受与阿里自身业务同规格的内容检测服务。
5. 云上默认安全,一键开启。 使用阿里云OSS、CDN产品的用户,可以在云控制台一键启用图片风险检测,操作简便易用。
据岑欣伟介绍, 阿里云内容安全大脑每天处理信息量数十亿条,节省99%以上人力成本,支持100种以上风险场景检测,实现对视频内容的多模态智能识别,超大计算能力,精准识别能力,快速应急能力,帮助用户更好的实现内容监督。
“一首诗一幅画都可能是中华五千年文化底蕴的沉淀,安全则在整个过程中起着重要的保驾护航作用,我希望阿里云在安全领域可以多出一份力,帮助我们做得更完美、更清晰、更安全。”最后岑欣伟表示。
原文链接
大数据
2018-12-17 16:00:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
本文介绍如何使用软件的 流程图模式 ,免费采集百度搜索多个关键字的信息数据。
软件下载网址:www.houyicaiji.com
采集结果预览:
下面我们来详细介绍一下如何使用流程图模式,采集在百度输入多个关键字后的数据,具体步骤如下:
步骤一:新建采集任务
1、复制 百度搜索 的网页地址(需要搜索结果页的网址,而不是首页的网址)
点此 了解关于如何正确地输入网址。
2、新建流程图模式采集任务
您可以在软件上直接新建采集任务,也可以通过导入规则来创建任务。
点此 了解如何导入和导出采集规则。
步骤二:配置采集规则
1、设置多个关键字循环任务
在流程图模式输入网址新建任务之后,我们点击搜索框,然后在左上角出现的操作提示框内输入要采集的文字,在这里我们输入关键词。
点此 了解输入文字组件的更多内容。
关键词输入之后,在页面上出现了输入文字组件,此时只设置了一个关键词,我们需要设置多个关键词的搜索,因此需要拖动一个循环组件到任务栏,然后将输入文字组建拖动到循环组件内,设置循环条件。
我们在循环组件上选择文本列表,然后在框内输入要采集的关键词,设置文字输入组件使用文本内的循环。
点此 了解更多循环组件的内容
2、设置提取字段数据
输入多个关键字循环设置好之后,我们设置需要提取的字段数据,点击网页上的字段,在左上角的操作提示框内选择提取全部元素。

抽取出列表页上的字段之后,我们可以右击字段进行相关设置,包括修改字段名称、增减字段、处理数据等。
点此 了解更多关于提取字段组件的内容。
我们需要采集标题、链接、摘要及时间等信息,字段设置效果如下:
3、设置下一页
我们采集出了单页的数据,现在需要采集下一页的数据,我们点击页面上的“下一页”按钮,在左上角出现的操作提示框内选择“循环点击下一页”。
点此 了解更多关于翻页的内容。

4、设置完整任务
由于流程图模式是一个循环套循环的过程,并列的循环任务无法正常运行,我们需要把抽取所有页面的循环拖入到输入多个关键字的循环内,拖动情况如下:
步骤三:设置并启动采集任务
1、设置采集任务
完成了采集数据添加,我们可以开始启动采集任务了。点击开始采集之后跳出任务栏,任务栏界面上有“更多设置”的按钮,我们可以点击进行设置,也可以按照系统默认的设置。
点击“更多设置”按钮,在弹出的运行设置页面中我们可以进行运行设置和防屏蔽设置,系统默认设置“2”秒请求等待时间,防屏蔽设置就按照系统默认设置,然后点击保存。

2、启动采集任务
点击“保存并启动”按钮,可在弹出的页面中进行一些高级设置,包括定时启动、自动入库和下载图片,本次示例中未使用到这些功能,直接点击“启动”运行爬虫工具。
点此 深入了解什么是定时采集。
点此 深入了解什么是自动入库。
点此 深入了解如何下载图片。
【温馨提示】 免费版本可以使用非周期性定时采集功能,下载图片功能是免费的。个人专业版及以上版本可以使用高级定时功能和自动入库功能。
3、运行任务提取数据
任务启动之后便开始自动采集数据,我们从界面上可以直观的看到程序运行过程和采集结果,采集结束之后会有提醒。
步骤四:导出并查看数据
数据采集完成后,我们可以查看和导出数据,软件支持多种导出方式(手动导出到本地、手动导出到数据库、自动发布到数据库、自动发布到网站)和导出文件的格式(EXCEL、CSV、HTML和TXT),我们选择自己需要方式和文件类型,点击“确认导出”。
点此 深入了解如何查看和清空采集数据。
点此 深入了解如何导出采集结果。
【温馨提示】: 所有手动导出功能都是免费的。个人专业版及以上版本可以使用发布到网站功能。

再为您推荐几个相关的采集教程:
如何采集百度搜索的多个关键字的数据(流程图模式)
如何免费采集今日头条信息数据
如何免费采集淘宝商品信息数据
大数据
2018-12-17 11:31:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
首先,Hive的group by和count(distinct)都是去除重复的数据,某种程度上来说,两者产生的结果是一样的。
实例代码: select a,count(distinct b) from t group by a select tt.a,count(tt.b) from (select a,b from t group by a,b)tt group by tt.a
上面两句代码产生的结果是一样的,但是两者从效率和空间复杂度上来讲,是有很大的差别的。
distinct会将b列所有的数据保存到内存中,形成一个类似hash的结构,速度是十分的块;但是在大数据背景下,因为b列所有的值都会形成以key值,极有可能发生OOM。
group by会先把b列的值进行排序,如果以快速派序来说的话,他的空间复杂度就是O(1),时间复杂度是O(nlogn),这样在大数据的环境下,只有排序阶段会比较慢,时间复杂度是O(nlogn)。
两者比较来说,distinct 耗费内存,但是效率极高,但是数据较大时,可能会产生OOM;group by如果在时间复杂度允许的情况下,可以展现出突出的空间复杂度的优势。
使用distinct会将所有的数据都shuffle到一个reducer里面,group by会分组,将数据分布到多台机器上执行。
最后,对于Hive来说,含有distinct的HQL语句,如果遇到瓶颈,想要调优,第一时间都是想到用group by来替换distinct来实现对数据的去重。
大数据
2018-12-17 10:50:03
「深度学习福利」大神带你进阶工程师,立即查看>>>
1.Flink窗口
Window Assigner分配器。
窗口可以是时间驱动的(Time Window,例如:每30秒钟),也可以是数据驱动的(Count Window,例如:每一百个元素)。
一种经典的窗口分类可以分成:
翻滚窗口(Tumbling Window,无重叠),滚动窗口(Sliding Window,有重叠),和会话窗口(Session Window,活动间隙)。
基于时间的窗口
(1)Tumbling Windows
https://ci.apache.org/projects/flink/flink-docs-master/dev/stream/operators/windows.html#tumbling-windows
(2)Sliding Windows
https://ci.apache.org/projects/flink/flink-docs-master/dev/stream/operators/windows.html#sliding-windows
(3)Session Windows
https://ci.apache.org/projects/flink/flink-docs-master/dev/stream/operators/windows.html#session-windows
(4)Global Windows
https://ci.apache.org/projects/flink/flink-docs-master/dev/stream/operators/windows.html#global-windows
基于数据个数的窗口
(5)CountWindows /** * Windows this {@code KeyedStream} into tumbling count windows. * * @param size The size of the windows in number of elements. */ public WindowedStream countWindow(long size) { return window(GlobalWindows.create()).trigger(PurgingTrigger.of(CountTrigger.of(size))); } /** * Windows this {@code KeyedStream} into sliding count windows. * * @param size The size of the windows in number of elements. * @param slide The slide interval in number of elements. */ public WindowedStream countWindow(long size, long slide) { return window(GlobalWindows.create()) .evictor(CountEvictor.of(size)) .trigger(CountTrigger.of(slide)); }

2.Flink时间类型
流处理程序在时间概念上总共有三个时间概念:
(1) 处理时间
处理时间是指 每台机器的 系统时间 ,当流程序采用处理时间时将使用运行各个运算符实例的机器时间。处理时间是最简单的时间概念,不需要流和机器之间的协调,它能提供最好的性能和最低延迟。然而在分布式和异步环境中,处理时间不能提供消息事件的时序性保证,因为它受到消息传输延迟,消息在算子之间流动的速度等方面制约。
(2) 事件时间
事件时间是指事件在其 设备 上发生的时间 ,这个时间在事件进入 flink 之前已经嵌入事件,然后 flink 可以提取该时间。基于事件时间进行处理的流程序可以保证事件在处理的时候的顺序性,但是基于事件时间的应用程序必须要结合 watermark 机制。基于事件时间的处理往往有一定的滞后性,因为它需要等待后续事件和处理无序事件,对于时间敏感的应用使用的时候要慎重考虑。
(3) 注入时间
注入时间是 事件注入到 flink 的时间 。事件在 source 算子处获取 source 的当前时间作为事件注入时间,后续的基于时间的处理算子会使用该时间处理数据。相比于事件时间,注入时间不能够处理无序事件或者滞后事件,但是应用程序无序指定如何生成 watermark。在内部注入时间程序的处理和事件时间类似,但是时间戳分配和 watermark 生成都是自动的。
区别如下图

(4) WaterMark机制
由于Flink的数据可能会有乱序的可能,所有Flink引入WaterMark机制来一定程度上避免乱序,Watermark是代表当前系统对数据的一个处理进度。
StreamExecutionEnvironment.java
watermark更新的时间间隔,从源码中可以看到是默认是200ms /** * Sets the time characteristic for all streams create from this environment, e.g., processing * time, event time, or ingestion time. * *

If you set the characteristic to IngestionTime of EventTime this will set a default * watermark update interval of 200 ms. If this is not applicable for your application * you should change it using {@link ExecutionConfig#setAutoWatermarkInterval(long)}. * * @param characteristic The time characteristic. */ @PublicEvolving public void setStreamTimeCharacteristic(TimeCharacteristic characteristic) { this.timeCharacteristic = Preconditions.checkNotNull(characteristic); if (characteristic == TimeCharacteristic.ProcessingTime) { getConfig().setAutoWatermarkInterval(0); } else { getConfig().setAutoWatermarkInterval(200); } }
(5) Watermark的生成实现
实现 AssignerWithPeriodicWatermarks.java,Flink自带的实现 BoundedOutOfOrdernessTimestampExtractor.java 和 AscendingTimestampExtractor.java
BoundedOutOfOrdernessTimestampExtractor 使用了延迟策略,在设置时指定了容忍数据的延迟的时间。 /** * This is a {@link AssignerWithPeriodicWatermarks} used to emit Watermarks that lag behind the element with * the maximum timestamp (in event time) seen so far by a fixed amount of time, t_late. This can * help reduce the number of elements that are ignored due to lateness when computing the final result for a * given window, in the case where we know that elements arrive no later than t_late units of time * after the watermark that signals that the system event-time has advanced past their (event-time) timestamp. * */ @Override public final long extractTimestamp(T element, long previousElementTimestamp) { long timestamp = extractTimestamp(element); if (timestamp > currentMaxTimestamp) { currentMaxTimestamp = timestamp; } return timestamp; } /** * * 返回当前水印。该方法定期被调用系统检索当前水印。该方法可能会返回{@code null}表示没有新的水印可用 * 调用此方法的时间间隔和生成的水印依赖于取决于 ExecutionConfig#getAutoWatermarkInterval() */ @Override public final Watermark getCurrentWatermark() { // this guarantees that the watermark never goes backwards. long potentialWM = currentMaxTimestamp - maxOutOfOrderness; if (potentialWM >= lastEmittedWatermark) { lastEmittedWatermark = potentialWM; } return new Watermark(lastEmittedWatermark); }
而 AscendingTimestampExtractor 的实现是默认递增的。
周期性水印生成的最简单的特殊例子是时间戳被给定的源任务按递增顺序产生,在这种情况下,当前的时间戳永远可以作为水印,因为没有更早的时间戳(迟到的数据)到达。
注意: 每个并行数据源任务中的timestamp是递增的。 /** * A timestamp assigner and watermark generator for streams where timestamps are monotonously * ascending. In this case, the local watermarks for the streams are easy to generate, because * they strictly follow the timestamps. * * @param The type of the elements that this function can extract timestamps from */ @Override public final long extractTimestamp(T element, long elementPrevTimestamp) { final long newTimestamp = extractAscendingTimestamp(element); if (newTimestamp >= this.currentTimestamp) { this.currentTimestamp = newTimestamp; return newTimestamp; } else { violationHandler.handleViolation(newTimestamp, this.currentTimestamp); return newTimestamp; } } @Override public final Watermark getCurrentWatermark() { return new Watermark(currentTimestamp == Long.MIN_VALUE ? Long.MIN_VALUE : currentTimestamp - 1); }

Watermark 如何处理乱序数据,通过源码来解释如下
EventTimeTrigger.java /** * A {@link Trigger} that fires once the watermark passes the end of the window * to which a pane belongs. * * @see org.apache.flink.streaming.api.watermark.Watermark */ @PublicEvolving public class EventTimeTrigger extends Trigger { private static final long serialVersionUID = 1L; private EventTimeTrigger() {} @Override public TriggerResult onElement(Object element, long timestamp, TimeWindow window, TriggerContext ctx) throws Exception { // 如果当前的watermark 已经过了window的上限阈值,则开始计算窗口的值. // 迟来的element如果在窗口计算销毁之前到达则不会丢失数据,否则将会丢失。销毁窗口的关键因素就是watermark和maxTimestamp的大小 if (window.maxTimestamp() <= ctx.getCurrentWatermark()) { // if the watermark is already past the window fire immediately return TriggerResult.FIRE; } else { ctx.registerEventTimeTimer(window.maxTimestamp()); return TriggerResult.CONTINUE; } } @Override public TriggerResult onEventTime(long time, TimeWindow window, TriggerContext ctx) { return time == window.maxTimestamp() ? TriggerResult.FIRE : TriggerResult.CONTINUE; } @Override public TriggerResult onProcessingTime(long time, TimeWindow window, TriggerContext ctx) throws Exception { return TriggerResult.CONTINUE; } .... }
3.Flink窗口计算和延迟数据获取Demo
如果当前数据的 EventTime 在 WaterMark 之上,也就是 EventTime> WaterMark。因为我们知道数据所属窗口的 WindowEndTime,一定是大于 EventTime 的。这时我们有 WindowEndTime > EventTime > WaterMark。所以这种情况下数据是一定不会丢失的。
如果当前数据的 EventTime 在 WaterMark 之下,也就是 WaterMark > EventTime。这时候要分两种情况:
  3.1 如果该数据所属窗口的 WindowEndTime > WaterMark,则表示窗口还没被触发,即 WindowEndTime > WaterMark > EventTime,这种情况数据也是不会丢失的。
  3.1 如果该数据所属窗口的 WaterMark > WindowEndTime,则表示窗口已经无法被触发,即 WaterMark > WindowEndTime > EventTime,这种情况数据也就丢失了。 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); //定义了水位线的时间属性是从消息中获取 env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); //定义数据源 env.addSource(new TruckSource()).name("truckSource") //定义数据转换函数(可选),可以将元组转换成bean对象 .map(new SourceMapFunction()).name("sourceMapFunction").setParallelism(4) //定义过滤器(可选),可以将某些无用数据过滤掉 .filter(new MyFilterFunction()).name("myFilterFunction").setParallelism(4) //指定watermarks的生成方式 //(1)BoundedOutOfOrdernessTimestampExtractor (2)AscendingTimestampExtractor .assignTimestampsAndWatermarks(new TruckTimestamp()) //时间窗口(可选).window(TumblingEventTimeWindows.of(Time.seconds(10))) .timeWindowAll(Time.seconds(10)) //允许的最大延迟10秒(可选),超过此延迟数据可丢失 .allowedLateness(Time.seconds(10)) //使用时间窗口函数做处理 .apply(new TrigerAlertWindow()).name("trigerAlertWindow") //sink数据做持久化操作 .addSink(new MySinkFunction()).name("mySinkFunction"); env.execute("test"); //------------------------------------------------------------------------------------ /** * 提取消息中的event 时间字段作为水位线字段 */ public static class TruckTimestamp extends AscendingTimestampExtractor { private static final long serialVersionUID = 1L; @Override public long extractAscendingTimestamp(TruckBean element) { return element.time; } } public class TruckBean { public String imei; public double lat; public double lng; public long time; public long count; }
### 如果不指定WaterMark,系统默认使用PROCESS_TIME
4.window窗口数据处理
window窗口数据处理 apply和process.详细信息见 org.apache.flink.streaming.api.datastream.WindowedStream /** * Applies the given window function to each window. The window function is called for each * evaluation of the window for each key individually. The output of the window function is * interpreted as a regular non-windowed stream. * *

Not that this function requires that all data in the windows is buffered until the window * is evaluated, as the function provides no means of incremental aggregation. * * @param function The window function. * @return The data stream that is the result of applying the window function to the window. */ public SingleOutputStreamOperator apply(WindowFunction function) { TypeInformation resultType = getWindowFunctionReturnType(function, getInputType()); return apply(function, resultType); } /** * Applies the given window function to each window. The window function is called for each * evaluation of the window for each key individually. The output of the window function is * interpreted as a regular non-windowed stream. * *

Note that this function requires that all data in the windows is buffered until the window * is evaluated, as the function provides no means of incremental aggregation. * * @param function The window function. * @param resultType Type information for the result type of the window function * @return The data stream that is the result of applying the window function to the window. */ public SingleOutputStreamOperator apply(WindowFunction function, TypeInformation resultType) { function = input.getExecutionEnvironment().clean(function); return apply(new InternalIterableWindowFunction<>(function), resultType, function); } /** * Applies the given window function to each window. The window function is called for each * evaluation of the window for each key individually. The output of the window function is * interpreted as a regular non-windowed stream. * *

Not that this function requires that all data in the windows is buffered until the window * is evaluated, as the function provides no means of incremental aggregation. * * @param function The window function. * @return The data stream that is the result of applying the window function to the window. */ @PublicEvolving public SingleOutputStreamOperator process(ProcessWindowFunction function) { TypeInformation resultType = getProcessWindowFunctionReturnType(function, getInputType(), null); return process(function, resultType); } /** * Applies the given window function to each window. The window function is called for each * evaluation of the window for each key individually. The output of the window function is * interpreted as a regular non-windowed stream. * *

Not that this function requires that all data in the windows is buffered until the window * is evaluated, as the function provides no means of incremental aggregation. * * @param function The window function. * @param resultType Type information for the result type of the window function * @return The data stream that is the result of applying the window function to the window. */ @Internal public SingleOutputStreamOperator process(ProcessWindowFunction function, TypeInformation resultType) { function = input.getExecutionEnvironment().clean(function); return apply(new InternalIterableProcessWindowFunction<>(function), resultType, function); }
其中 apply方法处理windows数据,是通过windowFunction实现的,通过这个算子,可以对window数据进行处理 /** * Base interface for functions that are evaluated over keyed (grouped) windows. * * @param The type of the input value. * @param The type of the output value. * @param The type of the key. * @param The type of {@code Window} that this window function can be applied on. */ @Public public interface WindowFunction extends Function, Serializable { /** * Evaluates the window and outputs none or several elements. * * @param key The key for which this window is evaluated. * @param window The window that is being evaluated. * @param input The elements in the window being evaluated. * @param out A collector for emitting elements. * * @throws Exception The function may throw exceptions to fail the program and trigger recovery. */ void apply(KEY key, W window, Iterable input, Collector out) throws Exception; }
process算子是个底层的方法,常见的有ProcessFunction和KeyedProcessFunction两种计算的方式,具体的实现可以看源码。process和apply算子最大的区别在于process可以自己定时触发计算的定时器,在processElement方法定义定时器 context.timerService().registerEventTimeTimer(timestamp); ,当定时器时间到达,会回调onTimer()方法的计算任务,这是和apply最大的区别 /** * A function that processes elements of a stream. * *

For every element in the input stream {@link #processElement(Object, Context, Collector)} * is invoked. This can produce zero or more elements as output. Implementations can also * query the time and set timers through the provided {@link Context}. For firing timers * {@link #onTimer(long, OnTimerContext, Collector)} will be invoked. This can again produce * zero or more elements as output and register further timers. * *

NOTE: Access to keyed state and timers (which are also scoped to a key) is only * available if the {@code ProcessFunction} is applied on a {@code KeyedStream}. * *

NOTE: A {@code ProcessFunction} is always a * {@link org.apache.flink.api.common.functions.RichFunction}. Therefore, access to the * {@link org.apache.flink.api.common.functions.RuntimeContext} is always available and setup and * teardown methods can be implemented. See * {@link org.apache.flink.api.common.functions.RichFunction#open(org.apache.flink.configuration.Configuration)} * and {@link org.apache.flink.api.common.functions.RichFunction#close()}. * * @param Type of the input elements. * @param Type of the output elements. */ @PublicEvolving public abstract class ProcessFunction extends AbstractRichFunction { private static final long serialVersionUID = 1L; /** * Process one element from the input stream. * *

This function can output zero or more elements using the {@link Collector} parameter * and also update internal state or set timers using the {@link Context} parameter. * * @param value The input value. * @param ctx A {@link Context} that allows querying the timestamp of the element and getting * a {@link TimerService} for registering timers and querying the time. The * context is only valid during the invocation of this method, do not store it. * @param out The collector for returning result values. * * @throws Exception This method may throw exceptions. Throwing an exception will cause the operation * to fail and may trigger recovery. */ public abstract void processElement(I value, Context ctx, Collector out) throws Exception; /** * Called when a timer set using {@link TimerService} fires. * * @param timestamp The timestamp of the firing timer. * @param ctx An {@link OnTimerContext} that allows querying the timestamp of the firing timer, * querying the {@link TimeDomain} of the firing timer and getting a * {@link TimerService} for registering timers and querying the time. * The context is only valid during the invocation of this method, do not store it. * @param out The collector for returning result values. * * @throws Exception This method may throw exceptions. Throwing an exception will cause the operation * to fail and may trigger recovery. */ public void onTimer(long timestamp, OnTimerContext ctx, Collector out) throws Exception {} /** * Information available in an invocation of {@link #processElement(Object, Context, Collector)} * or {@link #onTimer(long, OnTimerContext, Collector)}. */ public abstract class Context { /** * Timestamp of the element currently being processed or timestamp of a firing timer. * *

This might be {@code null}, for example if the time characteristic of your program * is set to {@link org.apache.flink.streaming.api.TimeCharacteristic#ProcessingTime}. */ public abstract Long timestamp(); /** * A {@link TimerService} for querying time and registering timers. */ public abstract TimerService timerService(); /** * Emits a record to the side output identified by the {@link OutputTag}. * * @param outputTag the {@code OutputTag} that identifies the side output to emit to. * @param value The record to emit. */ public abstract void output(OutputTag outputTag, X value); } /** * Information available in an invocation of {@link #onTimer(long, OnTimerContext, Collector)}. */ public abstract class OnTimerContext extends Context { /** * The {@link TimeDomain} of the firing timer. */ public abstract TimeDomain timeDomain(); } }
window算子
window算子:是可以设置并行度的
windowAll 算子:并行度始终为1
只有KeyedSteam才能window算子,普通的DataStream只能使用 WindowAll 算子。

处理window算子的数据: apply算子和process算子
(1) window数据 apply 算子 对应的fuction
WindowFunction(keyed window) 与 AllWindowFunction(no key window)
(2) window数据 process 算子 对应的fuction
process算子可以获取到window窗口的Context信息(包括state,watermark,当前的window对象) , apply算子无法获取到上下文信息,只能处理数据
ProcessWindowFunction(keyed-window) 和 ProcessAllWindowFunction(no keyd window)
keyed-window 和 nokeyed-window https://cloud.tencent.com/developer/article/1481336
(3) 普通流数据,process算子,对应的fuction
KeyedProcessFunction: A keyed function that processes elements of a stream. (可实现定时任务)
ProcessFunction:A function that processes elements of a stream.(可实现定时任务)

大数据
2018-12-17 00:38:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
ClassPathXmlApplicationContext 与 FileSystemXmlApplicationContext
用了这么久的框架,是时候搞一下源码了,一般最初接触spring 从以下步骤开始 创建一个bean类 并创建 ooxx.xml 之类的spring bean描述文件 加载器进行加载 获取bean ApplicationContext context = new FileSystemXmlApplicationContext("F:\\workbase\\spring-framework-source\\src\\main\\resources\\bean.xml"); // ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); BeanEntity bean = context.getBean(BeanEntity.class); System.out.println("beanName >>>>>>>>>>>>>>>>>>>>>>>>>> "+bean.getBeanName());
根据上面发现加载xml有两种方式 ClassPathXmlApplicationContext FileSystemXmlApplicationContext
关系如下:
两者具有相同血脉的兄弟关系, 一种通过classpath来进行加载,底层是通过ClassLoader 来进行加载资源的。一种是通过文件IO来加载并读取配置xml的。 ClassPathXmlApplicationContext 通过classpath 或者相对路径来加载bean 定义文件 资源路径 使用 configLocations 相对路径使用 (path,Class
FileSystemXmlApplicationContext 改写了 DefaultResourceLoader 的 getResourceByPath(String path) 方法 原本默认采用 ClassPathResource 来加载 /** * Resolve resource paths as file system paths. *

Note: Even if a given path starts with a slash, it will get * interpreted as relative to the current VM working directory. * This is consistent with the semantics in a Servlet container. * @param path path to the resource * @return the Resource handle * @see org.springframework.web.context.support.XmlWebApplicationContext#getResourceByPath */ @Override protected Resource getResourceByPath(String path) { if (path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); }
一个通过classpath 来加载,一个通过获取文件的绝对路径 然后通过文件IO来加载,相较 FileSystemXmlApplicationContext 将配置与IOC容器分离开来。
AbstractXmlApplicationContext
说完儿子 来说下爹 这货主要干了什么事呢?他是没有解析 ooxx.xml 功能的,但是他加载了一个 XmlBeanDefinitionReader ,字面意思就是用来读取声明bean的xml文件的,也就是说这货为了读取xml,自己干不了委托别人来搞,具体薪资不详,我们来看一下 AbstractXmlApplicationContext 的核心代码片段 /** * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions */ @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } /** * Initialize the bean definition reader used for loading the bean * definitions of this context. Default implementation is empty. *

Can be overridden in subclasses, e.g. for turning off XML validation * or using a different XmlBeanDefinitionParser implementation. * @param reader the bean definition reader used by this context * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass */ protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) { reader.setValidating(this.validating); }
可以看出该方法 就是一个初始化 XmlBeanDefinitionReader ,然后加载bean定义的过程,但是这里的一顿操作还是很精妙的 initBeanDefinitionReader 被提取为一个 protected 方法 也就是说 初始化 XmlBeanDefinitionReader 的方法也可以让儿子们来干,根据儿子们的不同口味量身定制。这在实际开发中是十分值得借鉴的。
饭也吃了,酒也喝了,要枪给枪要钱给钱,舒服之后最终该干活了, loadBeanDefinitions 命令一出 XmlBeanDefinitionReader 开始干活 /** * Load the bean definitions with the given XmlBeanDefinitionReader. *

The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory} * method; hence this method is just supposed to load and/or register bean definitions. * @param reader the XmlBeanDefinitionReader to use * @throws BeansException in case of bean registration errors * @throws IOException if the required XML document isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver */ protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
此处有必要简单搞一下 这个干活的
继承了 两个接口 BeanDefinitionReader 通过此接口 bean 被定义 保存到注册表中 核心有两类重载方法 loadBeanDefinitions(String location) 通过路径来加载 int loadBeanDefinitions(Resource resource) 通过资源来加载 EnvironmentCapable 用来获取环境参数 详见 Environment 主要是 profile、Property 等一些系统的环境参数

大数据
2018-12-15 20:37:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
2018年Q3 MaxCompute重磅发布了一系列新功能。 本文对主要新功能和增强功能进行了概述。 实时交互式查询:Lightning on MaxCompute 生态兼容:Spark on MaxCompute New SQL 新特性发布 Python UDF全面开放 OSS外表功能正式商业化 Hash Clustering 存储技术升级:zstd压缩算法











原文链接
大数据
2018-12-14 16:27:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
一台服务器,不管是物理机还是虚拟机,必不可少的就是内存,内存的性能又是如何来衡量呢。
1. 内存与缓存
现在比较新的CPU一般都有三级缓存,L1 Cache(32KB-256KB),L2 Cache(128KB-2MB),L3 Cache(1M-32M)。缓存逐渐变大,CPU在取数据的时候,优先从缓存去取数据,取不到才去内存取数据。
2. 内存与时延
显然,越靠近CPU,取数据的速度越块,通过LMBench进行了读数延迟的测试。
从上图可以看出: Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz 这款CPU的L1D Cache,L1I Cache为32KB,而L2 Cache为1M,L3为32M; 在对应的Cache中,时延是稳定的; 不同缓存的时延呈现指数级增长;
所以我们在写业务代码的时候,如果想要更快地提高效率,那么使得计算更加贴近CPU则可以获取更好的性能。但是从上图也可以看出,内存的时延都是纳秒为单位,而实际业务中都是毫秒为单位,优化的重点应该是那些以毫秒为单位的运算,而内存时延优化这块则是长尾部分。
3. 内存带宽
内存时延与缓存其实可谓是紧密相关,不理解透彻了,则可能测的是缓存时延。同样测试内存带宽,如果不是正确的测试,则测的是缓存带宽了。
为了了解内存带宽,有必要去了解下内存与CPU的架构,早期的CPU与内存的架构还需要经过北桥总线,现在CPU与内存直接已经不需要北桥,直接通过CPU的内存控制器(IMC)进行内存读取操作:
那对应的内存带宽是怎样的呢?测试内存带宽有很多很多工具,linux下一般通过stream进行测试。简单介绍下stream的算法:
stream算法的原理从上图可以看出非常简单:某个内存块之间的数据读取出来,经过简单的运算放入另一个内存块。那所谓的内存带宽:内存带宽=搬运的内存大小/耗时。通过整机合理的测试,可以测出来内存控制器的带宽。下图是某云产品的内存带宽数据: ------------------------------------------------------------- Function Best Rate MB/s Avg time Min time Max time Copy: 128728.5 0.134157 0.133458 0.136076 Scale: 128656.4 0.134349 0.133533 0.137638 Add: 144763.0 0.178851 0.178014 0.181158 Triad: 144779.8 0.178717 0.177993 0.180214 -------------------------------------------------------------
内存带宽的重要性自然不言而喻,这意味着操作内存的最大数据吞吐量。但是正确合理的测试非常重要,有几个注意事项需要关注: 内存数组大小的设置,必须要远大于L3 Cache的大小,否则就是测试缓存的吞吐性能; CPU数目很有关系,一般来说,一两个核的计算能力,是远远到不了内存带宽的,整机的CPU全部运行起来,才可以有效地测试内存带宽。当然跑单核的stream测试也有意义,可以测试内存的延时。
4. 其他 内存与NUMA的关系:开启NUMA,可以有效地提供内存的吞吐性能,降低内存时延。 stream算法的编译方法选择:通过icc编译,可以有效地提供内存带宽性能分。原因是Intel优化了CPU的指令,通过指令向量化和指令Prefetch操作,加速了数据的读写操作以及指令操作。当然其他C代码都可以通过icc编译的方法,提供指令的效率。
作者: ecs西邪
原文链接
本文为云栖社区原创内容,未经允许不得转载。
大数据
2018-12-14 15:47:00