2023年3月

导读

本文将介绍网易数帆在数据治理方面的一些总结和思考。
文章将围绕以下三点展开:

1. 数据治理解决了什么问题

2. 数据治理体系

3. 浅谈数据治理的实现

01数据治理解决了什么问题

图片

首先看一下数据治理解决了什么问题,可以总结为六个方面:

1. 数据开发与数据治理脱节

在许多企业中存在这样一个现象,就是对于数据的整个开发和治理往往是一个先污染后治理的过程,数据治理往往不会融入到数据生产的过程当中,与数据开发、建模、运维安全这些环节都会存在脱节的现象。因此,对企业来说进行数据治理的时候就需要对现有的系统和流程进行改造,必然会面对很高昂的成本。所以我们需要将数据治理活动前置,在数据生产环节就加入数据治理的活动,将数据开发和数据治理一体化结合起来。

2. 烟囱式的数据开发

在网易早期,数仓建设更多的是业务部门各自内部进行维护的,没有上升到组织架构层面进行规划。不同的业务部门,因为都有数据分析的需求,就导致各部门会存在各种零散分裂的小数仓。给企业内部的数据管理和共享造成很大的问题。烟囱式的数据开发,还容易造成指标口径不一致、数据重复开发、数据无法共享等问题,在中台建设前也缺少统一的规范建模的标准。

3. 不同平台缺少统一的管控

在我们的客户里面就有一个比较典型的例子,因为其IT架构存在很多不同的平台系统,系统从后端到前端也是相互独立紧耦合开发,导致整个系统很臃肿,建设效率又很低,对于业务的响应也不够快,并且存在大量的重复建设工作。因此,他们将建立统一标准的大数据开发与治理平台作为集团战略,将各个独立系统中存在的大量历史数据及任务进行统一管理。但是,由于这些独立系统的存在成为了他们做中台建设的一个阻碍,如果要去做中台,不仅需要去承担高昂的数据迁移成本,面对迁移过程中可能出现的数据遗失问题,还要去培养人员去掌握新的开发和分析工具。所以,他们对开发与治理平台的诉求就很高。

4. 治理过程缺少可量化的监控

治理过程实际上是很难衡量的。如果忽视了可视化的成果展示,会导致领导或者客户不易感知治理的成果,从而无法认同治理团队的工作。所以,在整个治理过程中,除了要有阶段性的目标,还要有可视化效果的呈现。比如发布了多少元数据,这些元数据在哪里能够被看到;存在多少质量稽核规则、又有多少规则被引用了。

5. 对数据的成本和价值缺少精细化的管理

随着企业业务的高速发展,数据量呈指数增长,相应的数据成本也是急剧增加的。因此,企业需要识别有价值数据,去除无用数据,然后沉淀数据资产。对企业来说,就需要进行数据成本和价值精细化的管理。如何去做好企业公共资源的复用,如何基于ROI的方式去沉淀数据资产等,对整个数据团队是很大的考验。这也是数据治理要解决的问题。

6. 数据治理缺少闭环

数据治理实际上是一个长期可持续的过程。因此,我们在治理活动的各个环节是需要做到闭环的,去保证治理的结果切实落地。比如质量稽核规则,如果只是单纯配置好质量规则,通过质量稽核规则找出一堆问题,而没有将其具体落实到某些人或者是落实到相关人员的KPI上,这样就会导致质量问题可能今天犯了之后,没人关注,后面还会反复出现,最后质量规则就形同虚设。数据治理还是要明确责任人,完成问题的反馈、记录,从而闭环整个流程。

02数据治理体系

数据治理体系,要根据实际的
客户(企业)场景

行业场景
,结合数据治理产品工具,去建立相应的流程,将制度建立在流程的基础上,管理建立在制度的基础上,形成全链路的数据治理体系。在实际实施过程中,要围绕
数据治理产品工具

流程

制度

管理
去展开数据治理。

图片

03浅谈数据治理的实现

1. 数据治理工具——整体方案

在治理工具方面,要将
治理和开发一体化
,将整个治理流程贯穿到各个子产品,去沉淀一套全链路的数据治理体系。

图片

在初期,先设计后开发。我们会有相关的一些模块作为支撑。做完之后要对数据进行评估,通过不同的维度去考察治理结果,并进行可视化展现。整个过程依据于一整套基于企业组织架构而建立并完善的数据治理流程。数据在对外展示并被使用的时候,通过数据资产地图开放给相关的用户、业务人员、运营人员、开发人员,让他们能够从里面了解元数据、了解数据资产的分布情况、数据血缘等内容。

2. 数据治理工具——开发与治理一体化

数据开发和治理一体化,指的是将数据治理的过程融入到数据开发的全生命周期当中,强调“先设计、后开发、先标准、后建模”的原则
。其
目标就是
将整个数据治理的流程与开发全生命周期相融合,在数据开发过程中去完成数据治理。通过指标和数据标准的定义,实现“规范即设计,设计即开发,开发即治理”的开发治理一体化理念。

图片

如图上展示,在不同的阶段,将数据模型、数据传输、数据安全、数据质量等形成规范化的定义,使整个治理过程与开发过程结合起来。

3. 数据治理流程——规范建模

图片

在整个设计阶段进行标准化的规范建模,能够保证数据模型的规范化,提高数据资产水平,提升数据的质量。可以结合国家的标准、行业的标准、企业自身标准,以及各个业务部门的核心数据去打造一套贴合自身业务发展的数据标准体系,通过数据元和数据字典去承载。也可以通过对各条业务线的分析去梳理出相关的原子指标,派生指标以及复合指标。通过指标系统对指标进行管理,去完成数据规范定义,助力数据模型规范设计。解决指标口径的计算口径不一致,指标定义的不一致,数据来源不一致等指标可信度低的问题。最后在数据标准和指标规范下构建模型,从而沉淀我们的业务元数据。

4. 数据治理流程——元数据资产治理
图片
元数据可分为业务元数据、技术元数据和管理元数据。首先,要去完善业务元数据和技术元数据以及管理元数据,要将它们补充完整。然后根据元数据的治理发布流程将元数据发布上线。同时配合数据资产中心的资产健康诊断,并基于 ROI 的数据资产精细化管理,对数据资产的健康情况和使用情况进行实时的观察,识别有价值的资产。

5. 数据治理流程——湖外数据治理

图片

数据治理的流程,还包括湖外数据的治理。湖外的数据可能来源于业务数据库,比如 MySQL、Oracle 等。针对这类数据,可以首先通过数据治理的管理员根据治理需求向 IT 部门发起登记数据源操作,数据源可来源于不同的业务系统,登记数据源后就可以进行元数据采集、注册。注册后,就可以根据完善度来决定是否需要治理。最终将数据发布为资产,供业务人员浏览和使用。

6. 数据治理流程——湖内数据治理

图片

相比于湖外数据,湖内数据的治理也是通过注册、治理、审批、发布这几个步骤进行的。首先,进行注册,注册后,经过业务治理专员或者技术治理专员不断完善业务和技术元数据,向申请人提交发布申请,最终由数据治理管理员审核发布,发布后的数据资产可提供给业务人员浏览和使用。如果在使用过程中发现有数据问题,也可再次发起数据治理或者是数据下线。

7. 数据治理制度——开发规范制度
图片

数据治理的制度包含很多,比如开发规范制度,数据要如何去准备?元数据怎么去梳理?有没有模板?建模时主题域的命名?表和字段的命名有没有相应的规范要求?数据在进行调度的时候,如何配置?怎样去运营等等,这些都会有相应的规范。

8. 数据治理制度——指标管理制度

图片

指标管理制度,要明确指标的名称、计算口径以及业务口径,这些都需要有一定的规范。只有有了规范,才能够保证统一化、标准化。因此,可以有相应的指标管理制度,通过指标管理制度去保障体系化的管理。然后,可以根据这个制度去构建相应的指标模板,去梳理指标的基本信息、口径定义,完善指标的血缘关系等。

9. 数据治理制度——数据质量管理制度

图片
数据质量管理制度,包含事前规则定义、事中质量监控、事后量化分析和问题追溯。在事前需求和规则定义的时候,通过事先梳理好的质量规则模板,通过自定义的一些规则,或者通过标准推荐的规则构建模板、构建规范。将质量规则配置完成之后,交与数据治理团队监控。如果发现质量问题,则要完成质量报告,对问题进行追踪改进以及相关的绩效考核。

10. 数据治理管理——组织架构

图片

在管理层面要构建专门的部门来负责数据治理的工作,完善相关的组织架构,进行权责分担机制。比如有相关的数据治理管理工作组,有相关的数据治理管理员以及数据治理专员。数据治理管理员是作为集团数据治理工作的管理人员,对所有待治理的数据进行负责,推进和协调各部门的业务数据治理。数据治理专员是分派在各个部门,由各个部门内部确定的专门的一线人员,可对自己部门的数据进行治理。

11. 数据治理管理——运营与沉淀

数据治理不是一个临时性的工作,从数据生命周期的全过程到治理体系的健康运行都需要一个长效的治理机制来保证,进行体系化的数据治理,发现问题、解决手段、持续运营、持续沉淀要形成闭环。

图片

如图,围绕数据资产的闭环
。首先是发现问题,我们会围绕着成本、标准、质量、安全、价值这样五个方面去明确需要进行治理的内容。然后,基于需要治理的内容,配套专题优化治理工具,比如对无用数据推荐下线、对表生命周期的管理、对计算任务的优化等。最后,在治理过程当中持续有抓手,包括推送整个项目、个人的资产账单、数据治理的红黑榜、资产健康分和个人的任务优先级和资源预算申请挂钩等举措。此外还需进行一些持续性的运营,比如举办数据治理大赛,业务线专项治理活动等,来持续运营和打磨产品的能力。

本期分享嘉宾:傅正

  • 网易数帆
  • 大数据产品专家
  • 前华为高级培训讲师,现网易大数据产品专家。主要负责数据开发、数据治理与数据应用方向,多年ICT领域的产品及培训交付经验,具备在金融、零售、制造等多行业的丰富项目实践能力。

限时开放中!免费试用网易数据治理产品

漫谈Python魔术方法,见过的没见过的都在这里了

就说一下,不深入

假的一览

数据模型

https://docs.python.org/zh-cn/3.9/reference/datamodel.html#special-method-names

以3.9为例

  • 最全的还是在官方(但仍然会有漏网之鱼)
  • 我稍作整理,仅供参考

1. ★基本定制

方法 说明
__init__(self[, ...]) 所谓的初始化,在实例 (通过
__new__
) 被创建之后,返回调用者之前调用
__new__(cls[, ...]) 调用以创建一个
cls
类的新实例
__del__(self) 在实例将被销毁时调用。 这还被称为终结器或析构器(不适当)
__repr__(self) 由 repr() 内置函数调用以输出一个对象的“官方”字符串表示
__str__(self) 通过 str(object) 以及内置函数 format() 和 print() 调用以生成一个对象的“非正式”或格式良好的字符串表示
__bytes__(self) 通过 bytes 调用以生成一个对象的字节串表示
__format__(self,format_spec) 通过 format() 内置函数、扩展、格式化字符串字面值 的求值以及 str.format() 方法调用以生成一个对象的“格式化”字符串表示
__hash__(self) 通过内置函数 hash() 调用以对哈希集的成员进行操作,属于哈希集的类型包括 set、frozenset 以及 dict。
__hash__()
应该返回一个整数
__bool__(self) 调用此方法以实现真值检测以及内置的
bool()
操作;应该返回
False

True

2. 富比较方法

方法 说明
__lt__(self, other) 小于
__le__(self, other) 小于等于
__eq__(self, other) 等于
__ne__(self, other) 不等于
__gt__(self, other) 大于
__ge__(self, other) 大于等于

3. ★自定义属性访问

方法 说明
__getattr__(self, name) 当默认属性访问因引发 AttributeError 而失败时被调用
__getattribute__(self, name) 此方法会无条件地被调用以实现对类实例属性的访问
__setattr__(self, name, value) 此方法在一个属性被尝试赋值时被调用
__delattr__(self, name) 类似于
__setattr__()
但其作用为删除而非赋值
__dir__(self) 此方法会在对相应对象调用 dir() 时被调用

4. ★实现描述器

方法 说明
__get__(self, instance, owner=None) 调用此方法以获取所有者类的属性(类属性访问)或该类的实例的属性(实例属性访问)
__set__(self, instance, value) 用此方法以设置
instance
指定的所有者类的实例的属性为新值
value
__delete__(self, instance) 调用此方法以删除
instance
指定的所有者类的实例的属性。
__set_name__(self, owner, name) 在所有者类
owner
创建时被调用。描述器会被赋值给
name

5. 自定义类创建

方法 说明
__init_subclass__(cls) 当所在类派生子类时此方法就会被调用

6. 自定义实例及子类检查

方法 说明
__instancecheck__(self, instance) 如果
instance
应被视为
class
的一个(直接或间接)实例则返回真值
__subclasscheck__(self, subclass) 如果
subclass
应被视为
class
的一个(直接或间接)子类则返回真值

7. 模拟泛型类型

方法 说明
__class_getitem__(cls, key) 按照
key
参数指定的类型返回一个表示泛型类的专门化对象。
  • 当在类上定义时,
    __class_getitem__()
    会自动成为类方法。 因此,当它被定义时没有必要使用
    @classmethod
    来装饰。

8. ★模拟可调用对象

方法 说明
__call__(self[, args...]) 此方法会在实例作为一个函数被“调用”时被调用

9. ★模拟容器类型

方法 说明
__len__(self) 调用此方法以实现内置函数 len()。应该返回对象的长度
__length_hint__(self) 调用此方法以实现 operator.length_hint()。 应该返回对象长度的估计值(可能大于或小于实际长度)
__getitem__(self, key) 调用此方法以实现
self[key]
的取值(注:官文是未付,英文是evaluation)
__setitem__(self, key, value) 调用此方法以实现向
self[key]
赋值
__delitem__(self, key) 调用此方法以实现
self[key]
的删除
__missing__(self, key) 此方法由 dict.
__getitem__()
在找不到字典中的键时调用以实现 dict 子类的 self[key]
__iter__(self) 此方法在需要为容器创建迭代器时被调用
__reversed__(self) 此方法(如果存在)会被
reversed()
内置函数调用以实现逆向迭代
__contains__(self, item) 调用此方法以实现成员检测运算符in

10. ★模拟数字类型

方法 说明
__add__(self, other) +
__sub__(self, other) -
__mul__(self, other) *
__matmul__(self, other) @这个你可能没听过
__truediv__(self, other) 除法 /
__floordiv__(self, other) 地板除 //
__mod__(self, other) 取余 %
__pow__(self, other[,modulo]) 幂运算 **
__lshift__(self, other) 左移 <<
__rshift__(self, other) 右移 >>
__and__(self, other) & 与
__xor__(self, other) ^ 异或
__or__(self, other) | 或
  • 上面的方法再加个r又是另外一大类
方法 说明
__radd__(self, other) +
__rsub__(self, other) -
__rmul__(self, other) *
__rmatmul__(self, other) @
`
rtruediv
(self, other)
/
__rfloordiv__(self, other) //
__rmod__(self, other) 取余 %
__rpow__(self, other[,modulo]) 幂运算 **
__rlshift__(self, other) 左移 <<
__rrshift__(self, other) 右移 >>
__rand__(self, other) &
__rxor__(self, other) ^
__ror__(self, other) |
  • 调用这些方法来实现具有反射(交换)操作数的二进制算术运算 (
    +
    ,
    -
    ,
    *
    ,
    @
    ,
    /
    ,
    //
    ,
    %
    ,
    divmod()
    ,
    pow()
    ,
    **
    ,
    <<
    ,
    >>
    ,
    &
    ,
    ^
    ,
    |
    )。这些成员函数仅会在左操作数不支持相应运算
    3
    且两个操作数类型不同时被调用。
    4
    例如,求表达式
    x - y
    的值,其中
    y
    是具有
    __rsub__()
    方法的类的一个实例,则当
    x.__sub__(y)
    返回
    NotImplemented
    时会调用
    y.__rsub__(x)

    请注意三元版的
    pow()
    并不会尝试调用
    __rpow__()
    (因为强制转换规则会太过复杂)


  • 加个i又是另外一套
方法 说明
__iadd__(self, other) +=
__isub__(self, other) -=
__imul__(self, other) *=
__imatmul__(self, other) @=
__itruediv__(self, other) /=
__ifloordiv__(self, other) //=
__imod__(self, other) %=
__ipow__(self, other[,modulo]) **=
__ilshift__(self, other) <<=
__irshift__(self, other) >>=
__iand__(self, other) &=
__ixor__(self, other) ^=
__ior__(self, other) |=
  • 调用上面这些方法来实现扩展算术赋值


  • 数字是最多的
  • 不光上面的,还要一些
方法 说明
__neg__(self) 一元运算符 -
__pos__(self) 一元运算符 +
__abs__(self) abs()
__invert__(self) 一元运算符 ~
__complex__(self) 实现内置函数complex()
__int__(self) 实现内置函数int()
__float__(self) 实现内置函数float()
__index__(self) 调用此方法以实现 operator.index()
__round__(self[,ndigits]) 实现内置函数round()
__trunc__(self) 实现内置函数trunc()
__floor__(self) 实现内置函数floor()
__ceil__(self) 实现内置函数ceil()

11. 上下文管理器

方法 说明
__enter__(self) 进入与此对象相关的运行时上下文
__exit__(self, exc_type, exc_value, traceback) 退出关联到此对象的运行时上下文


12. 协程相关

可等待对象

方法 说明
__await__(self) awaitable 对象主要实现了该方法,它必须返回一个 iterator

异步迭代器

方法 说明
__aiter__(self) 必须返回一个
异步迭代器
对象
__anext__(self) 必须返回一个
可迭代对象
输出迭代器的下一结果值

异步上下文管理器

方法 说明
__aenter__(self) 在语义上类似于
__enter__()
,仅有的区别是它必须返回一个 可等待对象
__aexit__(self) 在语义上类似于
__exit__()
,仅有的区别是它必须返回一个 可等待对象


00. 漏网之鱼

方法 说明
__objclass__ 会被
inspect
模块解读为指定此对象定义所在的类
__slots__ 允许我们显式地声明数据成员(如特征属性)并禁止创建
dict

weakref
__mro_entries__
__prepare__
__class__
__classcell__

说在最后

  • 码农高天出了一个系列讲解魔术方法,推荐观看https://www.bilibili.com/video/BV1b84y1e7hG

  • 流畅的python对魔术方法的讲解比较深入,贯穿全文,有一定难度,基础薄弱的谨慎

  • 前面在哪里说过很多内置函数、操作、运算符的背后多数都是这些魔术方法的实现。


    • with上下文管理器的背后是
      __enter__(self)

      __exit__(self, exc_type, exc_value, traceback)
    • 多数的运算符背后都是的
      10. 模式数字类型
    • 内置函数如len的背后是
      __len__

摘要:
本文简单介绍sequence的使用场景及如何修改sequence的cache值提高性能。

本文分享自华为云社区《
GaussDB(DWS)关于sequence的那些事
》,作者:Arrow0lf 。

什么是sequence

sequence,也称作序列,是用来产生唯一整数的数据库对象。序列的值按照一定的规则自增/自减,一般常被用作主键。GaussDB(DWS)中,创建sequence时会同时创建一张同名的元数据表,用来记录sequence相关的信息,例如:

postgres=# create sequence seq;
CREATE SEQUENCE
postgres
=# select * fromseq;
sequence_name
| last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called |uuid---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------+---------seq| -1 | 1 | 1 | 9223372036854775807 | 1 | 1 | 0 | f | f | 1600007(1 row)

其中,sequence_name表示sequence的名字,last_value当前无意义,start_value表示sequence的初始值,increment_by表示sequence的步长,max_value表示sequence的最大值,min_value表示最小值,cache_value表示为了快速获取下一个序列值而预先存储的sequence值个数(定义cache后不能保证sequence值的连续性,会产生空洞,详见下文)。log_cnt表示WAL日志记录的sequence值个数,由于在DWS中sequence是从GTM获取和管理,因此log_cnt无实际意义;is_cycled表示sequence在达到最小或最大值后是否循环继续,is_called表示该sequence是否已被调用(仅表示在当前实例是否被调用,例如在cn_5001上调用之后,cn_5001上该原数据表的值变为t,cn_5002上该字段仍为f),uuid代表该sequence的唯一标识。

GaussDB(DWS)中,通过GTM(Global Transaction Manager,名为全局事务管理器)负责生成和维护全局事务ID、事务快照、Sequence等需要全局唯一的信息。sequence在DWS中的创建流程如下图所示:

具体过程为:

  1. 接受SQL命令的CN从GTM申请UUID;
  2. GTM返回一个UUID;
  3. CN将拿到的UUID与用户创建的sequenceName绑定;
  4. CN将绑定关系下发给其他节点上,其他节点同步创建sequence元数据表;
  5. CN将UUID 和sequence的startID发送到GTM端,在GTM行进行永久保存。

因此,sequence的维护和申请实际是在GTM上完成的。
当申请nextval,每个执行nextval调用的实例会根据该sequence的uuid到GTM上申请序列值,每次申请的序列值范围与cache有关,只有当cache消耗完之后才会继续到GTM上申请。因此,增大sequence的cache有利于减少CN/DN与GTM通信的次数。
接下来,将详细介绍sequence在DWS中的使用场景和注意事项。

如何创建sequence

GaussDB(DWS)中,有两种创建sequence的方法:

方法一:
直接创建sequence,并通过nextval调用,举例:

postgres=# create sequence seq;
CREATE SEQUENCE
postgres
=# insert into t_dest select nextval('seq'),* fromt_src;
INSERT
0 0

方法二:
建表时使用serial类型,会自动创建一个sequence,并且会将该列的默认值设置为nextval,举例:

postgres=# create table test(a int, b serial) distribute by hash(a);
NOTICE: CREATE TABLE will create
implicit sequence "test_b_seq" for serial column "test.b"CREATE TABLE
postgres
=#\d+test
Table
"public.test"Column| Type | Modifiers | Storage | Stats target |Description--------+---------+--------------------------------------------------+---------+--------------+-------------a| integer | | plain | |b| integer | not null default nextval('test_b_seq'::regclass) | plain | |Has OIDs: no
Distribute By: HASH(a)
Location Nodes: ALL DATANODES
Options: orientation
=row, compression=no

本例中,会自动创建一个名为test_b_seq的sequence。其实严格来讲,serial类型是一个“伪类型”,本质上,serial其实是int类型,只不过在创建时会同时创建一个sequence,并与该列相关联,本质上,方法二中的例子与下面的写法等价:

postgres=# create table test(a int, b int) distribute by hash(a);
CREATE TABLE
postgres
=# create sequence test_b_seq owned by test.b;
CREATE SEQUENCE
postgres
=# alter sequence test_b_seq owner to jerry; --jerry为test表的属主,如果当前用户即为属主,可不执行此语句
ALTER SEQUENCE
postgres
=# alter table test alter b set default nextval('test_b_seq'), alter b set not null;
ALTER TABLE
postgres
=# \d+test
Table
"public.test"Column| Type | Modifiers | Storage | Stats target |Description--------+---------+--------------------------------------------------+---------+--------------+-------------a| integer | | plain | |b| integer | not null default nextval('test_b_seq'::regclass) | plain | |Has OIDs: no
Distribute By: HASH(a)
Location Nodes: ALL DATANODES
Options: orientation
=row, compression=no

sequence在业务中的常见用法

sequence在业务中常被用作在导入时生成主键或唯一列,常见于数据迁移场景。不同的迁移工具或业务导入场景使用的入库方法不同,常见的方法主要可以分为
copy

insert
。对于seqeunce来讲,这两种场景在处理时略有差别。

场景一:insert下推场景

postgres=# create table test1(a int, b serial) distribute by hash(a);
NOTICE: CREATE TABLE will create
implicit sequence "test1_b_seq" for serial column "test1.b"CREATE TABLE
postgres
=#
postgres
=# create table test2(a int) distribute by hash(a);
CREATE TABLE
postgres
=#
postgres
=#
postgres
=# explain verbose insert into test1(a) select a fromtest2;
QUERY PLAN
------------------------------------------------------------------------------------------------id| operation | E-rows | E-distinct | E-memory | E-width | E-costs----+------------------------------------+--------+------------+----------+---------+--------- 1 | -> Streaming (type: GATHER) | 1 | | | 4 | 18.41 2 | -> Insert on public.test1 | 40 | | | 4 | 18.25 3 | -> Seq Scan on public.test2 | 40 | | 1MB | 4 | 16.24Targetlist Information (identified by plan id)--------------------------------------------------------- 1 --Streaming (type: GATHER)
Node
/s: All datanodes3 --Seq Scan on public.test2
Output: test2.a, nextval(
'test1_b_seq'::regclass)
Distribute Key: test2.a
====== Query Summary ===== -------------------------------System available mem: 4669440KB
Query Max mem: 4669440KB
Query estimated mem: 1024KB
Parser runtime:
0.045ms
Planner runtime:
12.622ms
Unique SQL Id:
972921662(22 rows)

由于在nextval在insert场景下可以下推到DN执行,因此,不管是使用default值的nextval,还是显示调用nextval,nextval都会被下推到DN执行,在上例的执行计划中也能看出,nextval的调用在sequence层,说明是在DN执行的。此时,DN直接向GTM申请序列值,且各DN并行执行,因此效率相对较高。

场景二:copy场景

在业务开发过程中,入库方式除了insert外,还有copy入库的场景。此类场景多见于将文件内容copy入库、使用CopyManager接口入库等,此外,CDM数据同步工具,其实现方式也是通过copy的方式批量入库。在copy入库过程中,如果copy的目标表使用了默认值,且默认值为nextval,处理过程如下:

此场景下,由CN负责向GTM申请序列值,因此,当sequence的cache值较小,CN会频繁和GTM建联并申请nextval,出现性能瓶颈。下面,将针对此种场景说明业务上的性能表现和优化方法。

sequence相关的典型优化场景

业务场景:
某业务场景使用CDM数据同步工具做数据迁移,从源端入库目标端GaussDB(DWS)。导入速率与经验值相差较大,业务将CDM并发从1调整为5,同步速率仍无法提升。查看语句执行情况,除copy入库外,其余业务均正常执行,无性能瓶颈,且观察无资源瓶颈,因此初步判断为该业务自身存在瓶颈,查看该表copy相关的作业等待视图情况:

如图所示,由于CDM作业起了5个并发,因此在活跃视图中可以看到5个copy语句,根据这5个copy语句对应的query_id查看等待视图情况如上图所示。可以看到,这5个copy中,同一时刻,仅有1个copy在向GTM申请序列值,其余的copy在等待轻量级锁。因此,即使作业中开启了5并发在运行,实际效果比1并发并不能带来明显提升。

问题原因:
目标表在建表时使用了serial类型,默认创建的sequence的cache为1,导致在并发copy入库时,CN频繁与GTM建联,且多个并发之间存在轻量锁争抢,导致数据同步效率低。

解决方案:
此种场景下可以调大sequence的cache值,防止频繁GTM建联带来的瓶颈。本例中,业务每次同步的数据量在10万左右,综合其他使用场景评估,将cache值修改为10000(实际使用时应根据业务设置合理的cache值,既能保证快速访问,又不会造成序列号浪费)。

当前GaussDB(DWS)不支持通过alter sequence的方式修改cache值,那么如何修改已有sequence的cache值呢?以第二节中方法二的test表为例,可以通过如下方式达到修改cache的目的:

--解除当前sequence与目标表的关联关系
alter sequence test_b_seq owned by none;
alter table test alter b drop
default;--记录当前的seqeunce值并删除sequenceselect nextval('test_b_seq'); --记录该值,作为新建sequence的start value
drop sequence test_b_seq;
--新建seqeunce并绑定目标表
create sequence test_b_seq START with xxx cache
10000 owned by test.b; --xxx替换为上一步查到的nextval
alter sequence test_b_seq owner to jerry;
--jerry为test表的属主,如果当前用户即为属主,可不执行此语句
alter table test alter b
set default nextval('test_b_seq'), alter b set not null;

参考链接:

https://bbs.huaweicloud.com/blogs/180833

https://bbs.huaweicloud.com/blogs/338904

点击关注,第一时间了解华为云新鲜技术~

准备工作

需要先准备好你域名对应的证书和私钥,也就是cert证书和key。我部署是很常见的ng+tomcat双层配置,ng作为前端的代理,所以tomcat就不需要自己处理https,ng作为代理以http协议将请求转给tomcat处理,而后再把tomcat的输出通过SSL加密发给用户。

这种代理模式下,带来的问题就是tomcat会认为所有请求都是ng发出的,你在代码逻辑如果使用request.getScheme()等函数获取的信息会总是http,这种解决办法需要你在转发tomcat的配置一些选项proxy_set_header等信息。

该配置Demo是以客户在华为云上的一台服务器作为样例,免费证书需要
通过域名备案
后,到云证书管理服务中下载

Nginx

下载nginx自己去官网,可以wget
http://nginx.org/download
对应的版本号,自己解压安装后,我们检查下是否有配置SSL模块

$ /usr/local/nginx/sbin/nginx -v
nginx version: nginx/1.10.2

如果没有看到configure
arguments: --
with-http_ssl_module

则需要配置SSL模块,在解压后的nginx目录(注意,不是在安装好的那个nginx目录)执行make编译命令,编译好后,在当前目录下会多出一个objs文件夹。

$ cd nginx-1.10.2$ make

用新的nginx覆盖当前的安装好的nginx文件

$ cp objs/nginx /usr/local/nginx/sbin/

再次检查安装的模块 /usr/local/nginx/sbin/nginx -v,如果能看到 configure
arguments: --
with-http_ssl_module

则表示SSL模块已经安装

证书部署

将从华为云上下载的免费证书和秘钥通过sftp工具上传到云服务器上。可以创建一个文件夹cert专门存放,这是我当前存放证书的的路径

nginx.conf配置

在配置前,我们先copy一份原配置文件防止出错。然后在配置文件内新增一个server

server {
     $ 端口号,开启ssl
listen
443ssl;
     # 域名,多个以空格分开
server_name xxx www.xxx.com;

#charset koi8
-r;

#access_log logs
/host.access.log main;
     # 域名证书文件存放位置
ssl_certificate
/usr/local/nginx/cert/xxx.crt;
     # 域名私钥存放位置
ssl_certificate_key
/usr/local/nginx/cert/xxx.key;
     # 缓存有效期
ssl_session_timeout 5m;
     # 可选的加密协
ssl_protocols TLSv1 TLSv1.
1 TLSv1.2;
     # 加密算法
ssl_ciphers ECDHE
-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
     # https加密套件,
ssl_prefer_server_ciphers on;

     #静态文件存放位置
location
/{
try_files $uri $uri
/ /index.html;
#root html;
#index index.html index.htm;
}
location
~.*\.js$ {
root
/usr/local/nginx/html/build;
}
location
~.*\.css$ {
root
/usr/local/nginx/html/build;
}
     #tomcat 映射的服务器配置
location
^~/cms-manage/{
proxy_pass http:
//127.0.0.1:8080; proxy_set_header Host $http_host;
proxy_set_header X
-Real-IP $remote_addr;
}

#error_page
404 /404.html;

# redirect server error pages to the
static page /50x.html
#
error_page
500 502 503 504 /50x.html;
location
= /50x.html {
root html;
}

# proxy the PHP scripts to Apache listening on
127.0.0.1:80#
#location
~\.php$ {
# proxy_pass http:
//127.0.0.1; #}

# pass the PHP scripts to FastCGI server listening on
127.0.0.1:9000#
#location
~\.php$ {
# root html;
# fastcgi_pass
127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME
/scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files,
if Apache's document root # concurs with nginx's one #
#location
~ /\.ht {
# deny all;
#}
}

以上就是在配置文件内新增的server,然后在将原http重定向htps

server {
listen
80;
server_name xxx.com www.xxx.top;
return 301 https://$server_name$request_uri; }

重启nginx

关闭nginx,把占用的端口释放

$ netstat -lntp

杀掉原进程,重启,最后记得修改防火墙和入站规则,将443端口放开

$ /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf 

尝试访问下域名,已可正常访问

参考:
https://support.huaweicloud.com/usermanual-ccm/ccm_01_0082.html

需求分析之道——需求分析要做什么。

需求分析是架构师开始做架构设计的第一步,对架构师来讲非常非常的重要。因为需求分析能够告诉我们,到底我们要做什么,架构设计就是为了去完成这件事情而做的。

接下来,我们就从实战的角度来讲一讲,需求分析的一些方法,都是咱们多年经验的总结,也许听上去或者说大家看上去,没有那么高大上,但是是非常实用的知识,从几10万的小项目到数千万的大项目都可以用得上这些方法。

咱们要做一件事情,首先要紧盯目标,这样你才能够找到自己前进的方向;然后再盯脚下的路,找到具体做事的方法。一步一步,认认真真去做,最终达到这个目标。这里也一样,先来看看需求分析的目标是什么?

一:需求分析的目标:

是尽可能准确、全面、深入的理解业务。

关于这个话题,内容比较多,特别在上一篇《深入理解需求分析的目标》详细讲述了,这里就不再啰嗦了。

二:识别重难点业务

第二个大的任务,就是识别重难点业务。这个可能要求架构师有一定的业务经验,这个也算是架构师的一个基本功。拿到需求过后,架构师要能够快速的识别出里面的一些重难点的业务,足够的业务经验,就能告诉我们,要做这样子的业务,里面有哪些功能是非常重要的,有哪些业务可能是比较难做的,也就是咱们俗称的重难点的业务。

识别出重难点业务有什么样的作用呢?就是接下来,在进行分析设计的时候,我们要重点去考虑这些重点业务、难点业务的实现,如果能够把重难点的业务都解决了,一般来说,常规的、相对普通一些的业务功能,咱们的架构设计,是能够很好的去满足的。

这些重难点业务,很可能会影响到咱们后面的,包括像技术选型、具体的架构设计、架构形式,可能都会受到它的影响。

毕竟,
软件只是一个工具,工具嘛,不就是用来干活的吗?软件是用来干什么的呢?就是帮助用户或者客户,实现业务活动的工具。架构设计是干什么的呢?架构设计是为了把软件造好,也可以说它是为了软件服务的,开发和制作软件这个工具

所以,我们要去识别重难点业务,软件就是来解决这些业务问题的,肯定首先盯的,就是要解决重难点的业务,这些解决了,那些普通业务肯定能解决。是这个道理吧。

咱们的架构设计,就是在考虑,我怎么能够把这个软件做好。因此,对于重难点业务的把握,可能就直接决定了架构设计的成败,咱们一定要非常非常的重视。

这一点对于经验弱一些的架构师,可能就是一个小小的问题了,因为刚开始,他可能不能很快的去识别这些重难点的业务,但这个也没有关系,即使你刚开始没有识别出来,那你就尽量验证的全面一些。比方说,做完你的架构设计了,在做架构验证的时候,你就多挑一些业务来验证你的这个架构设计,这样也能够避免出现一些问题。

三:识别非功能需求,还有质量约束

第三的一个,要去识别非功能需求,还有质量约束。

啥叫非功能需求呢?就是除去咱们的业务功能需求之外的,剩下的这些需求,统称为非功能性需求,通常也是软件质量约束的一部分。

比如说,我们对这个系统提出了一些要求,但不是功能性的,常见的有:性能方面的要求,可靠性方面的要求,可扩展性方面的要求,可维护性方面的要求等等的。当然也还有其他的,比如说安全的要求,备份、恢复的要求等等,这些要求对于架构设计的影响也是非常非常大的。

很多都是架构设计要重点考虑的一些问题,比如说像性能问题,可靠性问题,高并发问题,海量数据的问题,可扩展的问题等。这些对咱们做架构设计都是有非常大的影响的,所以,在做需求分析的时候,就要把这些识别出来。

最后想要强调一点,
需求分析对架构师而言,是非常非常重要的。可以这么说,需求分析是架构师做架构设计的起点,需求分析没有做好,后面的全部都是在瞎做

因为,需求分析会告诉我们:到底要做什么?如果说,连要做什么,我们都不知道,那你想想,如果一片迷茫的情况下,就去做所谓的架构设计,请问这个架构设计为谁做的?做来干什么?

现在有一些所谓的架构师,轻业务而重技术,成天高谈阔论很多新的技术,各种技术大词、名词满天飞,为了技术而技术。但是他忘了架构设计的初心,架构设计的目的是为了软件服务的,是为了更好的去开发和制作软件这个工具,仅此而已,不是为了你去炫耀技术的。

可以毫不客气的说这些人,根本就算不上是真正的架构师,我们可以称之为是伪架构师,或者说是PPT架构师,有那么一句话:“离开业务场景谈架构设计,那就是在耍流氓”。所以说,大家一定要重视起来,业务很重要,需求分析很重要。

为了大家更好的交流架构设计的思想和知识,大家可以加sishuok,拉你进架构设计群,一起共同学习,共同进步。