• 关于

    段表长度不可用

    的搜索结果

回答

索引,索引!!!为经常查询的字段建索引!! 但也不能过多地建索引。insert和delete等改变表记录的操作会导致索引重排,增加数据库负担。优化目标1.减少 IO 次数 IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当然,也是收效最明显的优化手段。2.降低 CPU 计算 除了 IO 瓶颈之外,SQL优化中需要考虑的就是 CPU 运算量的优化了。order by, group by,distinct … 都是消耗 CPU 的大户(这些操作基本上都是 CPU 处理内存中的数据比较运算)。当我们的 IO 优化做到一定阶段之后,降低 CPU 计算也就成为了我们 SQL 优化的重要目标优化方法改变 SQL 执行计划 明确了优化目标之后,我们需要确定达到我们目标的方法。对于 SQL 语句来说,达到上述2个目标的方法其实只有一个,那就是改变 SQL 的执行计划,让他尽量“少走弯路”,尽量通过各种“捷径”来找到我们需要的数据,以达到 “减少 IO 次数” 和 “降低 CPU 计算” 的目标分析复杂的SQL语句explain 例如: mysql> explain select from (select from ( select * from t3 where id=3952602) a) b; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 2 DERIVED system NULL NULL NULL NULL 1 3 DERIVED t3 const PRIMARY,idx_t3_id PRIMARY 4 1 很显然这条SQL是从里向外的执行,就是从id=3 向上执行.show show tables或show tables from database_name; // 显示当前数据库中所有表的名称 show databases; // 显示mysql中所有数据库的名称 show columns from table_name from database_name; 或MySQL show columns from database_name.table_name; // 显示表中列名称 show grants for user_name@localhost; // 显示一个用户的权限,显示结果类似于grant 命令 show index from table_name; // 显示表的索引 show status; // 显示一些系统特定资源的信息,例如,正在运行的线程数量 show variables; // 显示系统变量的名称和值show processlist; // 显示系统中正在运行的所有进程,也就是当前正在执行的查询。 show table status; // 显示当前使用或者指定的database中的每个表的信息。信息包括表类型和表的最新更新时间 show privileges; // 显示服务器所支持的不同权限 show create database database_name; // 显示create database 语句是否能够创建指定的数据库 show create table table_name; // 显示create database 语句是否能够创建指定的数据库 show engies; // 显示安装以后可用的存储引擎和默认引擎。 show innodb status; // 显示innoDB存储引擎的状态 show logs; // 显示BDB存储引擎的日志 show warnings; // 显示最后一个执行的语句所产生的错误、警告和通知 show errors; // 只显示最后一个执行语句所产生的错误关于enum 存在争议。 对于取值有限且固定的字段,推荐使用enum而非varchar。但是!!其他数据库可能不支持,导致了难于迁移的问题。开启缓存查询 对于完全相同的sql,使用已经存在的执行计划,从而跳过解析和生成执行计划的过程。 应用场景:有一个不经常变更的表,且服务器收到该表的大量相同查询。对于频繁更新的表,查询缓存是不适合的 Mysql 判断是否命中缓存的办法很简单,首先会将要缓存的结果放在引用表中,然后使用查询语句,数据库名称,客户端协议的版本等因素算出一个hash值,这个hash值与引用表中的结果相关联。如果在执行查询时,根据一些相关的条件算出的hash值能与引用表中的数据相关联,则表示查询命中 查询必须是完全相同的(逐字节相同)才能够被认为是相同的。另外,同样的查询字符串由于其它原因可能认为是不同的。使用不同的数据库、不同的协议版本或者不同 默认字符集的查询被认为是不同的查询并且分别进行缓存。 下面sql查询缓存认为是不同的: SELECT * FROM tbl_name Select * from tbl_name 缓存机制失效的场景 如果查询语句中包含一些不确定因素时(例如包含 函数Current()),该查询不会被缓存,不确定因素主要包含以下情况 · 引用了一些返回值不确定的函数 · 引用自定义函数(UDFs)。 · 引用自定义变量。 · 引用mysql系统数据库中的表。 · 下面方式中的任何一种: SELECT ...IN SHARE MODE SELECT ...FOR UPDATE SELECT ...INTO OUTFILE ... SELECT ...INTO DUMPFILE ... SELECT * FROM ...WHERE autoincrement_col IS NULL · 使用TEMPORARY表。 · 不使用任何表。 · 用户有某个表的列级别权限。额外的消耗 如果使用查询缓存,在进行读写操作时会带来额外的资源消耗,消耗主要体现在以下几个方面 · 查询的时候会检查是否命中缓存,这个消耗相对较小 · 如果没有命中查询缓存,MYSQL会判断该查询是否可以被缓存,而且系统中还没有对应的缓存,则会将其结果写入查询缓存 · 如果一个表被更改了,那么使用那个表的所有缓冲查询将不再有效,并且从缓冲区中移出。这包括那些映射到改变了的表的使用MERGE表的查询。一个表可以被许多类型的语句更改,例如INSERT、UPDATE、DELETE、TRUNCATE、ALTER TABLE、DROP TABLE或DROP DATABASE。 对于InnoDB而言,事物的一些特性还会限制查询缓存的使用。当在事物A中修改了B表时,因为在事物提交之前,对B表的修改对其他的事物而言是不可见的。为了保证缓存结果的正确性,InnoDB采取的措施让所有涉及到该B表的查询在事物A提交之前是不可缓存的。如果A事物长时间运行,会严重影响查询缓存的命中率 查询缓存的空间不要设置的太大。 因为查询缓存是靠一个全局锁操作保护的,如果查询缓存配置的内存比较大且里面存放了大量的查询结果,当查询缓存失效的时候,会长时间的持有这个全局锁。因为查询缓存的命中检测操作以及缓存失效检测也都依赖这个全局锁,所以可能会导致系统僵死的情况静态表速度更快定长类型和变长类型 CHAR(M)定义的列的长度为固定的,M取值可以为0~255之间,当保存CHAR值时,在它们的右边填充空格以达到指定的长度。当检索到CHAR值时,尾部的空格被删除掉。在存储或检索过程中不进行大小写转换。CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间,不足的自动用空格填充。 VARCHAR(M)定义的列的长度为可变长字符串,M取值可以为0~65535之间,(VARCHAR的最大有效长度由最大行大小和使用的字符集确定。整体最大长度是65,532字节)。VARCHAR值保存时只保存需要的字符数,另加一个字节来记录长度(如果列声明的长度超过255,则使用两个字节)。VARCHAR值保存时不进行填充。当值保存和检索时尾部的空格仍保留,符合标准SQL。varchar存储变长数据,但存储效率没有CHAR高。 如果一个字段可能的值是不固定长度的,我们只知道它不可能超过10个字符,把它定义为 VARCHAR(10)是最合算的。VARCHAR类型的实际长度是它的值的实际长度+1。空间上考虑,用varchar合适;从效率上考虑,用char合适,关键是根据实际情况找到权衡点。VARCHAR和TEXT、BlOB类型 VARCHAR,BLOB和TEXT类型是变长类型,对于其存储需求取决于列值的实际长度(在前面的表格中用L表示),而不是取决于类型的最大可能尺寸。 BLOB和TEXT类型需要1,2,3或4个字节来记录列值的长度,这取决于类型的最大可能长度。VARCHAR需要定义大小,有65535字节的最大限制;TEXT则不需要。如果你把一个超过列类型最大长度的值赋给一个BLOB或TEXT列,值被截断以适合它。 一个BLOB是一个能保存可变数量的数据的二进制的大对象。4个BLOB类型TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB仅仅在他们能保存值的最大长度方面有所不同。 BLOB 可以储存图片,TEXT不行,TEXT只能储存纯文本文件。 在BLOB和TEXT类型之间的唯一差别是对BLOB值的排序和比较以大小写敏感方式执行,而对TEXT值是大小写不敏感的。换句话说,一个TEXT是一个大小写不敏感的BLOB。 效率来说基本是char>varchar>text,但是如果使用的是Innodb引擎的话,推荐使用varchar代替char char和varchar可以有默认值,text不能指定默认值静态表和动态表 静态表字段长度固定,自动填充,读写速度很快,便于缓存和修复,但比较占硬盘,动态表是字段长度不固定,节省硬盘,但更复杂,容易产生碎片,速度慢,出问题后不容易重建。当只需要一条数据的时候,使用limit 1 表记录中的一行尽量不要超过一个IO单元 区分in和exist select * from 表A where id in (select id from 表B)这句相当于select from 表A where exists(select from 表B where 表B.id=表A.id)对于表A的每一条数据,都执行select * from 表B where 表B.id=表A.id的存在性判断,如果表B中存在表A当前行相同的id,则exists为真,该行显示,否则不显示 区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询。 所以IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况复杂多表尽量少用join MySQL 的优势在于简单,但这在某些方面其实也是其劣势。MySQL 优化器效率高,但是由于其统计信息的量有限,优化器工作过程出现偏差的可能性也就更多。对于复杂的多表 Join,一方面由于其优化器受限,再者在 Join 这方面所下的功夫还不够,所以性能表现离 Oracle 等关系型数据库前辈还是有一定距离。但如果是简单的单表查询,这一差距就会极小甚至在有些场景下要优于这些数据库前辈。尽量用join代替子查询 虽然 Join 性能并不佳,但是和 MySQL 的子查询比起来还是有非常大的性能优势。 MySQL需要为内层查询语句的查询结果建立一个临时表。然后外层查询语句在临时表中查询记录。查询完毕后,MySQL需要插销这些临时表。所以在MySQL中可以使用连接查询来代替子查询。连接查询不需要建立临时表,其速度比子查询要快。尽量少排序 排序操作会消耗较多的 CPU 资源,所以减少排序可以在缓存命中率高等 IO 能力足够的场景下会较大影响 SQL 的响应时间。 对于MySQL来说,减少排序有多种办法,比如: 上面误区中提到的通过利用索引来排序的方式进行优化 减少参与排序的记录条数 非必要不对数据进行排序尽量避免select * 大多数关系型数据库都是按照行(row)的方式存储,而数据存取操作都是以一个固定大小的IO单元(被称作 block 或者 page)为单位,一般为4KB,8KB… 大多数时候,每个IO单元中存储了多行,每行都是存储了该行的所有字段(lob等特殊类型字段除外)。 所以,我们是取一个字段还是多个字段,实际上数据库在表中需要访问的数据量其实是一样的。 也有例外情况,那就是我们的这个查询在索引中就可以完成,也就是说当只取 a,b两个字段的时候,不需要回表,而c这个字段不在使用的索引中,需要回表取得其数据。在这样的情况下,二者的IO量会有较大差异。尽量少or 当 where 子句中存在多个条件以“或”并存的时候,MySQL 的优化器并没有很好的解决其执行计划优化问题,再加上 MySQL 特有的 SQL 与 Storage 分层架构方式,造成了其性能比较低下,很多时候使用 union all 或者是union(必要的时候)的方式来代替“or”会得到更好的效果。尽量用 union all 代替 union union 和 union all 的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 CPU 运算,加大资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使用 union all 而不是 union。尽量早过滤 在 SQL 编写中同样可以使用这一原则来优化一些 Join 的 SQL。比如我们在多个表进行分页数据查询的时候,我们最好是能够在一个表上先过滤好数据分好页,然后再用分好页的结果集与另外的表 Join,这样可以尽可能多的减少不必要的 IO 操作,大大节省 IO 操作所消耗的时间。避免类型转换 这里所说的“类型转换”是指 where 子句中出现 column 字段的类型和传入的参数类型不一致的时候发生的类型转换: 人为在column_name 上通过转换函数进行转换直接导致 MySQL(实际上其他数据库也会有同样的问题)无法使用索引,如果非要转换,应该在传入的参数上进行转换,由数据库自己进行转换, 如果我们传入的数据类型和字段类型不一致,同时我们又没有做任何类型转换处理,MySQL 可能会自己对我们的数据进行类型转换操作,也可能不进行处理而交由存储引擎去处理,这样一来,就会出现索引无法使用的情况而造成执行计划问题。优先优化高并发的 SQL,而不是执行频率低某些“大”SQL 对于破坏性来说,高并发的 SQL 总是会比低频率的来得大,因为高并发的 SQL 一旦出现问题,甚至不会给我们任何喘息的机会就会将系统压跨。而对于一些虽然需要消耗大量 IO 而且响应很慢的 SQL,由于频率低,即使遇到,最多就是让整个系统响应慢一点,但至少可能撑一会儿,让我们有缓冲的机会。从全局出发优化,而不是片面调整 尤其是在通过调整索引优化 SQL 的执行计划的时候,千万不能顾此失彼,因小失大。尽可能对每一条运行在数据库中的SQL进行 explain 知道 SQL 的执行计划才能判断是否有优化余地,才能判断是否存在执行计划问题。在对数据库中运行的 SQL 进行了一段时间的优化之后,很明显的问题 SQL 可能已经很少了,大多都需要去发掘,这时候就需要进行大量的 explain 操作收集执行计划,并判断是否需要进行优化。尽量避免where子句中对字段进行null值的判断 会导致引擎放弃索引,进而进行全表扫描。 尽量不要给数据库留null值,尽可能地使用not null填充数据库。可以为每个null型的字段设置一个和null对应的实际内容表述。避免在where中使用!=, >, <操作符 否则引擎放弃使用索引,进行全表扫描。常用查询字段建索引避免在where中使用or imagein和not in关键词慎用,容易导致全表扫面 对连续的数值尽量用between通配符查询也容易导致全表扫描避免在where子句中使用局部变量 sql只有在运行时才解析局部变量。而优化程序必须在编译时访问执行计划,这时并不知道变量值,所以无法作为索引的输入项。 image避免在where子句中对字段进行表达式操作 会导致引擎放弃使用索引 image避免在where子句中对字段进行函数操作 image不要where子句的‘=’左边进行函数、算术运算或其他表达式运算 系统可能无法正确使用索引避免update全部字段 只update需要的字段。频繁调用会引起明显的性能消耗,同时带来大量日志。索引不是越多越好 一个表的索引数最好不要超过6个尽量使用数字型字段而非字符型 因为处理查询和连接时会逐个比较字符串的每个字符,而对于数字型而言只需要比较一次就够了。尽可能用varchar/nvarchar代替char/nchar 变长字段存储空间小,对于查询来说,在一个相对较小的字段内搜索效率更高。。。?避免频繁创建和删除临时表,减少系统表资源消耗select into和create table 新建临时表时,如果一次性插入数据量很大,使用select into代替create table,避免造成大量log,以提高速度。 如果数据量不大,为了缓和系统表的资源,先create table,再insert。 拆分大的DELETE和INSERT语句 因为这两个操作是会锁表的,对于高访问量的站点来说,锁表时间内积累的访问数、数据库连接、打开的文件数等等,可能不仅仅让WEB服务崩溃,还会让整台服务器马上挂了。 所以,一定要拆分,使用LIMIT条件休眠一段时间,批量处理。

wangccsy 2019-12-02 01:50:30 0 浏览量 回答数 0

问题

从数据迁移测试小结看,黑盒测试与灰盒测试

技术小菜鸟 2019-12-01 21:48:13 2814 浏览量 回答数 1

回答

约翰逊法是作业排序中的一种排序方法。这种方法适用的条件是:n个工件经过二、三台设备(有限台设备)加工,所有工件在有限设备上加工的次序相同。为了便于阐述这种方法的具体做法,下面结合一个例子来进行说明: 例:有五个工件在二台设备上加工,加工顺序相同,现在设备1上加工,再在设备2上加工,工时列于下表1中,用约翰逊法排序。 表1 加工工时表 具体步骤为: 第一步,取出最小工时t12=2。如该工时为第一工序的,则最先加工;反之,则放在最后加工。此例是A工件第二工序时间,按规则排在最后加工。 第二步,将该已排序工作划去。 第三步,对余下的工作重复上述排序步骤,直至完毕。此时t21=t42=3,B工件第一工序时间最短,最先加工;D工件第二工序时间最短,排在余下的工件中最后加工。最后得到的排序为:B-C-E-D-A。整批工件的停留时间为27分钟。 更一般的情况是工件加工顺序不同,称为随机性排序。由杰克逊对约翰逊法稍加改进后得到求解方法,称为杰克逊算法。 [周期性生产类型作业计划编制] 周期性生产类型由于是多产品轮番生产,零件数量又十分大,作业计划的难度比较大。作业计划分厂部计划和车间计划。在车间计划中的作业排序问题是一件十分困难的工作。 一、 厂部作业计划 厂部作业计划一般只以产品作为计划单位,如产品结构比较简单,厂部计划的能力又很强,也可做部件计划。在确定了周期性生产类型的期量标准的基础上,根据其量标准下达产品的生产批量,以及投入出产的时间,就是厂部计划的主要内容。实际上,采用这种生产方式的企业由于产品大结构复杂,产品生产周期比较长,往往都超过一个月。厂部都是根据订单安排月度计划,当品种数量比较多时,很难做批量计划,这时的厂部计划主要下达月度的生产总量和具体的产品品种规格。由于产品周期垮了数个月,还要下达产品的出产日期、毛坯的投入出产期和机加工的投入出产期,计划单位为产品。部件和零件的生产计划由车间考虑。 二、 车间作业计划 车间接到的生产任务是一个计划期的总生产量,车间要进一步细分任务,分批生产。主要考虑的问题是生产能力的平衡、零部件数量上的配套、提高设备利用率、缩短生产周期、减少在制品资金占用量,所以计划难度很高。大多数企业都是凭经验安排计划。作车间作业计划时,有一些定量模型和方法可供适用,如多品种轮番生产的最小生产费用计划方法就是其中常用的一种。。 三、 作业排序 周期性生产类型的生产组织形式是工艺专业化,车间往往就是生产过程中的某个工艺阶段,每个零件在车间内要经过某几个工序的加工。因此车间的作业计划中工件加工的排序问题是一个难点。其难处在于零件种类多,加工的工艺流程和加工工时差别较大。一般采取重点管住关键零件和关键设备的方法。 零件加工排序问题一般可作如下描述:n种零件在有m台设备的车间内加工,每种零件加工所需要的设备数可以是不同的,加工的顺序也可以不同,要求排出效果尽可能好的工件加工次序。目前对这个问题的研究所取得的成果只能解决少数几种特殊条件下的排序问题,其思路是先确定一个优化目标,再寻求解题模型。通常取一批加工任务在车间内停留的时间最短为优化目标。 下面做简要介绍。 1、 n个工件在一台设备上加工 这是一种最简单的排序问题,只要按如下规则排序既可以了。 式中,ti为第i个工件的加工工时,该式的排序规律是加工工时短的工件先加工。 2、 n个工件需经过二台设备加工 比较简单的一种情况是所有工件在二台设备上加工的次序相同,此时用约翰逊法可以求解。更一般的情况是工件加工顺序不同,称为随机排序。由杰克逊对约翰逊法稍加改进后得到求解方法,称为杰克逊算法。 3、 n个工件在三台设备上加工 随着设备数量的增加,优化难度加大。在三台设备上加工,当满足一定条件时有优化方法。如果n个工件的加工顺序相同,且满足以下两条件中的任何一条,可用约翰逊法求解。 算法如下: 第一步,令 Ti1=ti1+ti2 Ti2=ti2+ti3 得到两台虚拟设备的工序工时; 第二步,对二台虚拟设备,按约翰逊法排序。 对于三台设备的随机性问题还没有简便的优化方法。 4、 二个工件在m台设备上加工 这种情况下可用分枝定界法求解,如设备数量较大,则工作量很大,通常采用图解法。但图解法不能保证是最优解。 上述四种情况在实际生产中只是少数情况,可见多数情况下还没有好的解法,一般可根据排队理论采用计算机模拟方法。 [最小批量法] 最小批量法是确定批量和生产间隔期时常用的一种以量定期法。此方法从设备利用和生产率方面考虑批量的选择,要时的选定的批量能够保证一次准备结束时间对批量加工时间的比值不大于给定的数值。可用下式表示: 损失系数由经验确定,可参考下表1: 表1 准备结束时间损失系数 [经济批量法] 经济批量法是确定批量和生产间隔期时常用的一种以量定期方法。生产费用与批量之间存在着函数关系,批量主要通过两方面因素影响生产费用:一是生产准备费用,这部分费用随生产批次增减而变化;二是保管费用,即在制品在存储保管期间所发生的费用,如仓库管理费用、资金呆滞损失、存货的损耗费用等。这些费用与批量大小和存储时间长短有关。 [周期性生产类型作业计划的期量标准] 周期性生产类型的作业计划的期量标准主要包括批量和生产间隔期、生产周期和生产提前期,合理制定期量标准可以使生产资源得到较好的利用。下面分别阐述这些期量标准。 一、 批量和生产间隔期 采用周期性生产类型的企业,由于产品体积大、结构复杂,再加上品种多等因素,不能采取月度计划一次投料生产的方法。否则不但使在制品充满生产现场,使现场一片混乱,甚至发生生产场地不够用的现象,还会占用大量的流动资金。但又不能像流水生产那样每天小批量的投料生产,所以需要确定一个合理的生产批量。 批量是指一次性投入生产的同种制品的数量。每投一次需要消耗一次准备结束时间,,用于熟悉图纸、领取工卡量居、调整设备工装等等作业。生产间隔期是相邻两批同种工件投入(或产出)的时间间隔。在周期性重复生产条件下批量和生产间隔期有如下关系: 批量=平均日产量*生产间隔期 在生产任务稳定条件下,日产量不变,则批量与生产间隔期成正比。批量大,则间隔期长,相应的在制品数量也大,生产周期较长,这样对使用流动资金是不利的。反之,如批量小,会导致频繁变动产品,增加准备结束作业次数,多消耗准备结束时间,降低设备利用率,也是不利的。因此确定批量和生产间隔期,需要在这些因素之间进行平衡,达到既有利于流动资金的有效使用,又提高设备的利用率。 确定批量和生产间隔期通常有两种方式。 (一) 以量定期法 当平均日产量不变时,批量与生产间隔期互为因果关系,此方法的思路为,先根据综合经济效果确定批量,然后推算生产间隔期,对间隔期做适当的修正后,再对批量做调整。这种方式又有几种具体的方法:最小批量法、经济批量法等。 (二) 以期定量法 此方法的思路为先确定生产间隔期,在推算出批量。按照零件复杂程度、体积大小、价值高低确定各个零件的生产间隔期,然后根据生产数量推算出批量。为了管理上的方便企业都事先制定好标准生产间隔期,数值通常取月工作日(20天)的约数,如1天、2天、4天、5天(一周)、10天、20天(1月)等等。采用这种方法使生产间隔期和相应的批量规范化了,便于管理。标准生产间隔期表如下表1所示: 表1 标准生产间隔期表 生产间隔期与批量的总数不宜太多,一般不超过六种为宜。 二、 生产周期 生产周期是指从加工对象投产起,到它完工时止所经历的日历时间。生产周期这一期量标准是编制生产作业计划和确定产品及其零件在各工艺阶段投入和产出日期的主要依据,是成批生产作业计划的一项重要期量标准。 对产品来说,它的生产周期包括毛坯准备、零件加工、部件装配、成品总装、油漆,直到入库为止的全部时间,如下图2所示: 图2 产品生产周期结构示意图 生产周期可以按零件工序、零件加工过程和产品进行计算。其中零件工序生产周期是计算产品生产周期的基础。这里分别介绍它们的计算方法: 1、 零件工序生产周期 指一批零件在某道工序上的作业时间。计算公式如下: 式中:Tp--修正后的零件加工生产周期; a--为平行系数。 上述公式也适用于计算装配阶段的生产周期。 2、 产品生产周期 产品生产周期是各工艺阶段的生产周期与所有保险期之和。 [多品种轮番生产的最小生产费用计划方法] 多品种轮番生产的最小生产费用计划方法是车间制定生产作业计划时常可用到的一种很有用的定量方法。这种方法的思路是将计划期划分为几个长度相等的循环流程,在每个循环流程中实行多品种轮番生产;以循环流程长度作为因变量,列出生产费用函数,求出最小费用循环流程;最后从该流程长度推算出各品种的批量。 设: Di--第i种产品计划期需求量; Pi--第i种产品计划期生产能力; tmi--第i种产品单件加工时间,tmi=1/Pi; ti--第i种产品批量生产时间,ti=Qi·tmi; tsi--第i种产品准备与结束时间; Si--第i种产品一次准备、结束单位时间的费用; Ci--第i种产品单位产品计划期储存费用; Qi--第i种产品生产批量; Ii--第i种产品在制品数量; L--循环流程长度,

云篆 2019-12-02 01:19:19 0 浏览量 回答数 0

阿里云试用中心,为您提供0门槛上云实践机会!

0元试用32+款产品,最高免费12个月!拨打95187-1,咨询专业上云建议!

回答

前提条件 您需要开通容器服务和访问控制(RAM)服务。 登录 容器服务管理控制台和RAM 管理控制台开通相应的服务。 说明 用户账户需有 100 元的余额并通过实名认证,否则无法创建按量付费的 ECS 实例和负载均衡。 随集群一同创建的负载均衡实例只支持按量付费的方式。 Kubernetes 集群仅支持专有网络 VPC。 每个账号默认可以创建的云资源有一定的配额,如果超过配额创建集群会失败。请在创建集群前确认您的配额。如果您需要提高配额,请提交工单申请。 每个账号默认最多可以创建 5 个集群(所有地域下),每个集群中最多可以添加 40 个节点。如果您需要创建更多的集群或者节点,请提交工单申请。 说明 Kubernetes 集群中,VPC 默认路由条目不超过 48 条,意味着 Kubernetes 集群使用 VPC 时,默认节点上限是 48 个,如果需要更大的节点数,需要您先对目标 VPC 开工单,提高 VPC 路由条目,再对容器服务提交工单。 每个账号默认最多可以创建 100 个安全组。 每个账号默认最多可以创建 60 个按量付费的负载均衡实例。 每个账号默认最多可以创建 20 个EIP。 创建安全沙箱容器 Kubernetes 集群时,以下界面参数需要按照表中的要求配置,否则创建的集群将无法使用安全沙箱容器的场景。 参数 配置 可用区 目前只有神龙实例支持安全沙箱容器,请确保所选可用区有神龙实例。 kubernetes 版本 1.14.6-aliyun.1 或更高版本。 容器运行时 安全沙箱容器 Worker 实例 新增实例 节点类型 包年包月 实例规格 神龙裸金属服务器(神龙) 挂载数据盘 请至少挂载一块不小于 200GiB 的数据盘,建议 1T+。 操作系统类型 Linux 网络插件 Terway 操作步骤 登录容器服务管理控制台。 在控制台左侧导航栏中,选择集群 > 集群,进入集群列表页面。 单击页面右上角的创建 Kubernetes 集群,在弹出的选择集群模板页面,选择标准托管集群页面,并单击创建,进入Kubernetes 托管版页面。 集群配置页面 完成集群配置。 完成集群基础选项配置。 配置项 描述 集群名称 填写集群的名称。 说明 集群名称应包含 1~63 个字符,可包含数字、汉字、英文字符或连字符(-)。 Kubernetes 版本 选择 1.14.6-aliyun.1 或更高版本。 容器运行时 必须选择安全沙箱容器。 地域 选择集群所在的地域。 资源组 将鼠标悬浮于页面上方的账号全部资源,选择集群所在的资源组。这里显示选择的资源组。 专有网络 设置集群的网络。 说明 Kubernetes 集群仅支持专有网络。您可以在已有 VPC 列表中选择所需的 VPC。如果没有您需要的专有网络,可以通过单击创建专有网络进行创建,请参见创建专有网络。 虚拟交换机 设置虚拟交换机。 说明 您可以在已有虚拟交换机列表中,根据可用区选择 1-3 个交换机 。如果没有您需要的交换机,可以通过单击创建虚拟交换机进行创建,请参见创建交换机。 网络插件 安全沙箱容器集群的网络类型目前仅支持 Terway 。具体请参见如何使用Terway网络插件。 指定 Terway 网络插件需要为 Pod 选择可用的 VSwitch,这些 VSwitch 的网段掩码必须小于或等于 19,例如 172.17.128.0/19;当集群创建 Pod 时,会为 Pod 从选定的那些 VSwitch 网段中分配 IP。 Pod 虚拟交换机 您需要为 Pod 分配 IP 的虚拟交换机。每个 Pod 虚拟交换机分别对应一个 Worker 实例的虚拟交换机。 Service CIDR 您需要指定 Service CIDR,网段不能与 VPC 及 VPC 内已有 Kubernetes 集群使用的网段重复,创建成功后不能修改。而且 Service 地址段也不能和 Pod 地址段重复,有关 Kubernetes 网络地址段规划的信息,请参见VPC下 Kubernetes 的网络地址段规划。 配置 SNAT 设置是否为专有网络配置 SNAT 网关。 说明 如果您使用的 VPC 中当前已有 NAT 网关,容器服务会使用已有的 NAT 网关。 如果 VPC 中没有 NAT 网关,系统会默认自动为您创建一个 NAT 网关。如果您不希望系统自动创建 NAT 网关,可以取消勾选页面下方的为专有网络配置 SNAT。此时您需要自行配置 NAT 网关实现 VPC 安全访问公网环境,或者手动配置 SNAT,否则 VPC 内实例将不能正常访问公网,会导致集群创建失败。 公网访问 设置是否开放使用 EIP 暴露 API Server。 说明 API Server 提供了各类资源对象(Pod,Service 等)的增删改查及 watch 等 HTTP Rest 接口。 如果选择开放,会创建一个 EIP,并挂载到内网 SLB 上。此时,Master 节点的 6443 端口(对应 API Server)暴露出来,用户可以在外网通过 kubeconfig 连接或操作集群。 如果选择不开放,则不会创建 EIP,用户只能在 VPC 内部用 kubeconfig 连接并操作集群。 RDS 白名单 设置 RDS 白名单。将节点 IP 添加到 RDS 实例的白名单中。 说明 允许白名单 RDS 访问 Kubernetes 集群,RDS 必须在当前集群的 VPC 内。 自定义安全组 设置安全组。单击请选择安全组,在弹出的页面选中目标安全组,单击确定。 详细内容请参见安全组概述。 说明 当前只有白名单用户可使用该功能。提交工单申请使用。 完成集群高级选项配置。 配置项 描述 kube-proxy 代理模式 支持 iptables 和 IPVS 两种模式。 iptables:成熟稳定的 kube-proxy 代理模式,Kubernetes service 的服务发现和负载均衡使用 iptables 规则配置,但性能一般,受规模影响较大,适用于集群存在少量的 service。 IPVS:高性能的 kube-proxy 代理模式,Kubernetes service 的服务发现和负载均衡使用 Linux ipvs 模块进行配置,适用于集群存在大量的 service,对负载均衡有高性能要求的场景。 标签 为集群绑定标签。输入键和对应的值,单击添加。 说明 键是必需的,而 值 是可选的,可以不填写。 键不能是 aliyun、http:// 、https:// 开头的字符串,不区分大小写,最多 64 个字符。 值不能是 http:// 或 https://,可以为空,不区分大小写,最多 128 个字符。 同一个资源,标签键不能重复,相同标签键(Key)的标签会被覆盖。 如果一个资源已经绑定了 20 个标签,已有标签和新建标签会失效,您需要解绑部分标签后才能再绑定新的标签。 集群本地域名 设置是否配置集群本地域名。 说明 默认域名为 cluster.local,可自定义域名。域名由两段组成,每段不超过 63 个字符,且只能使用大小写字母和数字,不能为空。 集群删除保护 设置是否启用集群删除保护。为防止通过控制台或 API 误释放集群。 单击下一步:Worker 配置,完成 Worker 节点配置。 说明 安全沙箱容器场景下, Worker 节点仅支持神龙工作节点,选择神龙型号为 ecs.ebmg5s.24xlarge 完成 Work 节点基础选项配置。 配置项 描述 Worker 实例 只支持新增实例,暂不支持添加已有实例。 付费类型 神龙实例付费模式只支持包年包月,不支持按量付费。 购买时长 选择包年包月时,需设置购买时长。目前支持选择 1、2、3、6 和12 个月。 自动续费 选择包年包月时,需设置是否自动续费。 实例规格 目前机型仅支持神龙裸金属服务器(神龙),该机型的实例规格均可使用。 已选规格 已选的实例规格。只能选择一个规格。 数量 新增 Worker 实例的数量。 系统盘 支持 SSD 云盘和高效云盘。 挂载数据盘 支持 SSD 云盘、高效云盘和普通云盘。 说明 挂载的数据盘用于存储节点上所有容器的根文件系统。因此,请至少挂载一块不小于 200 GiB 的数据盘,建议 1T 以上。 操作系统 安全沙箱容器集群仅支持 Linux 系统。 登录方式 设置密钥。 您需要在创建集群的时候选择密钥对登录方式,单击新建密钥对,跳转到 ECS 云服务器控制台,创建密钥对,参见创建SSH密钥对。密钥对创建完毕后,设置该密钥对作为登录集群的凭据。 设置密码。 登录密码:设置节点的登录密码。 确认密码:确认设置的节点登录密码。 密钥对 设置高级选项。 配置项 描述 实例保护 设置是否启用实例保护。 说明 为防止通过控制台或 API 误释放集群节点,默认启用实例保护。 实例自定义数据 请参见生成实例自定义数据。 自定义镜像 不要选择自定义镜像。安全沙箱容器集群不支持使用自定义镜像。 自定义节点名称 是否开启自定义节点名称。 节点名称由前缀 + 节点 IP 地址子串 + 后缀三部分组成: 前缀和后缀均可由.分隔的一个或多个部分构成,每个部分可以使用小写字母、数字和-,且首尾必须为小写字母和数字。 IP 地址段长度指截取节点 IP 地址末尾的位数,取值范围 5-12。 例如:节点 IP 地址为192.168.0.55,指定前缀为 aliyun.com,IP 地址段长度为 5,后缀为 test,则节点名称为aliyun.com00055test。 CPU Policy 设置 CPU policy。 none:默认策略,表示启用现有的默认 CPU 亲和方案。 static:允许为节点上具有某些资源特征的 Pod 赋予增强的 CPU 亲和性和独占性。 污点(Taints) 为集群内所有Worker节点添加污点。 单击下一步:组件配置,完成组件配置。 配置项 描述 Ingress 设置是否安装 Ingress 组件。默认勾选安装 Ingress 组件 ,请参见 Ingress 支持。 说明 如果您勾选创建 Ingress Dashboard,则需要同步安装日志服务组件。 存储插件 设置存储插件,支持 Flexvolume 和 CSI。Kubernetes 集群通过 Pod 可自动绑定阿里云云盘、NAS、 OSS 存储服务。请参见存储管理-Flexvolume 和存储管理-CSI。 云监控插件 设置是否启用云监控插件。您可以选择在 ECS 节点上安装云监控插件,从而在云监控控制台查看所创建 ECS 实例的监控信息。 日志服务 设置是否启用日志服务,您可使用已有 Project 或新建一个 Project。 勾选使用日志服务,会在集群中自动配置日志服务插件。创建应用时,您可通过简单配置,快速使用日志服务,详情参见使用日志服务进行Kubernetes日志采集。 工作流引擎 设置是否使用 AGS。 如果勾选 AGS,则创建集群时系统自动安装 AGS 工作流插件。 如果不勾选,则需要手动安装 AGS 工作流插件,请参见AGS命令行帮助。 可选组件 在系统组件之外,还可以选择安装容器服务提供的其他组件。 单击创建集群,在弹出的当前配置确认页面,单击创建,启动部署。 说明 一个包含多节点的 Kubernetes 集群的创建时间一般约为十分钟。 执行结果 集群创建成功后,您可以在容器服务管理控制台的 Kubernetes 集群列表页面查看所创建的集群。集群列表 您可以单击集群操作列的查看日志,进入集群日志信息页面查看集群的日志信息。 您也可以在集群日志信息页面中,单击资源栈事件查看更详细的信息。集群日志详情 在集群列表页面中,找到刚创建的集群,单击操作列中的管理,查看集群的基本信息和连接信息。集群基本信息 其中: API Server 公网连接端点:Kubernetes 的 API Server 对公网提供服务的地址和端口,可以通过此服务在用户终端使用 kubectl 等工具管理集群。 API Service 内网连接端点:Kubernetes 的 API server 对集群内部提供服务的地址和端口,此 IP 为负载均衡的地址。 Pod网络CIDR:Kubernetes 的 Pod CIDR 定义集群内 Pod 的网段范围。 Service CIDR:Kubernetes 的 Service CIDR 定义集群内暴露服务的网段范围。 测试域名:为集群中的服务提供测试用的访问域名。服务访问域名后缀是 <cluster_id>.<region_id>.alicontainer.com。 kube-proxy 代理模式:Kubernetes service 的服务发现和负载均衡需要通过服务代理进行配置,支持 iptables 和 IPVS 两种模式。 节点 Pod 数量:单个节点可运行 Pod 数量的上限,默认值为 128。 您可以通过kubectl连接Kubernetes集群,执行 kubectl get node查看集群的节点信息。集群结果

huc_逆天 2020-03-26 18:16:45 0 浏览量 回答数 0

回答

您可以通过容器服务控制台非常方便的创建安全沙箱容器集群。 前提条件 您需要开通容器服务和访问控制(RAM)服务。 登录 容器服务管理控制台和RAM 管理控制台开通相应的服务。 说明 用户账户需有 100 元的余额并通过实名认证,否则无法创建按量付费的 ECS 实例和负载均衡。 随集群一同创建的负载均衡实例只支持按量付费的方式。 Kubernetes 集群仅支持专有网络 VPC。 每个账号默认可以创建的云资源有一定的配额,如果超过配额创建集群会失败。请在创建集群前确认您的配额。如果您需要提高配额,请提交工单申请。 每个账号默认最多可以创建 5 个集群(所有地域下),每个集群中最多可以添加 40 个节点。如果您需要创建更多的集群或者节点,请提交工单申请。 说明 Kubernetes 集群中,VPC 默认路由条目不超过 48 条,意味着 Kubernetes 集群使用 VPC 时,默认节点上限是 48 个,如果需要更大的节点数,需要您先对目标 VPC 开工单,提高 VPC 路由条目,再对容器服务提交工单。 每个账号默认最多可以创建 100 个安全组。 每个账号默认最多可以创建 60 个按量付费的负载均衡实例。 每个账号默认最多可以创建 20 个EIP。 创建安全沙箱容器 Kubernetes 集群时,以下界面参数需要按照表中的要求配置,否则创建的集群将无法使用安全沙箱容器的场景。 参数 配置 可用区 目前只有神龙实例支持安全沙箱容器,请确保所选可用区有神龙实例。 kubernetes 版本 1.14.6-aliyun.1 或更高版本。 容器运行时 安全沙箱容器 Worker 实例 新增实例 节点类型 包年包月 实例规格 神龙裸金属服务器(神龙) 挂载数据盘 请至少挂载一块不小于 200GiB 的数据盘,建议 1T+。 操作系统类型 Linux 网络插件 Terway 操作步骤 登录容器服务管理控制台。 在控制台左侧导航栏中,选择集群 > 集群,进入集群列表页面。 单击页面右上角的创建 Kubernetes 集群,在弹出的选择集群模板页面,选择标准托管集群页面,并单击创建,进入Kubernetes 托管版页面。 集群配置页面 完成集群配置。 完成集群基础选项配置。 配置项 描述 集群名称 填写集群的名称。 说明 集群名称应包含 1~63 个字符,可包含数字、汉字、英文字符或连字符(-)。 Kubernetes 版本 选择 1.14.6-aliyun.1 或更高版本。 容器运行时 必须选择安全沙箱容器。 地域 选择集群所在的地域。 资源组 将鼠标悬浮于页面上方的账号全部资源,选择集群所在的资源组。这里显示选择的资源组。 专有网络 设置集群的网络。 说明 Kubernetes 集群仅支持专有网络。您可以在已有 VPC 列表中选择所需的 VPC。如果没有您需要的专有网络,可以通过单击创建专有网络进行创建,请参见创建专有网络。 虚拟交换机 设置虚拟交换机。 说明 您可以在已有虚拟交换机列表中,根据可用区选择 1-3 个交换机 。如果没有您需要的交换机,可以通过单击创建虚拟交换机进行创建,请参见创建交换机。 网络插件 安全沙箱容器集群的网络类型目前仅支持 Terway 。具体请参见如何使用Terway网络插件。 指定 Terway 网络插件需要为 Pod 选择可用的 VSwitch,这些 VSwitch 的网段掩码必须小于或等于 19,例如 172.17.128.0/19;当集群创建 Pod 时,会为 Pod 从选定的那些 VSwitch 网段中分配 IP。 Pod 虚拟交换机 您需要为 Pod 分配 IP 的虚拟交换机。每个 Pod 虚拟交换机分别对应一个 Worker 实例的虚拟交换机。 Service CIDR 您需要指定 Service CIDR,网段不能与 VPC 及 VPC 内已有 Kubernetes 集群使用的网段重复,创建成功后不能修改。而且 Service 地址段也不能和 Pod 地址段重复,有关 Kubernetes 网络地址段规划的信息,请参见VPC下 Kubernetes 的网络地址段规划。 配置 SNAT 设置是否为专有网络配置 SNAT 网关。 说明 如果您使用的 VPC 中当前已有 NAT 网关,容器服务会使用已有的 NAT 网关。 如果 VPC 中没有 NAT 网关,系统会默认自动为您创建一个 NAT 网关。如果您不希望系统自动创建 NAT 网关,可以取消勾选页面下方的为专有网络配置 SNAT。此时您需要自行配置 NAT 网关实现 VPC 安全访问公网环境,或者手动配置 SNAT,否则 VPC 内实例将不能正常访问公网,会导致集群创建失败。 公网访问 设置是否开放使用 EIP 暴露 API Server。 说明 API Server 提供了各类资源对象(Pod,Service 等)的增删改查及 watch 等 HTTP Rest 接口。 如果选择开放,会创建一个 EIP,并挂载到内网 SLB 上。此时,Master 节点的 6443 端口(对应 API Server)暴露出来,用户可以在外网通过 kubeconfig 连接或操作集群。 如果选择不开放,则不会创建 EIP,用户只能在 VPC 内部用 kubeconfig 连接并操作集群。 RDS 白名单 设置 RDS 白名单。将节点 IP 添加到 RDS 实例的白名单中。 说明 允许白名单 RDS 访问 Kubernetes 集群,RDS 必须在当前集群的 VPC 内。 自定义安全组 设置安全组。单击请选择安全组,在弹出的页面选中目标安全组,单击确定。 详细内容请参见安全组概述。 说明 当前只有白名单用户可使用该功能。提交工单申请使用。 完成集群高级选项配置。 配置项 描述 kube-proxy 代理模式 支持 iptables 和 IPVS 两种模式。 iptables:成熟稳定的 kube-proxy 代理模式,Kubernetes service 的服务发现和负载均衡使用 iptables 规则配置,但性能一般,受规模影响较大,适用于集群存在少量的 service。 IPVS:高性能的 kube-proxy 代理模式,Kubernetes service 的服务发现和负载均衡使用 Linux ipvs 模块进行配置,适用于集群存在大量的 service,对负载均衡有高性能要求的场景。 标签 为集群绑定标签。输入键和对应的值,单击添加。 说明 键是必需的,而 值 是可选的,可以不填写。 键不能是 aliyun、http:// 、https:// 开头的字符串,不区分大小写,最多 64 个字符。 值不能是 http:// 或 https://,可以为空,不区分大小写,最多 128 个字符。 同一个资源,标签键不能重复,相同标签键(Key)的标签会被覆盖。 如果一个资源已经绑定了 20 个标签,已有标签和新建标签会失效,您需要解绑部分标签后才能再绑定新的标签。 集群本地域名 设置是否配置集群本地域名。 说明 默认域名为 cluster.local,可自定义域名。域名由两段组成,每段不超过 63 个字符,且只能使用大小写字母和数字,不能为空。 集群删除保护 设置是否启用集群删除保护。为防止通过控制台或 API 误释放集群。 单击下一步:Worker 配置,完成 Worker 节点配置。 说明 安全沙箱容器场景下, Worker 节点仅支持神龙工作节点,选择神龙型号为 ecs.ebmg5s.24xlarge 完成 Work 节点基础选项配置。 配置项 描述 Worker 实例 只支持新增实例,暂不支持添加已有实例。 付费类型 神龙实例付费模式只支持包年包月,不支持按量付费。 购买时长 选择包年包月时,需设置购买时长。目前支持选择 1、2、3、6 和12 个月。 自动续费 选择包年包月时,需设置是否自动续费。 实例规格 目前机型仅支持神龙裸金属服务器(神龙),该机型的实例规格均可使用。 已选规格 已选的实例规格。只能选择一个规格。 数量 新增 Worker 实例的数量。 系统盘 支持 SSD 云盘和高效云盘。 挂载数据盘 支持 SSD 云盘、高效云盘和普通云盘。 说明 挂载的数据盘用于存储节点上所有容器的根文件系统。因此,请至少挂载一块不小于 200 GiB 的数据盘,建议 1T 以上。 操作系统 安全沙箱容器集群仅支持 Linux 系统。 登录方式 设置密钥。 您需要在创建集群的时候选择密钥对登录方式,单击新建密钥对,跳转到 ECS 云服务器控制台,创建密钥对,参见创建SSH密钥对。密钥对创建完毕后,设置该密钥对作为登录集群的凭据。 设置密码。 登录密码:设置节点的登录密码。 确认密码:确认设置的节点登录密码。 密钥对 设置高级选项。 配置项 描述 实例保护 设置是否启用实例保护。 说明 为防止通过控制台或 API 误释放集群节点,默认启用实例保护。 实例自定义数据 请参见生成实例自定义数据。 自定义镜像 不要选择自定义镜像。安全沙箱容器集群不支持使用自定义镜像。 自定义节点名称 是否开启自定义节点名称。 节点名称由前缀 + 节点 IP 地址子串 + 后缀三部分组成: 前缀和后缀均可由.分隔的一个或多个部分构成,每个部分可以使用小写字母、数字和-,且首尾必须为小写字母和数字。 IP 地址段长度指截取节点 IP 地址末尾的位数,取值范围 5-12。 例如:节点 IP 地址为192.168.0.55,指定前缀为 aliyun.com,IP 地址段长度为 5,后缀为 test,则节点名称为aliyun.com00055test。 CPU Policy 设置 CPU policy。 none:默认策略,表示启用现有的默认 CPU 亲和方案。 static:允许为节点上具有某些资源特征的 Pod 赋予增强的 CPU 亲和性和独占性。 污点(Taints) 为集群内所有Worker节点添加污点。 单击下一步:组件配置,完成组件配置。 配置项 描述 Ingress 设置是否安装 Ingress 组件。默认勾选安装 Ingress 组件 ,请参见 Ingress 支持。 说明 如果您勾选创建 Ingress Dashboard,则需要同步安装日志服务组件。 存储插件 设置存储插件,支持 Flexvolume 和 CSI。Kubernetes 集群通过 Pod 可自动绑定阿里云云盘、NAS、 OSS 存储服务。请参见存储管理-Flexvolume 和存储管理-CSI。 云监控插件 设置是否启用云监控插件。您可以选择在 ECS 节点上安装云监控插件,从而在云监控控制台查看所创建 ECS 实例的监控信息。 日志服务 设置是否启用日志服务,您可使用已有 Project 或新建一个 Project。 勾选使用日志服务,会在集群中自动配置日志服务插件。创建应用时,您可通过简单配置,快速使用日志服务,详情参见使用日志服务进行Kubernetes日志采集。 工作流引擎 设置是否使用 AGS。 如果勾选 AGS,则创建集群时系统自动安装 AGS 工作流插件。 如果不勾选,则需要手动安装 AGS 工作流插件,请参见AGS命令行帮助。 可选组件 在系统组件之外,还可以选择安装容器服务提供的其他组件。 单击创建集群,在弹出的当前配置确认页面,单击创建,启动部署。 说明 一个包含多节点的 Kubernetes 集群的创建时间一般约为十分钟。 执行结果 集群创建成功后,您可以在容器服务管理控制台的 Kubernetes 集群列表页面查看所创建的集群。集群列表 您可以单击集群操作列的查看日志,进入集群日志信息页面查看集群的日志信息。 您也可以在集群日志信息页面中,单击资源栈事件查看更详细的信息。集群日志详情 在集群列表页面中,找到刚创建的集群,单击操作列中的管理,查看集群的基本信息和连接信息。集群基本信息 其中: API Server 公网连接端点:Kubernetes 的 API Server 对公网提供服务的地址和端口,可以通过此服务在用户终端使用 kubectl 等工具管理集群。 API Service 内网连接端点:Kubernetes 的 API server 对集群内部提供服务的地址和端口,此 IP 为负载均衡的地址。 Pod网络CIDR:Kubernetes 的 Pod CIDR 定义集群内 Pod 的网段范围。 Service CIDR:Kubernetes 的 Service CIDR 定义集群内暴露服务的网段范围。 测试域名:为集群中的服务提供测试用的访问域名。服务访问域名后缀是 <cluster_id>.<region_id>.alicontainer.com。 kube-proxy 代理模式:Kubernetes service 的服务发现和负载均衡需要通过服务代理进行配置,支持 iptables 和 IPVS 两种模式。 节点 Pod 数量:单个节点可运行 Pod 数量的上限,默认值为 128。 您可以通过kubectl连接Kubernetes集群,执行 kubectl get node查看集群的节点信息。集群结果 上一篇:概述

1934890530796658 2020-03-26 18:10:44 0 浏览量 回答数 0

回答

92题 一般来说,建立INDEX有以下益处:提高查询效率;建立唯一索引以保证数据的唯一性;设计INDEX避免排序。 缺点,INDEX的维护有以下开销:叶节点的‘分裂’消耗;INSERT、DELETE和UPDATE操作在INDEX上的维护开销;有存储要求;其他日常维护的消耗:对恢复的影响,重组的影响。 需要建立索引的情况:为了建立分区数据库的PATITION INDEX必须建立; 为了保证数据约束性需要而建立的INDEX必须建立; 为了提高查询效率,则考虑建立(是否建立要考虑相关性能及维护开销); 考虑在使用UNION,DISTINCT,GROUP BY,ORDER BY等字句的列上加索引。 91题 作用:加快查询速度。原则:(1) 如果某属性或属性组经常出现在查询条件中,考虑为该属性或属性组建立索引;(2) 如果某个属性常作为最大值和最小值等聚集函数的参数,考虑为该属性建立索引;(3) 如果某属性经常出现在连接操作的连接条件中,考虑为该属性或属性组建立索引。 90题 快照Snapshot是一个文件系统在特定时间里的镜像,对于在线实时数据备份非常有用。快照对于拥有不能停止的应用或具有常打开文件的文件系统的备份非常重要。对于只能提供一个非常短的备份时间而言,快照能保证系统的完整性。 89题 游标用于定位结果集的行,通过判断全局变量@@FETCH_STATUS可以判断是否到了最后,通常此变量不等于0表示出错或到了最后。 88题 事前触发器运行于触发事件发生之前,而事后触发器运行于触发事件发生之后。通常事前触发器可以获取事件之前和新的字段值。语句级触发器可以在语句执行前或后执行,而行级触发在触发器所影响的每一行触发一次。 87题 MySQL可以使用多个字段同时建立一个索引,叫做联合索引。在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引。具体原因为:MySQL使用索引时需要索引有序,假设现在建立了"name,age,school"的联合索引,那么索引的排序为: 先按照name排序,如果name相同,则按照age排序,如果age的值也相等,则按照school进行排序。因此在建立联合索引的时候应该注意索引列的顺序,一般情况下,将查询需求频繁或者字段选择性高的列放在前面。此外可以根据特例的查询或者表结构进行单独的调整。 86题 建立索引的时候一般要考虑到字段的使用频率,经常作为条件进行查询的字段比较适合。如果需要建立联合索引的话,还需要考虑联合索引中的顺序。此外也要考虑其他方面,比如防止过多的所有对表造成太大的压力。这些都和实际的表结构以及查询方式有关。 85题 存储过程是一组Transact-SQL语句,在一次编译后可以执行多次。因为不必重新编译Transact-SQL语句,所以执行存储过程可以提高性能。触发器是一种特殊类型的存储过程,不由用户直接调用。创建触发器时会对其进行定义,以便在对特定表或列作特定类型的数据修改时执行。 84题 存储过程是用户定义的一系列SQL语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程,而函数通常是数据库已定义的方法,它接收参数并返回某种类型的值并且不涉及特定用户表。 83题 减少表连接,减少复杂 SQL,拆分成简单SQL。减少排序:非必要不排序,利用索引排序,减少参与排序的记录数。尽量避免 select *。尽量用 join 代替子查询。尽量少使用 or,使用 in 或者 union(union all) 代替。尽量用 union all 代替 union。尽量早的将无用数据过滤:选择更优的索引,先分页再Join…。避免类型转换:索引失效。优先优化高并发的 SQL,而不是执行频率低某些“大”SQL。从全局出发优化,而不是片面调整。尽可能对每一条SQL进行 explain。 82题 如果条件中有or,即使其中有条件带索引也不会使用(要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引)。对于多列索引,不是使用的第一部分,则不会使用索引。like查询是以%开头。如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引。如果mysql估计使用全表扫描要比使用索引快,则不使用索引。例如,使用<>、not in 、not exist,对于这三种情况大多数情况下认为结果集很大,MySQL就有可能不使用索引。 81题 主键不能重复,不能为空,唯一键不能重复,可以为空。建立主键的目的是让外键来引用。一个表最多只有一个主键,但可以有很多唯一键。 80题 空值('')是不占用空间的,判断空字符用=''或者<>''来进行处理。NULL值是未知的,且占用空间,不走索引;判断 NULL 用 IS NULL 或者 is not null ,SQL 语句函数中可以使用 ifnull ()函数来进行处理。无法比较 NULL 和 0;它们是不等价的。无法使用比较运算符来测试 NULL 值,比如 =, <, 或者 <>。NULL 值可以使用 <=> 符号进行比较,该符号与等号作用相似,但对NULL有意义。进行 count ()统计某列的记录数的时候,如果采用的 NULL 值,会被系统自动忽略掉,但是空值是统计到其中。 79题 HEAP表是访问数据速度最快的MySQL表,他使用保存在内存中的散列索引。一旦服务器重启,所有heap表数据丢失。BLOB或TEXT字段是不允许的。只能使用比较运算符=,<,>,=>,= <。HEAP表不支持AUTO_INCREMENT。索引不可为NULL。 78题 如果想输入字符为十六进制数字,可以输入带有单引号的十六进制数字和前缀(X),或者只用(Ox)前缀输入十六进制数字。如果表达式上下文是字符串,则十六进制数字串将自动转换为字符串。 77题 Mysql服务器通过权限表来控制用户对数据库的访问,权限表存放在mysql数据库里,由mysql_install_db脚本初始化。这些权限表分别user,db,table_priv,columns_priv和host。 76题 在缺省模式下,MYSQL是autocommit模式的,所有的数据库更新操作都会即时提交,所以在缺省情况下,mysql是不支持事务的。但是如果你的MYSQL表类型是使用InnoDB Tables 或 BDB tables的话,你的MYSQL就可以使用事务处理,使用SET AUTOCOMMIT=0就可以使MYSQL允许在非autocommit模式,在非autocommit模式下,你必须使用COMMIT来提交你的更改,或者用ROLLBACK来回滚你的更改。 75题 它会停止递增,任何进一步的插入都将产生错误,因为密钥已被使用。 74题 创建索引的时候尽量使用唯一性大的列来创建索引,由于使用b+tree做为索引,以innodb为例,一个树节点的大小由“innodb_page_size”,为了减少树的高度,同时让一个节点能存放更多的值,索引列尽量在整数类型上创建,如果必须使用字符类型,也应该使用长度较少的字符类型。 73题 当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下: 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读。垂直分区: 根据数据库里面数据表的相关性进行拆分。简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。水平分区: 保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。水平拆分可以支撑非常大的数据量。 72题 乐观锁失败后会抛出ObjectOptimisticLockingFailureException,那么我们就针对这块考虑一下重试,自定义一个注解,用于做切面。针对注解进行切面,设置最大重试次数n,然后超过n次后就不再重试。 71题 一致性非锁定读讲的是一条记录被加了X锁其他事务仍然可以读而不被阻塞,是通过innodb的行多版本实现的,行多版本并不是实际存储多个版本记录而是通过undo实现(undo日志用来记录数据修改前的版本,回滚时会用到,用来保证事务的原子性)。一致性锁定读讲的是我可以通过SELECT语句显式地给一条记录加X锁从而保证特定应用场景下的数据一致性。 70题 数据库引擎:尤其是mysql数据库只有是InnoDB引擎的时候事物才能生效。 show engines 查看数据库默认引擎;SHOW TABLE STATUS from 数据库名字 where Name='表名' 如下;SHOW TABLE STATUS from rrz where Name='rrz_cust';修改表的引擎alter table table_name engine=innodb。 69题 如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经过一次算法即可找到相应的键值;当然了,这个前提是,键值都是唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据;如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;同理,哈希索引也没办法利用索引完成排序,以及like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询);哈希索引也不支持多列联合索引的最左匹配规则;B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题。 68题 decimal精度比float高,数据处理比float简单,一般优先考虑,但float存储的数据范围大,所以范围大的数据就只能用它了,但要注意一些处理细节,因为不精确可能会与自己想的不一致,也常有关于float 出错的问题。 67题 datetime、timestamp精确度都是秒,datetime与时区无关,存储的范围广(1001-9999),timestamp与时区有关,存储的范围小(1970-2038)。 66题 Char使用固定长度的空间进行存储,char(4)存储4个字符,根据编码方式的不同占用不同的字节,gbk编码方式,不论是中文还是英文,每个字符占用2个字节的空间,utf8编码方式,每个字符占用3个字节的空间。Varchar保存可变长度的字符串,使用额外的一个或两个字节存储字符串长度,varchar(10),除了需要存储10个字符,还需要1个字节存储长度信息(10),超过255的长度需要2个字节来存储。char和varchar后面如果有空格,char会自动去掉空格后存储,varchar虽然不会去掉空格,但在进行字符串比较时,会去掉空格进行比较。Varbinary保存变长的字符串,后面不会补\0。 65题 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。 64题 建立索引的时候一般要考虑到字段的使用频率,经常作为条件进行查询的字段比较适合。如果需要建立联合索引的话,还需要考虑联合索引中的顺序。此外也要考虑其他方面,比如防止过多的所有对表造成太大的压力。这些都和实际的表结构以及查询方式有关。 63题 存储过程是一些预编译的SQL语句。1、更加直白的理解:存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。2、存储过程是一个预编译的代码块,执行效率比较高,一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率,可以一定程度上确保数据安全。 62题 密码散列、盐、用户身份证号等固定长度的字符串应该使用char而不是varchar来存储,这样可以节省空间且提高检索效率。 61题 推荐使用自增ID,不要使用UUID。因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降。总之,在数据量大一些的情况下,用自增主键性能会好一些。 60题 char是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容。该字段都占用10个字符,而varchar是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1,最后一个字符存储使用了多长的空间。在检索效率上来讲,char > varchar,因此在使用中,如果确定某个字段的值的长度,可以使用char,否则应该尽量使用varchar。例如存储用户MD5加密后的密码,则应该使用char。 59题 一. read uncommitted(读取未提交数据) 即便是事务没有commit,但是我们仍然能读到未提交的数据,这是所有隔离级别中最低的一种。 二. read committed(可以读取其他事务提交的数据)---大多数数据库默认的隔离级别 当前会话只能读取到其他事务提交的数据,未提交的数据读不到。 三. repeatable read(可重读)---MySQL默认的隔离级别 当前会话可以重复读,就是每次读取的结果集都相同,而不管其他事务有没有提交。 四. serializable(串行化) 其他会话对该表的写操作将被挂起。可以看到,这是隔离级别中最严格的,但是这样做势必对性能造成影响。所以在实际的选用上,我们要根据当前具体的情况选用合适的。 58题 B+树的高度一般为2-4层,所以查找记录时最多只需要2-4次IO,相对二叉平衡树已经大大降低了。范围查找时,能通过叶子节点的指针获取数据。例如查找大于等于3的数据,当在叶子节点中查到3时,通过3的尾指针便能获取所有数据,而不需要再像二叉树一样再获取到3的父节点。 57题 因为事务在修改页时,要先记 undo,在记 undo 之前要记 undo 的 redo, 然后修改数据页,再记数据页修改的 redo。 Redo(里面包括 undo 的修改) 一定要比数据页先持久化到磁盘。 当事务需要回滚时,因为有 undo,可以把数据页回滚到前镜像的状态,崩溃恢复时,如果 redo log 中事务没有对应的 commit 记录,那么需要用 undo把该事务的修改回滚到事务开始之前。 如果有 commit 记录,就用 redo 前滚到该事务完成时并提交掉。 56题 redo log是物理日志,记录的是"在某个数据页上做了什么修改"。 binlog是逻辑日志,记录的是这个语句的原始逻辑,比如"给ID=2这一行的c字段加1"。 redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。 redo log是循环写的,空间固定会用完:binlog 是可以追加写入的。"追加写"是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。 最开始 MySQL 里并没有 InnoDB 引擎,MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog日志只能用于归档。而InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统,也就是 redo log 来实现 crash-safe 能力。 55题 重做日志(redo log)      作用:确保事务的持久性,防止在发生故障,脏页未写入磁盘。重启数据库会进行redo log执行重做,达到事务一致性。 回滚日志(undo log)  作用:保证数据的原子性,保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。 二进 制日志(binlog)    作用:用于主从复制,实现主从同步;用于数据库的基于时间点的还原。 错误日志(errorlog) 作用:Mysql本身启动,停止,运行期间发生的错误信息。 慢查询日志(slow query log)  作用:记录执行时间过长的sql,时间阈值可以配置,只记录执行成功。 一般查询日志(general log)    作用:记录数据库的操作明细,默认关闭,开启后会降低数据库性能 。 中继日志(relay log) 作用:用于数据库主从同步,将主库发来的bin log保存在本地,然后从库进行回放。 54题 MySQL有三种锁的级别:页级、表级、行级。 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。 死锁: 是指两个或两个以上的进程在执行过程中。因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。 死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。 那么对应的解决死锁问题的关键就是:让不同的session加锁有次序。死锁的解决办法:1.查出的线程杀死。2.设置锁的超时时间。3.指定获取锁的顺序。 53题 当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性(脏读,不可重复读,幻读等),可能产生死锁。 乐观锁:乐观锁不是数据库自带的,需要我们自己去实现。 悲观锁:在进行每次操作时都要通过获取锁才能进行对相同数据的操作。 共享锁:加了共享锁的数据对象可以被其他事务读取,但不能修改。 排他锁:当数据对象被加上排它锁时,一个事务必须得到锁才能对该数据对象进行访问,一直到事务结束锁才被释放。 行锁:就是给某一条记录加上锁。 52题 Mysql是关系型数据库,MongoDB是非关系型数据库,数据存储结构的不同。 51题 关系型数据库优点:1.保持数据的一致性(事务处理)。 2.由于以标准化为前提,数据更新的开销很小。 3. 可以进行Join等复杂查询。 缺点:1、为了维护一致性所付出的巨大代价就是其读写性能比较差。 2、固定的表结构。 3、高并发读写需求。 4、海量数据的高效率读写。 非关系型数据库优点:1、无需经过sql层的解析,读写性能很高。 2、基于键值对,数据没有耦合性,容易扩展。 3、存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,而关系型数据库则只支持基础类型。 缺点:1、不提供sql支持,学习和使用成本较高。 2、无事务处理,附加功能bi和报表等支持也不好。 redis与mongoDB的区别: 性能:TPS方面redis要大于mongodb。 可操作性:mongodb支持丰富的数据表达,索引,redis较少的网络IO次数。 可用性:MongoDB优于Redis。 一致性:redis事务支持比较弱,mongoDB不支持事务。 数据分析:mongoDB内置了数据分析的功能(mapreduce)。 应用场景:redis数据量较小的更性能操作和运算上,MongoDB主要解决海量数据的访问效率问题。 50题 如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。 49题 分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。分区使Redis的计算能力通过简单地增加计算机得到成倍提升,Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。 48题 除了缓存服务器自带的缓存失效策略之外(Redis默认的有6种策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种: 1.定时去清理过期的缓存; 2.当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。 两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,可以根据应用场景来权衡。 47题 Redis提供了两种方式来作消息队列: 一个是使用生产者消费模式模式:会让一个或者多个客户端监听消息队列,一旦消息到达,消费者马上消费,谁先抢到算谁的,如果队列里没有消息,则消费者继续监听 。另一个就是发布订阅者模式:也是一个或多个客户端订阅消息频道,只要发布者发布消息,所有订阅者都能收到消息,订阅者都是平等的。 46题 Redis的数据结构列表(list)可以实现延时队列,可以通过队列和栈来实现。blpop/brpop来替换lpop/rpop,blpop/brpop阻塞读在队列没有数据的时候,会立即进入休眠状态,一旦数据到来,则立刻醒过来。Redis的有序集合(zset)可以用于实现延时队列,消息作为value,时间作为score。Zrem 命令用于移除有序集中的一个或多个成员,不存在的成员将被忽略。当 key 存在但不是有序集类型时,返回一个错误。 45题 1.热点数据缓存:因为Redis 访问速度块、支持的数据类型比较丰富。 2.限时业务:expire 命令设置 key 的生存时间,到时间后自动删除 key。 3.计数器:incrby 命令可以实现原子性的递增。 4.排行榜:借助 SortedSet 进行热点数据的排序。 5.分布式锁:利用 Redis 的 setnx 命令进行。 6.队列机制:有 list push 和 list pop 这样的命令。 44题 一致哈希 是一种特殊的哈希算法。在使用一致哈希算法后,哈希表槽位数(大小)的改变平均只需要对 K/n 个关键字重新映射,其中K是关键字的数量, n是槽位数量。然而在传统的哈希表中,添加或删除一个槽位的几乎需要对所有关键字进行重新映射。 43题 RDB的优点:适合做冷备份;读写服务影响小,reids可以保持高性能;重启和恢复redis进程,更加快速。RDB的缺点:宕机会丢失最近5分钟的数据;文件特别大时可能会暂停数毫秒,或者甚至数秒。 AOF的优点:每个一秒执行fsync操作,最多丢失1秒钟的数据;以append-only模式写入,没有任何磁盘寻址的开销;文件过大时,不会影响客户端读写;适合做灾难性的误删除的紧急恢复。AOF的缺点:AOF日志文件比RDB数据快照文件更大,支持写QPS比RDB支持的写QPS低;比RDB脆弱,容易有bug。 42题 对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。Redis的操作之所以是原子性的,是因为Redis是单线程的。而在程序中执行多个Redis命令并非是原子性的,这也和普通数据库的表现是一样的,可以用incr或者使用Redis的事务,或者使用Redis+Lua的方式实现。对Redis来说,执行get、set以及eval等API,都是一个一个的任务,这些任务都会由Redis的线程去负责执行,任务要么执行成功,要么执行失败,这就是Redis的命令是原子性的原因。 41题 (1)twemproxy,使用方式简单(相对redis只需修改连接端口),对旧项目扩展的首选。(2)codis,目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在节点数改变情况下,旧节点数据可恢复到新hash节点。(3)redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持节点设置从节点。(4)在业务代码层实现,起几个毫无关联的redis实例,在代码层,对key进行hash计算,然后去对应的redis实例操作数据。这种方式对hash层代码要求比较高,考虑部分包括,节点失效后的代替算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。 40题 (1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件 (2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次 (3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内 (4) 尽量避免在压力很大的主库上增加从库 (5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。 39题 比如订单管理,热数据:3个月内的订单数据,查询实时性较高;温数据:3个月 ~ 12个月前的订单数据,查询频率不高;冷数据:1年前的订单数据,几乎不会查询,只有偶尔的查询需求。热数据使用mysql进行存储,需要分库分表;温数据可以存储在ES中,利用搜索引擎的特性基本上也可以做到比较快的查询;冷数据可以存放到Hive中。从存储形式来说,一般情况冷数据存储在磁带、光盘,热数据一般存放在SSD中,存取速度快,而温数据可以存放在7200转的硬盘。 38题 当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。 37题 分层架构设计,有一条准则:站点层、服务层要做到无数据无状态,这样才能任意的加节点水平扩展,数据和状态尽量存储到后端的数据存储服务,例如数据库服务或者缓存服务。显然进程内缓存违背了这一原则。 36题 更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个 jvm 内部队列中。读取数据的时候,如果发现数据不在缓存中,那么将重新读取数据+更新缓存的操作,根据唯一标识路由之后,也发送同一个 jvm 内部队列中。一个队列对应一个工作线程,每个工作线程串行拿到对应的操作,然后一条一条的执行。 35题 redis分布式锁加锁过程:通过setnx向特定的key写入一个随机值,并同时设置失效时间,写值成功既加锁成功;redis分布式锁解锁过程:匹配随机值,删除redis上的特点key数据,要保证获取数据、判断一致以及删除数据三个操作是原子的,为保证原子性一般使用lua脚本实现;在此基础上进一步优化的话,考虑使用心跳检测对锁的有效期进行续期,同时基于redis的发布订阅优雅的实现阻塞式加锁。 34题 volatile-lru:当内存不足以容纳写入数据时,从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。 volatile-ttl:当内存不足以容纳写入数据时,从已设置过期时间的数据集中挑选将要过期的数据淘汰。 volatile-random:当内存不足以容纳写入数据时,从已设置过期时间的数据集中任意选择数据淘汰。 allkeys-lru:当内存不足以容纳写入数据时,从数据集中挑选最近最少使用的数据淘汰。 allkeys-random:当内存不足以容纳写入数据时,从数据集中任意选择数据淘汰。 noeviction:禁止驱逐数据,当内存使用达到阈值的时候,所有引起申请内存的命令会报错。 33题 定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。 惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。 定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。 32题 缓存击穿,一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。如何避免:在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。 31题 缓存雪崩,是指在某一个时间段,缓存集中过期失效。大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。而缓存服务器某个节点宕机或断网,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。如何避免:1.redis高可用,搭建redis集群。2.限流降级,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。3.数据预热,在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间。 30题 缓存穿透,是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。一些恶意的请求会故意查询不存在的 key,请求量很大,对数据库造成压力,甚至压垮数据库。 如何避免:1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该 key 对应的数据 insert 了之后清理缓存。2:对一定不存在的 key 进行过滤。可以把所有的可能存在的 key 放到一个大的 Bitmap 中,查询时通过该 bitmap 过滤。 29题 1.memcached 所有的值均是简单的字符串,redis 作为其替代者,支持更为丰富的数据类型。 2.redis 的速度比 memcached 快很多。 3.redis 可以持久化其数据。 4.Redis支持数据的备份,即master-slave模式的数据备份。 5.Redis采用VM机制。 6.value大小:redis最大可以达到1GB,而memcache只有1MB。 28题 Spring Boot 推荐使用 Java 配置而非 XML 配置,但是 Spring Boot 中也可以使用 XML 配置,通过spring提供的@ImportResource来加载xml配置。例如:@ImportResource({"classpath:some-context.xml","classpath:another-context.xml"}) 27题 Spring像一个大家族,有众多衍生产品例如Spring Boot,Spring Security等等,但他们的基础都是Spring的IOC和AOP,IOC提供了依赖注入的容器,而AOP解决了面向切面的编程,然后在此两者的基础上实现了其他衍生产品的高级功能。Spring MVC是基于Servlet的一个MVC框架,主要解决WEB开发的问题,因为 Spring的配置非常复杂,各种xml,properties处理起来比较繁琐。Spring Boot遵循约定优于配置,极大降低了Spring使用门槛,又有着Spring原本灵活强大的功能。总结:Spring MVC和Spring Boot都属于Spring,Spring MVC是基于Spring的一个MVC框架,而Spring Boot是基于Spring的一套快速开发整合包。 26题 YAML 是 "YAML Ain't a Markup Language"(YAML 不是一种标记语言)的递归缩写。YAML 的配置文件后缀为 .yml,是一种人类可读的数据序列化语言,可以简单表达清单、散列表,标量等数据形态。它通常用于配置文件,与属性文件相比,YAML文件就更加结构化,而且更少混淆。可以看出YAML具有分层配置数据。 25题 Spring Boot有3种热部署方式: 1.使用springloaded配置pom.xml文件,使用mvn spring-boot:run启动。 2.使用springloaded本地加载启动,配置jvm参数-javaagent:<jar包地址> -noverify。 3.使用devtools工具包,操作简单,但是每次需要重新部署。 用

游客ih62co2qqq5ww 2020-03-27 23:56:48 0 浏览量 回答数 0

问题

梦网云通讯平台单条短信发送接口singlesend说明

梦网云通讯 2019-12-01 21:59:51 3297 浏览量 回答数 0

回答

我们都知道虚拟机的内存划分了多个区域,并不是一张大饼。那么为什么要划分为多块区域呢,直接搞一块区域,所有用到内存的地方都往这块区域里扔不就行了,岂不痛快。是的,如果不进行区域划分,扔的时候确实痛快,可用的时候再去找怎么办呢,这就引入了第一个问题,分类管理,类似于衣柜,系统磁盘等等,为了方便查找,我们会进行分区分类。另外如果不进行分区,内存用尽了怎么办呢?这里就引入了内存划分的第二个原因,就是为了方便内存的回收。如果不分,回收内存需要全部内存扫描,那就慢死了,内存根据不同的使用功能分成不同的区域,那么内存回收也就可以根据每个区域的特定进行回收,比如像栈内存中的栈帧,随着方法的执行栈帧进栈,方法执行完毕就出栈了,而对于像堆内存的回收就需要使用经典的回收算法来进行回收了,所以看起来分类这么麻烦,其实是大有好处的。 提到虚拟机的内存结构,可能首先想起来的就是堆栈。对象分配到堆上,栈上用来分配对象的引用以及一些基本数据类型相关的值。但是·虚拟机的内存结构远比此要复杂的多。除了我们所认识的(还没有认识完全)的堆栈以外,还有程序计数器,本地方法栈和方法区。我们平时所说的栈内存,一般是指的栈内存中的局部变量表。 从图中可以看到有5大内存区域,按照是否被线程所共享可分为两部分,一部分是线程独占区域,包括Java栈,本地方法栈和程序计数器。还有一部分是被线程所共享的,包括方法区和堆。什么是线程共享和线程独占呢,非常好理解,我们知道每一个Java进行都会有多个线程同时运行,那么线程共享区的这片区域就是被所有线程一起使用的,不管有多少个线程,这片空间始终就这一个。而线程的独占区,是每个线程都有这么一份内存空间,每个线程的这片空间都是独有的,有多少个线程就有多少个这么个空间。上图的区域的大小并不代表实际内存区域的大小,实际运行过程中,内存区域的大小也是可以动态调整的。下面来具体说说每一个区域的主要功能。 程序计数器,我们在写代码的过程中,开发工具一般都会给我们标注行号方便查看和阅读代码。那么在程序在运行过程中也有一个类似的行号方便虚拟机的执行,就是程序计数器,在c语言中,我们知道会有一个goto语句,其实就是跳转到了指定的行,这个行号就是程序计数器。存储的就是程序下一条所执行的指令。这部分区域是线程所独享的区域,我们知道线程是一个顺序执行流,每个线程都有自己的执行顺序,如果所有线程共用一个程序计数器,那么程序执行肯定就会出乱子。为了保证每个线程的执行顺序,所以程序计数器是被单个线程所独显的。程序计数器这块内存区域是唯一一个在jvm规范中没有规定内存溢出的。 java虚拟机栈,java虚拟机栈是程序运行的动态区域,每个方法的执行都伴随着栈帧的入栈和出栈。 栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。栈帧中包括了局部变量表,操作数栈,方法返回地址以及额外的一些附加信息,在编译过程中,局部变量表的大小已经确定,操作数栈深度也已经确定,因此栈帧在运行的过程中需要分配多大的内存是固定的,不受运行时影响。对于没有逃逸的对象也会在栈上分配内存,对象的大小其实在运行时也是确定的,因此即使出现了栈上内存分配,也不会导致栈帧改变大小。 一个线程中,可能调用链会很长,很多方法都同时处于执行状态。对于执行引擎来讲,活动线程中,只有栈顶的栈帧是最有效的,称为当前栈帧,这个栈帧所关联的方法称为当前方法。执行引擎所运行的字节码指令仅对当前栈帧进行操作。Ft5rk58GfiJxcdcCzGeAt8fjkFPkMRdf 局部变量表:我们平时所说的栈内存一般就是指栈内存中的局部变量表。这里主要是存储变量所用。对于基本数据类型直接存储其值,对于引用数据类型则存储其地址。局部变量表的最小存储单位是Slot,每个Slot都能存放一个boolean、byte、char、short、int、float、reference或returnAddress类型的数据。 既然前面提到了数据类型,在此顺便说一下,一个Slot可以存放一个32位以内的数据类型,Java中占用32位以内的数据类型有boolean、byte、char、short、int、float、reference和returnAddress八种类型。前面六种不需要多解释,大家都认识,而后面的reference是对象的引用。虚拟机规范既没有说明它的长度,也没有明确指出这个引用应有怎样的结构,但是一般来说,虚拟机实现至少都应当能从此引用中直接或间接地查找到对象在Java堆中的起始地址索引和方法区中的对象类型数据。而returnAddress是为字节码指令jsr、jsr_w和ret服务的,它指向了一条字节码指令的地址。 对于64位的数据类型,虚拟机会以高位在前的方式为其分配两个连续的Slot空间。Java语言中明确规定的64位的数据类型只有long和double两种(reference类型则可能是32位也可能是64位)。值得一提的是,这里把long和double数据类型读写分割为两次32读写的做法类似。不过,由于局部变量表建立在线程的堆栈上,是线程私有的数据,无论读写两个连续的Slot是否是原子操作,都不会引起数据安全问题。 操作数栈是一个后入先出(Last In First Out, LIFO)栈。同局部变量表一样,操作数栈的最大深度也在编译的时候被写入到字节码文件中,关于字节码文件,后面我会具体的来描述。操作数栈的每一个元素可以是任意的Java数据类型,包括long和double。32位数据类型所占的栈容量为1,64位数据类型所占的栈容量为2。在方法执行的任何时候,操作数栈的深度都不会超过在max_stacks数据项中设定的最大值。 当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令向操作数栈中写入和提取内容,也就是入栈出栈操作。例如,在做算术运算的时候是通过操作数栈来进行的,又或者在调用其他方法的时候是通过操作数栈来进行参数传递的。 举个例子,整数加法的字节码指令iadd在运行的时候要求操作数栈中最接近栈顶的两个元素已经存入了两个int型的数值,当执行这个指令时,会将这两个int值和并相加,然后将相加的结果入栈。 操作数栈中元素的数据类型必须与字节码指令的序列严格匹配,在编译程序代码的时候,编译器要严格保证这一点,在类校验阶段的数据流分析中还要再次验证这一点。再以上面的iadd指令为例,这个指令用于整型数加法,它在执行时,最接近栈顶的两个元素的数据类型必须为int型,不能出现一个long和一个float使用iadd命令相加的情况。 本地方法栈 与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。 方法区经常会被人称之为永久代,但这俩并不是一个概念。首先永久代的概念仅仅在HotSpot虚拟机中存在,不幸的是,在jdk8中,Hotspot去掉了永久代这一说法,使用了Native Memory,也就是Metaspace空间。那么方法区是干嘛的呢?我们可以这么理解,我们要运行Java代码,首先需要编译,然后才能运行。在运行的过程中,我们知道首先需要加载字节码文件。也就是说要把字节码文件加载到内存中。好了,问题就来了,字节码文件放到内存中的什么地方呢,就是方法区中。当然除了编译后的字节码之外,方法区中还会存放常量,静态变量以及及时编译器编译后的代码等数据。 堆,一般来讲堆内存是Java虚拟机中最大的一块内存区域,同方法区一样,是被所有线程所共享的区域。此区域所存在的唯一目的就存放对象的实例(对象实例并不一定全部在堆中创建)。堆内存是垃圾收集器主要光顾的区域,一般来讲根据使用的垃圾收集器的不同,堆中还会划分为一些区域,比如新生代和老年代。新生代还可以再划分为Eden,Survivor等区域。另外为了性能和安全性的角度,在堆中还会为线程划分单独的区域,称之为线程分配缓冲区。更细致的划分是为了让垃圾收集器能够更高效的工作,提高垃圾收集的效率。 如果想要了解更多的关于虚拟机的内容,可以观看录制的<深入理解Java虚拟机>这套视频教程。

zwt9000 2019-12-02 00:21:07 0 浏览量 回答数 0

回答

遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?Java 中 List 遍历的最佳实践是什么? 遍历方式有以下几种: for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。 foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。 最佳实践:Java Collections 框架中提供了一个 RandomAccess 接口,用来标记 List 实现是否支持 Random Access。 如果一个数据集合实现了该接口,就意味着它支持 Random Access,按位置读取元素的平均时间复杂度为 O(1),如ArrayList。如果没有实现该接口,表示不支持 Random Access,如LinkedList。 推荐的做法就是,支持 Random Access 的列表可用 for 循环遍历,否则建议用 Iterator 或 foreach 遍历。 说一下 ArrayList 的优缺点 ArrayList的优点如下: ArrayList 底层以数组实现,是一种随机访问模式。ArrayList 实现了 RandomAccess 接口,因此查找的时候非常快。ArrayList 在顺序添加一个元素的时候非常方便。 ArrayList 的缺点如下: 删除元素的时候,需要做一次元素复制操作。如果要复制的元素很多,那么就会比较耗费性能。插入元素的时候,也需要做一次元素复制操作,缺点同上。 ArrayList 比较适合顺序添加、随机访问的场景。 如何实现数组和 List 之间的转换? 数组转 List:使用 Arrays. asList(array) 进行转换。List 转数组:使用 List 自带的 toArray() 方法。 代码示例: ArrayList 和 LinkedList 的区别是什么? 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全; 综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。 补充:数据结构基础之双向链表 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。 ArrayList 和 Vector 的区别是什么? 这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。性能:ArrayList 在性能方面要优于 Vector。扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。 Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。 Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。 插入数据时,ArrayList、LinkedList、Vector谁速度较快?阐述 ArrayList、Vector、LinkedList 的存储性能和特性? ArrayList、LinkedList、Vector 底层的实现都是使用数组方式存储数据。数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。 Vector 中的方法由于加了 synchronized 修饰,因此 Vector 是线程安全容器,但性能上较ArrayList差。 LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但插入数据时只需要记录当前项的前后项即可,所以 LinkedList 插入速度较快。 多线程场景下如何使用 ArrayList? ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。例如像下面这样: 为什么 ArrayList 的 elementData 加上 transient 修饰? ArrayList 中的数组定义如下: private transient Object[] elementData; 再看一下 ArrayList 的定义: public class ArrayList extends AbstractList implements List<E>, RandomAccess, Cloneable, java.io.Serializable 可以看到 ArrayList 实现了 Serializable 接口,这意味着 ArrayList 支持序列化。transient 的作用是说不希望 elementData 数组被序列化,重写了 writeObject 实现: 每次序列化时,先调用 defaultWriteObject() 方法序列化 ArrayList 中的非 transient 元素,然后遍历 elementData,只序列化已存入的元素,这样既加快了序列化的速度,又减小了序列化之后的文件大小。 List 和 Set 的区别 List , Set 都是继承自Collection 接口 List 特点:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。 Set 特点:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。 另外 List 支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。 Set和List对比 Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变 Set接口 说一下 HashSet 的实现原理? HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为PRESENT,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。 HashSet如何检查重复?HashSet是如何保证数据不可重复的? 向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合equles 方法比较。 HashSet 中的add ()方法会使用HashMap 的put()方法。 HashMap 的 key 是唯一的,由源码可以看出 HashSet 添加进去的值就是作为HashMap 的key,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V。所以不会重复( HashMap 比较key是否相等是先比较hashcode 再比较equals )。 以下是HashSet 部分源码: hashCode()与equals()的相关规定: 如果两个对象相等,则hashcode一定也是相同的 两个对象相等,对两个equals方法返回true 两个对象有相同的hashcode值,它们也不一定是相等的 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖 hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。 ** ==与equals的区别** ==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同 ==是指对内存地址进行比较 equals()是对字符串的内容进行比较3.==指引用是否相同 equals()指的是值是否相同 HashSet与HashMap的区别 Queue BlockingQueue是什么? Java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。 在 Queue 中 poll()和 remove()有什么区别? 相同点:都是返回第一个元素,并在队列中删除返回的对象。 不同点:如果没有元素 poll()会返回 null,而 remove()会直接抛出 NoSuchElementException 异常。 代码示例: Queue queue = new LinkedList (); queue. offer("string"); // add System. out. println(queue. poll()); System. out. println(queue. remove()); System. out. println(queue. size()); Map接口 说一下 HashMap 的实现原理? HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 HashMap的数据结构: 在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。 HashMap 基于 Hash 算法实现的 当我们往Hashmap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,则覆盖原始值;(2)如果key不同(出现冲突),则将当前的key-value放入链表中获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。 需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn) HashMap在JDK1.7和JDK1.8中有哪些不同?HashMap的底层实现 在Java中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是:寻址容易,插入和删除困难;链表的特点是:寻址困难,但插入和删除容易;所以我们将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做拉链法的方式可以解决哈希冲突。 JDK1.8之前 JDK1.8之前采用的是拉链法。拉链法:将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。 JDK1.8之后 相比于之前的版本,jdk1.8在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。 JDK1.7 VS JDK1.8 比较 JDK1.8主要解决或优化了一下问题: resize 扩容优化引入了红黑树,目的是避免单条链表过长而影响查询效率,红黑树算法请参考解决了多线程死循环问题,但仍是非线程安全的,多线程时可能会造成数据丢失问题。 HashMap的put方法的具体流程? 当我们put的时候,首先计算 key的hash值,这里调用了 hash方法,hash方法实际是让key.hashCode()与key.hashCode()>>>16进行异或操作,高16bit补0,一个数和0异或不变,所以 hash 函数大概的作用就是:高16bit不变,低16bit和高16bit做了一个异或,目的是减少碰撞。按照函数注释,因为bucket数组大小是2的幂,计算下标index = (table.length - 1) & hash,如果不做 hash 处理,相当于散列生效的只有几个低 bit 位,为了减少散列的碰撞,设计者综合考虑了速度、作用、质量之后,使用高16bit和低16bit异或来简单处理减少碰撞,而且JDK8中用了复杂度 O(logn)的树结构来提升碰撞下的性能。 putVal方法执行流程图 ①.判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容; ②.根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③; ③.判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals; ④.判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向⑤; ⑤.遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可; ⑥.插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。 HashMap的扩容操作是怎么实现的? ①.在jdk1.8中,resize方法是在hashmap中的键值对大于阀值时或者初始化时,就调用resize方法进行扩容; ②.每次扩展的时候,都是扩展2倍; ③.扩展后Node对象的位置要么在原位置,要么移动到原偏移量两倍的位置。 在putVal()中,我们看到在这个函数里面使用到了2次resize()方法,resize()方法表示的在进行第一次初始化时会对其进行扩容,或者当该数组的实际大小大于其临界值值(第一次为12),这个时候在扩容的同时也会伴随的桶上面的元素进行重新分发,这也是JDK1.8版本的一个优化的地方,在1.7中,扩容之后需要重新去计算其Hash值,根据Hash值对其进行分发,但在1.8版本中,则是根据在同一个桶的位置中进行判断(e.hash & oldCap)是否为0,重新进行hash分配后,该元素的位置要么停留在原始位置,要么移动到原始位置+增加的数组大小这个位置上 HashMap是怎么解决哈希冲突的? 答:在解决这个问题之前,我们首先需要知道什么是哈希冲突,而在了解哈希冲突之前我们还要知道什么是哈希才行; 什么是哈希? Hash,一般翻译为“散列”,也有直接音译为“哈希”的,这就是把任意长度的输入通过散列算法,变换成固定长度的输出,该输出就是散列值(哈希值);这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。 所有散列函数都有如下一个基本特性**:根据同一散列函数计算出的散列值如果不同,那么输入值肯定也不同。但是,根据同一散列函数计算出的散列值如果相同,输入值不一定相同**。 什么是哈希冲突? 当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们就把它叫做碰撞(哈希碰撞)。 HashMap的数据结构 在Java中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是:寻址容易,插入和删除困难;链表的特点是:寻址困难,但插入和删除容易;所以我们将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做链地址法的方式可以解决哈希冲突: 这样我们就可以将拥有相同哈希值的对象组织成一个链表放在hash值所对应的bucket下,但相比于hashCode返回的int类型,我们HashMap初始的容量大小DEFAULT_INITIAL_CAPACITY = 1 << 4(即2的四次方16)要远小于int类型的范围,所以我们如果只是单纯的用hashCode取余来获取对应的bucket这将会大大增加哈希碰撞的概率,并且最坏情况下还会将HashMap变成一个单链表,所以我们还需要对hashCode作一定的优化 hash()函数 上面提到的问题,主要是因为如果使用hashCode取余,那么相当于参与运算的只有hashCode的低位,高位是没有起到任何作用的,所以我们的思路就是让hashCode取值出的高位也参与运算,进一步降低hash碰撞的概率,使得数据分布更平均,我们把这样的操作称为扰动,在JDK 1.8中的hash()函数如下: static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);// 与自己右移16位进行异或运算(高低位异或) } 这比在JDK 1.7中,更为简洁,相比在1.7中的4次位运算,5次异或运算(9次扰动),在1.8中,只进行了1次位运算和1次异或运算(2次扰动); JDK1.8新增红黑树 通过上面的链地址法(使用散列表)和扰动函数我们成功让我们的数据分布更平均,哈希碰撞减少,但是当我们的HashMap中存在大量数据时,加入我们某个bucket下对应的链表有n个元素,那么遍历时间复杂度就为O(n),为了针对这个问题,JDK1.8在HashMap中新增了红黑树的数据结构,进一步使得遍历复杂度降低至O(logn); 总结 简单总结一下HashMap是使用了哪些方法来有效解决哈希冲突的: 使用链地址法(使用散列表)来链接拥有相同hash值的数据;使用2次扰动函数(hash函数)来降低哈希冲突的概率,使得数据分布更平均;引入红黑树进一步降低遍历的时间复杂度,使得遍历更快; **能否使用任何类作为 Map 的 key? **可以使用任何类作为 Map 的 key,然而在使用之前,需要考虑以下几点: 如果类重写了 equals() 方法,也应该重写 hashCode() 方法。 类的所有实例需要遵循与 equals() 和 hashCode() 相关的规则。 如果一个类没有使用 equals(),不应该在 hashCode() 中使用它。 用户自定义 Key 类最佳实践是使之为不可变的,这样 hashCode() 值可以被缓存起来,拥有更好的性能。不可变的类也可以确保 hashCode() 和 equals() 在未来不会改变,这样就会解决与可变相关的问题了。 为什么HashMap中String、Integer这样的包装类适合作为K? 答:String、Integer等包装类的特性能够保证Hash值的不可更改性和计算准确性,能够有效的减少Hash碰撞的几率 都是final类型,即不可变性,保证key的不可更改性,不会存在获取hash值不同的情况 内部已重写了equals()、hashCode()等方法,遵守了HashMap内部的规范(不清楚可以去上面看看putValue的过程),不容易出现Hash值计算错误的情况; 如果使用Object作为HashMap的Key,应该怎么办呢? 答:重写hashCode()和equals()方法 重写hashCode()是因为需要计算存储数据的存储位置,需要注意不要试图从散列码计算中排除掉一个对象的关键部分来提高性能,这样虽然能更快但可能会导致更多的Hash碰撞; 重写equals()方法,需要遵守自反性、对称性、传递性、一致性以及对于任何非null的引用值x,x.equals(null)必须返回false的这几个特性,目的是为了保证key在哈希表中的唯一性; HashMap为什么不直接使用hashCode()处理后的哈希值直接作为table的下标 答:hashCode()方法返回的是int整数类型,其范围为-(2 ^ 31)~(2 ^ 31 - 1),约有40亿个映射空间,而HashMap的容量范围是在16(初始化默认值)~2 ^ 30,HashMap通常情况下是取不到最大值的,并且设备上也难以提供这么多的存储空间,从而导致通过hashCode()计算出的哈希值可能不在数组大小范围内,进而无法匹配存储位置; 那怎么解决呢? HashMap自己实现了自己的hash()方法,通过两次扰动使得它自己的哈希值高低位自行进行异或运算,降低哈希碰撞概率也使得数据分布更平均; 在保证数组长度为2的幂次方的时候,使用hash()运算之后的值与运算(&)(数组长度 - 1)来获取数组下标的方式进行存储,这样一来是比取余操作更加有效率,二来也是因为只有当数组长度为2的幂次方时,h&(length-1)才等价于h%length,三来解决了“哈希值与数组大小范围不匹配”的问题; HashMap 的长度为什么是2的幂次方 为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀,每个链表/红黑树长度大致相同。这个实现就是把数据存到哪个链表/红黑树中的算法。 这个算法应该如何设计呢? 我们首先可能会想到采用%取余的操作来实现。但是,重点来了:“取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。 那为什么是两次扰动呢? 答:这样就是加大哈希值低位的随机性,使得分布更均匀,从而提高对应数组存储下标位置的随机性&均匀性,最终减少Hash冲突,两次就够了,已经达到了高位低位同时参与运算的目的; HashMap 与 HashTable 有什么区别? 线程安全: HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!); 效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它; 对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛NullPointerException。 **初始容量大小和每次扩充容量大小的不同 **: ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。 推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代。 如何决定使用 HashMap 还是 TreeMap? 对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。 HashMap 和 ConcurrentHashMap 的区别 ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的synchronized锁的粒度更精细了一些,并发性能更好,而HashMap没有锁机制,不是线程安全的。(JDK1.8之后ConcurrentHashMap启用了一种全新的方式实现,利用CAS算法。) HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。 ConcurrentHashMap 和 Hashtable 的区别? ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。 底层数据结构: JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用 数组+链表 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的; 实现线程安全的方式(重要): ① 在JDK1.7的时候,ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。(默认分配16个Segment,比Hashtable效率提高16倍。) 到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化) 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本;② Hashtable(同一把锁) :使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用 put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。 两者的对比图: HashTable: JDK1.7的ConcurrentHashMap: JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点 Node: 链表节点): 答:ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,HashTable 考虑了同步的问题。但是 HashTable 在每次同步执行时都要锁住整个结构。 ConcurrentHashMap 锁的方式是稍微细粒度的。 ConcurrentHashMap 底层具体实现知道吗?实现原理是什么? JDK1.7 首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。 在JDK1.7中,ConcurrentHashMap采用Segment + HashEntry的方式进行实现,结构如下: 一个 ConcurrentHashMap 里包含一个 Segment 数组。Segment 的结构和HashMap类似,是一种数组和链表结构,一个 Segment 包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护着一个HashEntry数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment的锁。 该类包含两个静态内部类 HashEntry 和 Segment ;前者用来封装映射表的键值对,后者用来充当锁的角色;Segment 是一种可重入的锁 ReentrantLock,每个 Segment 守护一个HashEntry 数组里得元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 锁。 JDK1.8 在JDK1.8中,放弃了Segment臃肿的设计,取而代之的是采用Node + CAS + Synchronized来保证并发安全进行实现,synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。 结构如下: 如果该节点是TreeBin类型的节点,说明是红黑树结构,则通过putTreeVal方法往红黑树中插入节点;如果binCount不为0,说明put操作对数据产生了影响,如果当前链表的个数达到8个,则通过treeifyBin方法转化为红黑树,如果oldVal不为空,说明是一次更新操作,没有对元素个数产生影响,则直接返回旧值;如果插入的是一个新节点,则执行addCount()方法尝试更新元素个数baseCount; 辅助工具类 Array 和 ArrayList 有何区别? Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。 对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。 如何实现 Array 和 List 之间的转换? Array 转 List: Arrays. asList(array) ;List 转 Array:List 的 toArray() 方法。 comparable 和 comparator的区别? comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用来排序 一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo方法或compare方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写compareTo方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的Collections.sort(). 方法如何比较元素? TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进 行排 序。 Collections 工具类的 sort 方法有两种重载的形式, 第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现元素的比较; 第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator 接口的子类型(需要重写 compare 方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java 中对函数式编程的支持)。

剑曼红尘 2020-03-24 14:41:57 0 浏览量 回答数 0

问题

比较Apache Hadoop生态系统中不同的文件格式和存储引擎的性能

anrui2016 2019-12-01 22:03:39 2706 浏览量 回答数 0

问题

【阿里云产品公测】简单日志服务SLS使用评测含教程

mr_wid 2019-12-01 21:08:11 36639 浏览量 回答数 20

回答

转自:阿飞的博客 一、数据库技术选型的思考维度 我们做选型的时候首先要问: 谁选型?是负责采购的同学、 DBA 还是业务研发? 如果选型的是采购的同学,他们更注重成本,包括存储方式、网络需求等。 如果选型的是 DBA 同学,他们关心的: ① 运维成本 首先是运维成本,包括监控告警是否完善、是否有备份恢复机制、升级和迁移的成本是否高、社区是否稳定、是否方便调优、排障是否简易等; ② 稳定性 其次,DBA会关注稳定性,包括是否支持数据多副本、服务高可用、多写多活等; ③ 性能 第三是性能,包括延迟、QPS 以及是否支持更高级的分级存储功能等; ④ 拓展性 第四是扩展性,如果业务的需求不确定,是否容易横向扩展和纵向扩容; ⑤ 安全 最后是安全,需要符合审计要求,不容易出现 SQL 注入或拖库情况。 ⑥ 其他 除了采购和 DBA之外,后台应用研发的同学同样会关注稳定性、性能、扩展性等问题,同时也非常关注数据库接口是否便于开发,是否便于修改数据库 schema 等问题。 接下来我们来看一下爱奇艺使用的数据库类型: MySQL,互联网业务必备系统; TiDB,爱奇艺的 TiDB 实践会有另外的具体介绍; Redis,KV 数据库,互联网公司标配; Couchbase,这个在爱奇艺用得比较多,但国内互联网公司用得比较少,接下来的部分会详细说明; 其他,比如 MongoDB、图数据库、自研 KV 数据库 HiKV 等; 大数据分析相关系统,比如 Hive、Impala 等等。 可以看到爱奇艺的数据库种类还是很多的,这会造成业务开发的同学可能不太清楚在他的业务场景下应该选用哪种数据库系统。 那么,我们先对这些数据库按照接口(SQL、NoSQL)和面向的业务场景(OLTP、OLAP)这两位维度进行一个简单非严谨的分类。 下图中,左上角是面向 OLTP、支持 SQL 的这样一类系统,例如 MySQL,一般支持事务不同的隔离级别, QPS 要求比较高,延时比较低,主要用于交易信息和关键数据的存储,比如订单、VIP 信息等。 左下角是 NoSQL 数据库,是一类针对特殊场景做优化的系统,schema 一般比较简单,吞吐量较高、延迟较低,一般用作缓存或者 KV 数据库。 整个右侧都是 OLAP 的大数据分析系统,包括 Clickhouse、Impala等,一般支持SQL、不支持事务,扩展性比较好,可以通过加机器增加数据的存储量,响应延迟较长。 还有一类数据库是比较中立的,在数据量比较小的时候性能比较好,在数据量较大或复杂查询的时候性能也不差,一般通过不同的存储引擎和查询引擎来满足不同的业务需求,我们把它叫做 HTAP,TiDB 就是这样一种数据库。 二、iQIYI对数据库的优化与完善 前面我们提到了很多种的数据库,那么接下来就和大家介绍一下在爱奇艺我们是怎么使用这些数据库的。 1、MySQL在爱奇艺的使用 ① MySQL 首先是 MySQL。MySQL 基本使用方式是 master-slave + 半同步,支持每周全备+每日增量备份。我们做了一些基本功能的增强,首先是增强了数据恢复工具 Xtrabackup 的性能。 之前遇到一个情况,我们有一个全量库是 300G 数据,增量库每天 70G 数据,总数据量 700G 左右。我们当时只需要恢复一个表的数据,但该工具不支持单表恢复,且整库恢复需要 5 个小时。 针对这个情况我们具体排查了原因,发现在数据恢复的过程中需要进行多次写盘的 IO 操作并且有很多串行操作,所以我们做了一些优化。例如删减过程中的一些写盘操作,减少落盘并将数据处理并行化,优化后整库恢复耗时减少到 100 分钟,而且可以直接恢复单表数据。 然后是适配 DDL 和 DML 工具到内部系统,gh-ostt 和 oak-online-alter-table 在数据量大的时候会造成 master-slave 延时,所以我们在使用工具的时候也增加了延时上的考虑,实时探测Master-Slave 库之间延时的情况,如果延时较大会暂停工具的使用,恢复到正常水平再继续。 ② MySQL高可用 第二是 MySQL 高可用。Master-slave 加上半同步这种高可用方式不太完善,所以我们参照了 MHA 并进行了改动,采用 master + agent 的方式。Agent 在每一个物理机上部署,可以监控这个物理机上的所有实例的状态,周期性地向 master 发送心跳,Master 会实时监测各个Agent的状态。 如果 MySQL故障,会启动 Binlog 补偿机制,并切换访问域名完成 failover。考虑到数据库跨机房跨地区部署的情况,MHA 的 master 我们也做了高可用设计,众多 master 会通过 raft 组成一个 raft group,类似 TiDB 的 PD 模块。目前 MySQL failover 策略支持三种方式:同机房、同地域跨机房以及跨地域。 ③ MySQL拓展能力 第三是提高MySQL扩展能力,以提供更大容量的数据存储。扩展方式有 SDK,例如开源的 ShardingSphere,在爱奇艺的使用也比较广泛。另外就是 Proxy,开源的就更多了。但是 SDK 和 Proxy 使用的问题是支持的 SQL 语句简单,扩容难度大,依赖较多且运维复杂,所以部分业务已经迁移至 TiDB。 ④ 审计 第四是审计。我们在 MySQL 上做了一个插件获取全量 SQL 操作,后端打到 Kafka,下游再接入包括 Clickhouse 等目标端进行 SQL 统计分析。除此之外还有安全策略,包括主动探索是否有 SQL 注入及是否存在拖库情况等,并触发对应的告警。 MySQL 审计插件最大的问题是如何降低对 MySQL 性能的影响,对此我们进行了一些测试,发现使用 General Log 对性能损耗较大,有 10%~20% 的降低。 于是我们通过接口来获取 MySQL 插件里的监控项,再把监控项放到 buffer 里边,用两级的 RingBuffer 来保证数据的写入不会有锁资源竞争。在这个插件里再启动一个线程,从 RingBuffer 里读取数据并把数据打包写到 FIFO 管道里。 我们在每台 MySQL 的物理机里再启动一个 Agent,从管道里阻塞地读取数据发至 Kafka。优化后我们再次进行压测,在每台机器上有 15 万的更新、删除或插入操作下不会丢失数据,性能损耗一般情况下小于 2%。 目前已经在公司内部的集群上线了一年时间,运行比较稳定,上线和下线对业务没有影响。 ⑤ 分级存储 第五是分级存储。MySQL 里会存一些过程性的数据,即只需要读写最近一段时间存入的数据,过段时间这些数据就不需要了,需要进行定时清理。 分级存储就是在 MySQL 之上又用了其他存储方式,例如 TiDB 或其他 TokuDB,两者之间可以进行数据自动搬迁和自动归档,同时前端通过 SDK + Proxy 来做统一的访问入口。这样一来,业务的开发同学只需要将数据存入 MySQL 里,读取时可能从后端接入的任意数据库读出。这种方式目前只是过渡使用,之后会根据 TiDB 的特性进行逐步迁移。 Redis在爱奇艺的使用 接下来是 Redis。Redis 也是使用 master - slave 这种方式,由于网络的复杂性我们对 Sentinel 的部署进行了一些特殊配置,在多机房的情况下每个机房配置一定数量 Sentinel 来避免脑裂。 备份恢复方面介绍一个我们的特殊场景,虽然 Redis 是一个缓存,但我们发现不少的业务同学会把它当做一个 KVDB 来使用,在某些情况下会造成数据的丢失。 所以我们做了一个 Redis 实时备份功能,启动一个进程伪装成 Redis 的 Slave 实时获取数据,再放到后端的 KV 存储里,例如 ScyllaDB,如果要恢复就可以从 ScyllaDB 里把数据拉出来。 我们在用 Redis 时最大的痛点就是它对网络的延迟或抖动非常敏感。如有抖动造成 Redis Master 超时,会由 Sentinel 重新选出一个新的节点成为 Master,再把该节点上的数据同步到所有 Slave 上,此过程中数据会放在 Master 节点的 Buffer 里,如果写入的 QPS 很高会造成 Buffer 满溢。如果 Buffer 满后 RDB 文件还没有拷贝过去,重建过程就会失败。 基于这种情况,我们对 Redis 告警做了自动化优化,如有大量 master - slave 重建失败,我们会动态调整一些参数,例如把 Buffer 临时调大等, 此外我们还做了 Redis 集群的自动扩缩容功能。 我们在做 Redis 开发时如果是 Java 语言都会用到 Jedis。用 Jedis 访问客户端分片的 Redis 集群,如果某个分片发生了故障或者 failover,Jedis 就会对所有后端的分片重建连接。如果某一分片发生问题,整个 Redis 的访问性能和 QPS 会大幅降低。针对这个情况我们优化了 Jedis,如果某个分片发生故障,就只针对这个分片进行重建。 在业务访问 Redis 时我们会对 Master 绑定一个读写域名,多个从库绑定读域名。但如果我们进行 Master failover,会将读写域名从某旧 Master 解绑,再绑定到新 Master 节点上。 DNS 本身有一个超时时间,所以数据库做完 failover 后业务程序里没有立刻获取到新的 Master 节点的 IP的话,有可能还会连到原来的机器上,造成访问失败。 我们的解决方法是把 DNS 的 TTL 缩短,但对 DNS 服务又会造成很大的压力,所以我们在 SDK 上提供 Redis 的名字服务 RNS,RNS 从 Sentinel 里获取集群的拓扑和拓扑的变化情况,如果集群 failover,Sentinel 会接到通知,客户端就可以通过 RNS 来获取新的 Master 节点的 IP 地址。我们去掉域名,通过 IP 地址来访问整个集群,屏蔽了 DNS 的超时,缩短了故障的恢复时间。 SDK 上还做了一些功能,例如 Load Balance 以及故障检测,比如某个节点延时较高的话会被临时熔断等。 客户端分片的方式会造成 Redis 的扩容非常痛苦,如果客户端已经进行了一定量的分片,之后再增加就会非常艰难。 Redis 在 3.0 版本后会提供 Redis Cluster,因为功能受限在爱奇艺应用的不是很多,例如不支持显示跨 DC 部署和访问,读写只在主库上等。 我们某些业务场景下会使用 Redis 集群,例如数据库访问只发生在本 DC,我们会在 DC 内部进行 Cluster 部署。 但有些业务在使用的过程中还是想做 failover,如果集群故障可以切换到其他集群。根据这种情况我们做了一个 Proxy,读写都通过它来进行。写入数据时 Proxy 会做一个旁路,把新增的数据写在 Kafka 里,后台启用同步程序再把 Kafka 里的数据同步到其他集群,但存在一些限制,比如我们没有做冲突检测,所以集群间数据需要业务的同学做单元化。线上环境的Redis Cluster 集群间场景跨 DC 同步 需要 50 毫秒左右的时间。 2、Couchbase在爱奇艺的使用 Redis 虽然提供 Cluster 这种部署方式,但存在一些问题。所以数据量较大的时候(经验是 160G),就不推荐 Redis 了,而是采用另一种存储方式 Couchbase。 Couchbase 在国内互联网公司用的比较少,一开始我们是把他当做一个 Memcached 来使用的,即纯粹的缓存系统。 但其实它性能还是比较强大的,是一个分布式高性能的 KV 系统,支持多种存储引擎 (bucket)。第一种是 Memcached bucket,使用方式和 Memcached 一样为 KV 存储,不支持数据持久化也没有数据副本,如果节点故障会丢失数据; 第二种是 Couchbase bucket,支持数据持久化,使用 Json 写入,有副本,我们一般会在线上配置两个副本,如果新加节点会对数据进行 rebalance,爱奇艺使用的一般是 Couchbase bucket 这种配置。 Couchbase 数据的分布如下图,数据写入时在客户端上会先进行一次哈希运算,运算完后会定位 Key 在哪一个 vBucket (相当于数据库里的某个分片)。之后客户端会根据 Cluster Map 发送信息至对应的服务端,客户端的 Cluster Map 保存的是 vBucket 和服务器的映射关系,在服务端数据迁移的过程中客户端的 Cluster Map 映射关系会动态更新,因此客户端对于服务端的 failover 操作不需要做特殊处理,但可能在 rebalance 过程中会有短暂的超时,导致的告警对业务影响不大。 Couchbase 在爱奇艺应用比较早,2012 年还没有 Redis Cluster 的时候就开始使用了。集群管理使用 erlang 语言开发,最大功能是进行集群间的复制,提供多种复制方式:单向、双向、星型、环式、链式等。 爱奇艺从最初的 1.8 版本使用到如今的 5.0 版本,正在调研的 6.0,中间也遇到了很多坑,例如 NTP 时间配置出错会导致崩溃,如果每个集群对外 XDCR 并发过高导致不稳定,同步方向变更会导致数据丢失等等,我们通过运维和一些外部工具来进行规避。 Couchbase 的集群是独立集群,集群间的数据同步通过 XDCR,我们一般配置为双向同步。对于业务来说,如果 Cluster 1 写入, Cluster 2 不写入,正常情况下客户端会写 Cluster 1。如果 Cluster 1 有故障,我们提供了一个 Java SDK,可以在配置中心把写入更改到 Cluster 2,把原来到 Cluster 1 的连接逐步断掉再与Cluster 2 新建连接。这种集群 failover 的过程对于客户端来说是相对透明和无感的。 3、爱奇艺自研数据库HiKV的使用 Couchbase 虽然性能非常高,并且数据的存储可以超过内存。但是,如果数据量超过内存 75% 这个阈值,性能就会下降地特别快。在爱奇艺,我们会把数据量控制在可用内存的范围之内,当做内存数据库使用。但是它的成本非常高,所以我们后面又开发了一个新的数据库—— HiKV。 开发 HiKV 的目的是为了把一些对性能要求没那么高的 Couchbase 应用迁移到 HiKV 上。HiKV 基于开源系统 ScyllaDB,主要使用了其分布式数据库的管理功能,增加了单机存储引擎 HiKV。 ScyllaDB 比较吸引人的是它宣称性能高于 Cassandra 十倍,又完全兼容 Cassandra 接口,设计基本一致,可以视为 C++ 版 Cassandra 系统。 ScyllaDB 性能的提升主要是使用了一些新的技术框架,例如 C++ 异步框架 seastar,主要原理是在j每台物理机的核上会 attach 一个应用线程,每个核上有自己独立的内存、网络、IO 资源,核与核之间没有数据共享但可以通信,其最大的好处是内存访问无锁,没有冲突过程。 当一个数据读或写到达 ScyllaDB 的 server 时,会按照哈希算法来判断请求的 Key 是否是该线程需要处理的,如果是则本线程处理,否则会转发到对应线程上去。 除此之外,它还支持多副本、多数据中心、多写多活,功能比较强大。 在爱奇艺,我们基于 SSD 做了一个 KV 存储引擎。Key 放在内存里,Value 放在盘上的文件里,我们在读和写文件时,只需要在内存索引里定位,再进行一次盘的 IO 开销就可以把数据读出来,相比 ScyllaDB 原本基于 LSM Tree 的存储引擎方式对 IO 的开销较少。 索引数据全部放在内存中,如果索引长度较长会限制单机可存储的数据量,于是我们通过开发定长的内存分布器,对于比较长的 Key 做摘要缩短长度至 20 字节,采用红黑树索引,限制每条记录在内存里的索引长度至为 64 字节。内存数据要定期做 checkpoint,客户端要做限流、熔断等。 HiKV 目前在爱奇艺应用范围比较大,截至目前已经替换了 30% 的 Couchbase,有效地降低了存储成本。 4、爱奇艺的数据库运维管理 爱奇艺数据库种类较多,如何高效地运维和管理这些数据库也是经历了不同的阶段。 最初我们通过 DBA 写脚本的方式管理,如果脚本出问题就找 DBA,导致了 DBA 特别忙碌。 第二个阶段我们考虑让大家自己去查问题的答案,于是在内部构建了一个私有云,通过 Web 的方式展示数据库运行状态,让业务的同学可以自己去申请集群,一些简单的操作也可以通过自服务平台实现,解放了 DBA。一些需要人工处理的大型运维操作经常会造成一些人为故障,敲错参数造成数据丢失等。 于是在第三个阶段我们把运维操作 Web 化,通过网页点击可以进行 90% 的操作。 第四个阶段让经验丰富的 DBA 把自身经验变成一些工具,比如有业务同学说 MySQL master-slave 延时了,DBA 会通过一系列操作排查问题。现在我们把这些操作串起来形成一套工具,出问题时业务的同学可以自己通过网页上的一键诊断工具去排查,自助进行处理。 除此之外我们还会定期做预警检查,对业务集群里潜在的问题进行预警报告;开发智能客服,回答问题;通过监控的数据对实例打标签,进行削峰填谷地智能调度,提高资源利用率。 三、不同场景下数据库选型建议 1、实用数据库选型树 最后来说一些具体数据库选型建议。这是 DBA 和业务一起,通过经验得出来的一些结论。 对于关系型数据库的选型来说,可以从数据量和扩展性两个维度考虑,再根据数据库有没有冷备、要不要使用 Toku 存储引擎,要不要使用 Proxy 等等进行抉择。 NoSQL 也是什么情况下使用 master-slave,什么情况下使用客户端分片、集群、Couchbase、HiKV 等,我们内部自服务平台上都有这个选型树信息。 2、一些思考 ① 需求 我们在选型时先思考需求,判断需求是否真实。 你可以从数据量、QPS、延时等方面考虑需求,但这些都是真实需求吗?是否可以通过其他方式把这个需求消耗掉,例如在数据量大的情况下可以先做数据编码或者压缩,数据量可能就降下来了。 不要把所有需求都推到数据库层面,它其实是一个兜底的系统。 ② 选择 第二个思考的点是对于某个数据库系统或是某个技术选型我们应该考虑什么?是因为热门吗?还是因为技术上比较先进?但是不是能真正地解决你的问题?如果你数据量不是很大的话就不需要选择可以存储大数据量的系统。 ③ 放弃 第三是放弃,当你放弃一个系统时真的是因为不好用吗?还是没有用好?放弃一个东西很难,但在放弃时最好有一个充分的理由,包括实测的结果。 ④ 自研 第四是自研,在需要自己开发数据库时可以参考和使用一些成熟的产品,但不要盲目自研。 ⑤ 开源 最后是开源,要有拥抱开源的态度。

茶什i 2019-12-27 14:17:56 0 浏览量 回答数 0

回答

for(int i=0;i<a.length;i++) ar.data[i]=a[i]; for(int j=i;j<b.length;j++) ar.data[j]=b[j]; 这段逻辑有问题吧 j<b.length ,这个判断就直接为false了 应该是j<(a.length + b.length) ,而且第二个for循环给j赋值的i 属于上个for循环的局部变量吧 而且相加返回的时候 应该用赋值构造函数吧。。###### 引用来自“jqy”的答案 for(int i=0;i<a.length;i++) ar.data[i]=a[i]; for(int j=i;j<b.length;j++) ar.data[j]=b[j]; 这段逻辑有问题吧 j<b.length ,这个判断就直接为false了 应该是j<(a.length + b.length) ,而且第二个for循环给j赋值的i 属于上个for循环的局部变量吧 对,这个我已经改过来了。 我想问下我的insert函数,每插入一个数,就要申请一个空间,以至于我的构造函数,比数组原长要申请多一个才能插入一个数,否则会出错,难道只能通过这种方法,在构造函数加长数组,有没有别的方法 ###### 引用来自“java_hh”的答案 引用来自“jqy”的答案 for(int i=0;i<a.length;i++) ar.data[i]=a[i]; for(int j=i;j<b.length;j++) ar.data[j]=b[j]; 这段逻辑有问题吧 j<b.length ,这个判断就直接为false了 应该是j<(a.length + b.length) ,而且第二个for循环给j赋值的i 属于上个for循环的局部变量吧 对,这个我已经改过来了。 我想问下我的insert函数,每插入一个数,就要申请一个空间,以至于我的构造函数,比数组原长要申请多一个才能插入一个数,否则会出错,难道只能通过这种方法,在构造函数加长数组,有没有别的方法 这个就是数组的缺陷吧,不能动态增长,只能动态申请。如果需要动态添加的话,我觉得最好用链表。 ###### Array<T> ar; //这里调用无参构造函数,应该用有参的,用下一行的l为参数传入就行了,         int l=a.length+b.length;          ar.data=new T[l]; //这行会导致内存泄漏,不要这行,其它的保持原样应该可以了         for(int i=0;i<a.length;i++)              ar.data[i]=a[i];          for(int j=i;j<b.length;j++)              ar.data[j]=b[j];          return ar;  有标准的std::vector<T>或std::list<T>可用,不用自己写的.######恩, 我已经改为     Array <T> & operator +(Array<T> & a)     {             for(int i=length;i<a.length+length;i++)             data[i]=a[i-length];         length=length+a.length;         return *this;     } ###### @jqy : 你看代码,他并没有重新new新的内存.如果在for之前新new一个大小为this.length+a.length的大小就可以.同时原来的要先保存,复制之后再删除.###### @周翼翼 : 这个data用new动态分配,应该没什么问题吧!只是新增的时候,必须delete掉,然后重新分配length+1的长度的空间。######这个有大问题,你只是拼命给原来的data里放数据,可是data的内存大小在构造的时候已经定了,你这么放肯定会出事.你想,data=new T[lenght],你给data[length]赋值,...结果会怎么样?

爱吃鱼的程序员 2020-06-04 16:50:43 0 浏览量 回答数 0

问题

十大经典排序算法大梳理 7月6日 【今日算法】

游客ih62co2qqq5ww 2020-07-07 02:04:48 1002 浏览量 回答数 1

回答

一、Java内存分配     Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域存储不同类型的数据,这些区域的内存分配和销毁的时间也不同,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。根据《Java虚拟机规范(第2版)》的规定,Java虚拟机管理的内存包括五个运行时数据区域,如下图所示:      1、方法区     方法区(Method Area)是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息(包括类的名称、方法信息、成员变量信息)、常量、静态变量、以及编译器编译后的代码等数据。当方法区无法满足内存分配需求时,将抛出OutOfMemeryError异常。     运行时常量池(Runtime Constant Pool)是方法区的一部分,此区域会在两种情况下存储数据。     (1)class文件的常量池中的数据     class文件中的常量池用于存放编译期生成的各种字面值和常量,这部分内容在类被加载后存放到方法区的运行时常量池中。     字面值:private String name="zhangSan";private int age = 23+3;     常量:private final String TAG = "MainActivity";private final int age = 26;     (2)运行期间生成的常量     运行时常量池相对于class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只能在编译期产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。String str = "abc".intern();当运行时常量池中存在字符串"abc时,将该字符串的引用返回,赋值给str,否则创建字符串"abc",加入运行时常量池中,并返回引用赋值给str。既然运行时常量池是方法区的一部分,自然会受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常。 2、虚拟机栈     虚拟机栈是线程私有的内存空间,每个线程都有一个线程栈,每个方法被执行时都会创建一个栈帧,方法执行完成,栈帧弹出,线程运行结束,线程栈被回收。虚拟机栈就是Java中的方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧,这个栈帧用于存储局部变量表、操作数栈、指向当前方法所属的类的运行时常量池的引用、方法返回地址等信息,每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。局部变量表用来存储方法中的局部变量,包括方法中声明的变量以及函数形参。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。局部变量表的大小在编译器就可以确定其大小,并且在程序执行期间局部变量表的大小是不会改变的。程序中的所有计算过程都是在借助于操作数栈来完成的。指向运行时常量池的引用,因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向当前方法所属的类的运行时常量池。方法返回地址,当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。     在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。 3、本地方法栈     本地方法栈也是线程私有的内存空间,本地方法栈与Java栈所发挥的作用是非常相似的,它们之间的区别不过是Java栈执行Java方法,本地方法栈执行的是本地方法,有的虚拟机直接把本地方法栈和虚拟机栈合二为一。 4、堆     Java堆是Java虚拟机所管理的内存中最大的一块,在虚拟机启动时创建,此内存区域的目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。从内存分配的角度来看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区(TLAB)。Java堆可以处于物理上不连续的内存空间,只要逻辑上连续即可,在实现上,既可以实现固定大小的,也可以是扩展的。如果堆中没有足够的内存分配给实例,并且堆也无法再拓展时,将会抛出OutOfMemeryError异常。     堆是运行时动态分配内存,对象在没有引用变量指向它的时候,才变成垃圾,但是仍然占着内存,在程序空闲的时候(没有工作线程运行,GC线程优先级最低)或者堆内存不足的时候(GC线程被触发),被垃圾回收器释放掉,由于要在运行时动态分配内存,存取速度较慢。 5、程序计数器     程序计数器的作用可以看做是当前线程所执行的字节码的行号指示。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为线程私有的内存。如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie方法,这个计数器值则为空。 二、Java内存回收     对于虚拟机栈空间,当方法调用结束后,基本类型变量、引用类型变量、形参占据的空间会被自动释放,但引用类型指向的对象在堆中,堆中的无用内存由垃圾回收线程回收,GC线程优先级最低,只有当没有工作线程存在时GC线程才会执行,或者堆空间不足时会自动触发GC线程工作。除了回收内存,GC线程还负责整理堆中的碎片。 1、四种引用类型     Java中的对象引用分为四种,强引用类型、软引用类型、弱引用类型、虚引用类型。Java中提供这四种引用类型主要有两个目的:第一是可以让程序员通过代码的方式决定某些对象的生命周期;第二是有利于JVM进行垃圾回收。使用软引用和弱引用可以有效的避免oom。软引用关联的对象,只有软引用关联时,才可回收,如果有强引用同时关联,不会回收对象占用的内存,弱引用也如此。 (1)强引用     强引用是使用最普遍的引用,类似Object obj = new Object()、String str = "hello"。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。 (2)软引用(SoftReference)     软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示,如果内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用通常用于网页缓存、图片缓存,防止内存溢出,在内存充足的时候,缓存对象会一直存在,在内存不足的时候,缓存对象占用的内存会被垃圾收集器回收。使用示例: public void testSoftReference() { Map<String,SoftReference<Bitmap>> imagesCache = new HashMap<String,SoftReference<Bitmap>>(); Bitmap bitmap = getBitmap(); SoftReference<Bitmap> image1 = new SoftReference<Bitmap>(bitmap); imagesCache.put("image1",image1); SoftReference<Bitmap> result_SoftReference = imagesCache.get("image1"); Bitmap result_Bitmap = result_SoftReference .get(); } import java.lang.ref.SoftReference; public class Main { public static void main(String[] args) { SoftReference<String> sr = new SoftReference<String>(new String("hello")); System.out.println(sr.get()); } } (3)弱引用(WeakReference)     弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,在java中用java.lang.ref.WeakReference类来表示。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象,不过由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。弱引用可以用于:单例类持有一个activity引用时,会造成内存泄露,把activity声明为弱引用,在activity销毁后,垃圾收集器扫描到activity对象时,会回收activity对象的内存。使用示例: public class SingleTon1 { private static final SingleTon1 mInstance = null; private WeakReference<Context> mContext; private SingleTon1(WeakReference<Context> context) { mContext = context; } public static SingleTon1 getInstance(WeakReference<Context> context) { if (mInstance == null) { synchronized (SingleTon1.class) { if (mInstance == null) { mInstance = new SingleTon1(context); } } } return mInstance; } } public class MyActivity extents Activity { public void onCreate (Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); SingleTon1 singleTon1 = SingleTon1.getInstance(new WeakReference<Context>(this)); } }import java.lang.ref.WeakReference; public class Main { public static void main(String[] args) { WeakReference<String> sr = new WeakReference<String>(new String("hello")); System.out.println(sr.get()); System.gc(); //通知JVM的gc进行垃圾回收 System.out.println(sr.get()); } } 输出结果: hellonull     第二个输出结果是null,这说明只要JVM进行垃圾回收,被弱引用关联的对象必定会被回收掉。不过要注意的是,这里所说的被弱引用关联的对象是指只有弱引用与之关联,如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象(软引用也是如此)。 (4)虚引用     虚引用和软引用、弱引用不同,它并不影响对象的生命周期,也无法通过虚引用来取得一个对象实例,在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列(ReferenceQueue)联合使用,如下: import java.lang.ref.PhantomReference;import java.lang.ref.ReferenceQueue; public class Main { public static void main(String[] args) { ReferenceQueue<String> queue = new ReferenceQueue<String>(); PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue); System.out.println(pr.get()); } } 2、垃圾回收算法 (1)标记-清除(Mark-Sweep)    标记-清除(Mark-Sweep)算法,分为标记和清除两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。 标记-清除算法主要问题是:1、效率问题,标记和清除过程的效率很低2、空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集 (2)复制(Copying)算法     复制算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。 复制算法的主要问题是:1、复制算法将内存缩小为原来的一半,过于浪费2、对象存活率较高时就要执行较多的复制操作,造成频繁GC,效率将会变低 (3)标记-整理(Mark-Compact)     标记-整理算法的标记过程仍然与标记-清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存,这样连续的内存空间就比较多了。     如上图所示,所有存活的对象依次向左上角移动,(0,4)移动到(0,2),(1,0)移动到(0,3),依次类推,当所有的存活对象移动完成后,把剩余的所有空间清空,也就是清空(1,1)后的所有空间。 (4)分代回收(generational collection) 程序创建的大部分对象的生命周期都很短,只有一小部分对象的生命周期比较长,根据这样的规律,一般把Java堆分为Young Generation(新生代),Old Generation(老年代)和Permanent Generation(持久代),上面几种算法是通过分代回收混合在一起的,这样就可以根据各个年代的特点采用最适当的回收算法。 (1)新生代     在新生代中,有一个叫Eden Space的空间,主要是用来存放新生的对象,还有两个Survivor Spaces(from、to), 这两个区域大小相等,相当于copying算法中的两个区域,它们用来存放每次垃圾回收后存活下来的对象。在新生代中,垃圾回收一般用Copying的算法,速度快。     当新建对象无法放入eden区时,将触发minor collection(minorGC 是清理新生代的GC线程,eden的清理,from、to的清理都由MinorGC完成),将eden区与from区的存活对象复制到to区,经过一次垃圾回收,eden区和from区清空,to区中则紧密的存放着存活对象;当eden区再次满时,minor collection将eden区和to区的存活对象复制到from区,eden区和to区被清空,from区存放eden区和to区的存活对象,就这样from区和to区来回切换。如果进行minor collection的时候,发现to区放不下,则将eden区和from区的部分对象放入成熟代。另一方面,即使to区没有满,JVM依然会移动世代足够久远的对象到成熟代。 (2)成熟代     在成熟代中主要存放应用程序中生命周期长的内存对象,垃圾回收一般用mark-compact的算法,速度慢些,但减少内存要求。如果成熟代放满对象,无法从新生代移入新的对象,那么将触发major collection(major GC清理整合OldGen的内存空间)。 (3)永久代    在永久代中,主要用来放JVM自己的反射对象,比如类对象、方法对象、成员变量对象、构造方法对象等。     此外,垃圾回收一般是在程序空闲的时候(没有工作线程,GC线程优先级较低)或者堆内存不足的时候自动触发,也可以调用System.gc()主动的通知Java虚拟机进行垃圾回收,但这只是个建议,Java虚拟机不一定马上执行,启动时机的选择由JVM决定,并且取决于堆内存中Eden区是否可用 作者:喜六六 来源:CSDN 原文:https://blog.csdn.net/qq_29078329/article/details/78929457 版权声明:本文为博主原创文章,转载请附上博文链接!

auto_answer 2019-12-02 01:50:42 0 浏览量 回答数 0

问题

第6篇 指针数组字符串(下)补充:报错

kun坤 2020-06-08 11:02:03 3 浏览量 回答数 1

回答

您可以使用阿里云负载均衡来访问服务。 背景信息 如果您的集群的cloud-controller-manager版本大于等于v1.9.3,对于指定已有SLB,系统默认不再为该SLB处理监听,用户可以通过设置service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners: "true"参数来显示启用监听配置,或者手动配置该SLB的监听规则。 执行以下命令,可查看cloud-controller-manager的版本。 root@master # kubectl get pod -n kube-system -o yaml|grep image:|grep cloud-con|uniq image: registry-vpc.cn-hangzhou.aliyuncs.com/acs/cloud-controller-manager-amd64:v1.9.3 注意事项 Cloud Controller Manager(简称CCM)会为Type=LoadBalancer类型的Service创建或配置阿里云负载均衡(SLB),包含SLB、监听、虚拟服务器组等资源。 对于非LoadBalancer类型的Service则不会为其配置负载均衡,这包含如下场景:当用户将Type=LoadBalancer的Service变更为Type!=LoadBalancer时,CCM也会删除其原先为该Service创建的SLB(用户通过service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id指定的已有SLB除外)。 自动刷新配置 CCM使用声明式API,会在一定条件下自动根据Service的配置刷新阿里云负载均衡配置,所有用户自行在SLB控制台上修改的配置均存在被覆盖的风险(使用已有SLB同时不覆盖监听的场景除外),因此不能在SLB控制台手动修改Kubernetes创建并维护的SLB的任何配置,否则有配置丢失的风险。 同时支持为serivce指定一个已有的负载均衡,或者让CCM自行创建新的负载均衡。但两种方式在SLB的管理方面存在一些差异: 指定已有SLB 仅支持复用负载均衡控制台创建的SLB,不支持复用CCM创建的SLB。 如果您需要在Kubernetes集群中复用私网类型的SLB,则该SLB需要和Kubernetes集群在同一VPC下。 需要为Service设置annotation:service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id 。 SLB配置 此时CCM会使用该SLB做为Service的SLB,并根据其他annotation配置SLB,并且自动的为SLB创建多个虚拟服务器组(当集群节点变化的时候,也会同步更新虚拟服务器组里面的节点)。 监听配置 是否配置监听取决于service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners: 是否设置为true。如果设置为false,CCM不会为SLB管理任何监听配置;如果设置为true,CCM会根据service配置管理监听,如果监听已经存在,则CCM会覆盖已有监听。 SLB的删除 当Service删除时CCM不会删除用户通过id指定的已有SLB。 CCM管理的SLB CCM会根据Service的配置自动的创建配置SLB、监听、虚拟服务器组等资源,所有资源归CCM管理,因此用户不得手动在SLB控制台更改以上资源的配置,否则CCM在下次Reconcile的时候将配置刷回Service所声明的配置,造成非用户预期的结果。 SLB的删除 当Service删除时CCM会删除该SLB。 后端服务器更新 CCM会自动的为该Service对应的SLB刷新后端虚拟服务器组。当Service对应的后端Endpoint发生变化的时候或者集群节点变化的时候都会自动的更新SLB的后端Server。 spec.externalTrafficPolicy = Cluster模式的Service,CCM默认会将所有节点挂载到SLB的后端(使用BackendLabel标签配置后端的除外)。由于SLB限制了每个ECS上能够attach的SLB的个数(quota),因此这种方式会快速的消耗该quota,当quota耗尽后,会造成Service Reconcile失败。解决的办法,可以使用Local模式的Service。 spec.externalTrafficPolicy = Local模式的Service,CCM默认只会将Service对应的Pod所在的节点加入到SLB后端。这会明显降低quota的消耗速度。同时支持四层源IP保留。 任何情况下CCM不会将Master节点作为SLB的后端。 CCM默认不会从SLB后端移除被kubectl drain/cordon的节点。如需移除节点,请设置service.beta.kubernetes.io/alibaba-cloud-loadbalancer-remove-unscheduled-backend为on。 说明 如果是v1.9.3.164-g2105d2e-aliyun之前的版本,CCM默认会从SLB后端移除被kubectl drain/cordon的节点。 VPC路由 集群中一个节点对应一条路由表项,VPC默认情况下仅支持48条路由表项,如果集群节点数目多于48个,请提工单给VPC产品。 说明 您可以在提交工单时,说明需要修改vpc_quota_route_entrys_num参数,用于提升单个路由表可创建的自定义路由条目的数量。 更多VPC使用限制请参见使用限制。 专有网络VPC配额查询请参见专有网络VPC配额管理。 SLB使用限制 CCM会为Type=LoadBalancer类型的Service创建SLB。默认情况下一个用户可以保留60个SLB实例,如果需要创建的SLB数量大于60,请提交工单给SLB产品。 说明 您可以在提交工单时,说明需要修改slb_quota_instances_num参数,用于提高用户可保有的slb实例个数。 CCM会根据Service将ECS挂载到SLB后端服务器组中。 默认情况下一个ECS实例可挂载的后端服务器组的数量为50个,如果一台ECS需要挂载到更多的后端服务器组中,请提交工单给SLB产品。 说明 您可以在提交工单时,说明需要修改slb_quota_backendservers_num参数,用于提高同一台服务器可以重复添加为SLB后端服务器的次数。 默认情况下一个SLB实例可以挂载200个后端服务器,如果需要挂载更多的后端服务器,请提交工单给SLB产品。 说明 您可以在提交工单时,说明需要修改slb_quota_backendservers_num参数,提高每个SLB实例可以挂载的服务器数量。 CCM会根据Service中定义的端口创建SLB监听。默认情况下一个SLB实例可以添加50个监听,如需添加更多监听,请提交工单给SLB产品。 说明 您可以在提交工单时,说明需要修改slb_quota_listeners_num参数,用于提高每个实例可以保有的监听数量。 更多SLB使用限制请参见使用限制。 负载均衡SLB配额查询请参见负载均衡SLB配额管理。 通过命令行操作 方法一: 通过命令行工具创建一个Nginx应用。 root@master # kubectl run nginx --image=registry.aliyuncs.com/acs/netdia:latest root@master # kubectl get po NAME READY STATUS RESTARTS AGE nginx-2721357637-dvwq3 1/1 Running 1 6s 为Nginx应用创建阿里云负载均衡服务,指定 type=LoadBalancer 来向外网用户暴露Nginx服务。 root@master # kubectl expose deployment nginx --port=80 --target-port=80 --type=LoadBalancer root@master # kubectl get svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx 172.19.XX.XX 101.37.XX.XX 80:31891/TCP 4s 在浏览器中访问 http://101.37.XX.XX,来访问您的Nginx服务。 方法二: 将下面的yml code保存到 nginx-svc.yml文件中。 apiVersion: v1 kind: Service metadata: labels: run: nignx name: nginx-01 namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 执行如下命令,创建一个Nginx应用。 kubectl apply -f nginx-svc.yml 执行如下命令,向外网用户暴露Nginx服务。 root@master # kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE9d ngi-01nx LoadBalancer 172.19.XX.XX 101.37.XX.XX 80:32325/TCP 3h 在浏览器中访问 http://101.37.XX.XX,来访问您的Nginx服务。 通过 Kubernetes Dashboard 操作 将下面的yml code保存到 nginx-svc.yml文件中。 apiVersion: v1 kind: Service metadata: labels: run: nginx name: http-svc namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 登录容器服务管理控制台,单击目标集群右侧的控制台,进入Kubernetes Dashboard页面。 单击创建,开始创建应用。 创建应用 单击使用文件创建。选择刚才保存的nginx-svc.yml 文件。 单击上传。 此时,会创建一个阿里云负载均衡实例指向创建的Nginx应用,服务的名称为 http-svc。 在Kubernetes Dashboard上定位到default命名空间,选择服务。 可以看到刚刚创建的 http-svc 的Nginx服务和机器的负载均衡地址 http://114.55.XX.XX:80。 访问服务 将该地址拷贝到浏览器中即可访问该服务。 通过控制台操作 登录容器服务管理控制台。 在 Kubernetes 菜单下,单击左侧导航栏中的应用 > 无状态,进入无状态(Deployment)页面。 选择目标集群和命名空间,单击右上角使用模板创建。 创建应用 示例模板选为自定义,将以下内容复制到模板中。 apiVersion: v1 kind: Service metadata: labels: run: nginx name: ngnix namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 单击创建。 创建成功,单击Kubernetes 控制台前往控制台查看创建进度。 Kubernetes 控制台 或单击左侧导航栏路由与负载均衡 > 服务,选择目标集群和命名空间,查看已部署的服务。 部署服务 更多信息 阿里云负载均衡还支持丰富的配置参数,包含健康检查、收费类型、负载均衡类型等参数。 注释 阿里云可以通过注释annotations的形式支持丰富的负载均衡功能。 创建一个公网类型的负载均衡 apiVersion: v1 kind: Service metadata: name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 创建一个私网类型的负载均衡 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet" name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 创建HTTP类型的负载均衡 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-protocol-port: "http:80" name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 创建HTTPS类型的负载均衡 需要先在阿里云控制台上创建一个证书并记录cert-id,然后使用如下annotation创建一个 HTTPS 类型的SLB。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-protocol-port: "https:443" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-cert-id: "${YOUR_CERT_ID}" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 限制负载均衡的带宽 只限制负载均衡实例下的总带宽,所有监听共享实例的总带宽,参见共享实例带宽。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-charge-type: "paybybandwidth" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-bandwidth: "100" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 指定负载均衡规格 负载均衡规格可参见CreateLoadBalancer。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: "slb.s1.small" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 使用已有的负载均衡 默认情况下,使用已有的负载均衡实例,不会覆盖监听,如要强制覆盖已有监听,请配置service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners为true。 说明 复用已有的负载均衡默认不覆盖已有监听,因为以下两点原因: 如果已有负载均衡的监听上绑定了业务,强制覆盖可能会引发业务中断。 由于CCM目前支持的后端配置有限,无法处理一些复杂配置。如果有复杂的后端配置需求,可以在不覆盖监听的情况下,通过控制台自行配置监听。 如存在以上两种情况不建议强制覆盖监听,如果已有负载均衡的监听端口不再使用,则可以强制覆盖。 使用已有的负载均衡暂不支持添加额外标签(annotation: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-additional-resource-tags) apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: "${YOUR_LOADBALACER_ID}" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 使用已有的负载均衡,并强制覆盖已有监听 强制覆盖已有监听,如果监听端口冲突,则会删除已有监听。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: "${YOUR_LOADBALACER_ID}" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners: "true" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 使用指定Label的worker节点作为后端服务器 多个Label以逗号分隔。例如"k1=v1,k2=v2"。多个label之间是and的关系。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-backend-label: "failure-domain.beta.kubernetes.io/zone=ap-southeast-5a" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 为TCP类型的负载均衡配置会话保持时间 参数service.beta.kubernetes.io/alibaba-cloud-loadbalancer-persistence-time仅对TCP协议的监听生效。 如果负载均衡实例配置了多个TCP协议的监听端口,则默认将该配置应用到所有TCP协议的监听端口。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-persistence-timeout: "1800" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 为HTTP&HTTPS协议的负载均衡配置会话保持(insert cookie) 仅支持HTTP及HTTPS协议的负载均衡实例。 如果配置了多个HTTP或者HTTPS的监听端口,该会话保持默认应用到所有HTTP和HTTPS监听端口。 配置insert cookie,以下四项annotation必选。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session: "on" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session-type: "insert" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-cookie-timeout: "1800" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-protocol-port: "http:80" name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 为HTTP&HTTPS协议的负载均衡配置会话保持(server cookie) 仅支持HTTP及HTTPS协议的负载均衡实例。 如果配置了多个HTTP或者HTTPS的监听端口,该会话保持默认应用到所有HTTP和HTTPS监听端口。 配置server cookie,以下四项annotation必选。 cookie名称(service.beta.kubernetes.io/alibaba-cloud-loadbalancer-cookie)只能包含字母、数字、‘_’和‘-’。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session: "on" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session-type: "server" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-cookie: "${YOUR_COOKIE}" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-protocol-port: "http:80" name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 创建负载均衡时,指定主备可用区 某些region的负载均衡不支持主备可用区,例如ap-southeast-5。 一旦创建,主备可用区不支持修改。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-master-zoneid: "ap-southeast-5a" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-slave-zoneid: "ap-southeast-5a" name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 使用Pod所在的节点作为后端服务器 默认externalTrafficPolicy为Cluster模式,会将集群中所有节点挂载到后端服务器。Local模式仅将Pod所在节点作为后端服务器。 Local模式需要设置调度策略为加权轮询wrr。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-scheduler: "wrr" name: nginx namespace: default spec: externalTrafficPolicy: Local ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 创建私有网络类型(VPC)的负载均衡 创建私有网络类型的负载均衡,以下两个annotation必选。 私网负载均衡支持专有网络(VPC)和经典网络(Classic),两者区别参见实例概述。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-network-type: "vpc" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 创建按流量付费的负载均衡 仅支持公网类型的负载均衡实例 以下两项annotation必选 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-bandwidth: "45" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-charge-type: "paybybandwidth" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 创建带健康检查的负载均衡 设置TCP类型的健康检查 TCP端口默认开启健康检查,且不支持修改,即service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-flag annotation无效。 设置TCP类型的健康检查,以下所有annotation必选。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-type: "tcp" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-connect-timeout: "8" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-healthy-threshold: "4" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-unhealthy-threshold: "4" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-interval: "3" name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 设置HTTP类型的健康检查 设置HTTP类型的健康检查,以下所有的annotation必选。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-flag: "on" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-type: "http" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-uri: "/test/index.html" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-healthy-threshold: "4" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-unhealthy-threshold: "4" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-timeout: "10" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-interval: "3" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-protocol-port: "http:80" name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 为负载均衡设置调度算法 rr(默认值):轮询,按照访问顺序依次将外部请求依序分发到后端服务器。 wrr:加权轮询,权重值越高的后端服务器,被轮询到的次数(概率)也越高。 wlc:加权最小连接数,除了根据每台后端服务器设定的权重值来进行轮询,同时还考虑后端服务器的实际负载(即连接数)。当权重值相同时,当前连接数越小的后端服务器被轮询到的次数(概率)也越高。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-scheduler: "wlc" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 为负载均衡配置访问控制策略组 需要先在阿里云负载均衡控制台上创建一个负载均衡访问控制策略组,然后记录该访问控制策略组ID(acl-id),然后使用如下annotation创建一个带有访问控制的负载均衡实例。 白名单适合只允许特定IP访问的场景,black黑名单适用于只限制某些特定IP访问的场景。 使用该功能前,请确保CloudControllerManage组件是最新版本。请登录容器服务管理控制台,在左侧导航栏选择集群 > 集群,在集群列表中对需要升级的集群单击更多 > 系统组件升级,在组件列表中找到Cloud Controller Manager,单击升级。系统组建升级 创建带有访问控制的负载均衡,以下三项annotation必选。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-acl-status: "on" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-acl-id: "${YOUR_ACL_ID}" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-acl-type: "white" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 为负载均衡指定虚拟交换机 通过阿里云专有网络控制台查询交换机ID,然后使用如下的annotation为负载均衡实例指定虚拟交换机。 为负载均衡指定虚拟交换机,以下两项annotation必选。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-vswitch-id: "${YOUR_VSWITCH_ID}" name: nginx namespace: default spec: ports: - port: 443 protocol: TCP targetPort: 443 selector: run: nginx type: LoadBalancer 为负载均衡指定转发端口 端口转发是指将http端口的请求转发到https端口上。 设置端口转发需要先在阿里云控制台上创建一个证书并记录cert-id。 如需设置端口转发,以下三项annotation必选。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-protocol-port: "https:443,http:80" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-cert-id: "${YOUR_CERT_ID}" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-forward-port: "80:443" name: nginx namespace: default spec: ports: - name: https port: 443 protocol: TCP targetPort: 443 - name: http port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 为负载均衡添加额外标签 多个tag以逗号分隔,例如"k1=v1,k2=v2"。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-additional-resource-tags: "Key1=Value1,Key2=Value2" name: nginx namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx type: LoadBalancer 移除SLB后端unscheduleable状态的节点 kubectl cordon与kubectl drain命令会将节点置为unscheduleable状态,默认service.beta.kubernetes.io/alibaba-cloud-loadbalancer-remove-unscheduled-backend的取值为off,此时不会将处于unscheduleable状态的节点从SLB的后端服务器组移除。若需要从SLB的后端服务器组移除unscheduleable状态的节点,请将service.beta.kubernetes.io/alibaba-cloud-loadbalancer-remove-unscheduled-backend的的取值设置为on。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-remove-unscheduled-backend: "on" name: nginx spec: externalTrafficPolicy: Local ports: - name: http port: 30080 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer 直接将Pod ENI挂载到SLB后端 支持在Terway 网络模式下,通过annotation:service.beta.kubernetes.io/backend-type:"eni" 将Pod直接挂载到SLB后端,提升网络转发性能。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/backend-type: "eni" name: nginx spec: ports: - name: http port: 30080 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer 创建IPv6类型的负载均衡 集群的kube-proxy代理模式需要是IPVS。 生成的IPv6地址仅可在支持IPv6的环境中访问。 创建后IP类型不可更改。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-ip-version: "ipv6" name: nginx spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer 说明 注释的内容是区分大小写的。 自2019年9月11日起,annotation字段alicloud更新为alibaba-cloud。 例如: 更新前:service.beta.kubernetes.io/alicloud-loadbalancer-id 更新后:service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id 系统将继续兼容alicloud的写法,用户无需做任何修改,敬请注意。 注释 类型 描述 默认值 支持的版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-protocol-port string 多个值之间由逗号分隔,例如:https:443,http:80 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type string 取值可以是internet或者intranet internet v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-slb-network-type string 负载均衡的网络类型,取值可以是classic或者vpc 取值为vpc时,需设置service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type为intranet。 classic v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-charge-type string 取值可以是paybytraffic或者paybybandwidth paybytraffic v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id string 负载均衡实例的 ID。通过 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id指定您已有的SLB,默认情况下,使用已有的负载均衡实例,不会覆盖监听,如要强制覆盖已有监听,请配置service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners为true。 无 v1.9.3.81-gca19cd4-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-backend-label string 通过 label 指定 SLB 后端挂载哪些worker节点。 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec string 负载均衡实例的规格。可参见:CreateLoadBalancer 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-persistence-timeout string 会话保持时间。 仅针对TCP协议的监听,取值:0-3600(秒) 默认情况下,取值为0,会话保持关闭。 可参见:CreateLoadBalancerTCPListener 0 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session string 是否开启会话保持。取值:on | off 说明 仅对HTTP和HTTPS协议的监听生效。 可参见:CreateLoadBalancerHTTPListener和CreateLoadBalancerHTTPSListener off v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session-type string cookie的处理方式。取值: insert:植入Cookie。 server:重写Cookie。 说明 仅对HTTP和HTTPS协议的监听生效。 当service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session取值为on时,该参数必选。 可参见:CreateLoadBalancerHTTPListener和CreateLoadBalancerHTTPSListener 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-cookie-timeout string Cookie超时时间。取值:1-86400(秒) 说明 当service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session为on且service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session-type为insert时,该参数必选。 可参见:CreateLoadBalancerHTTPListener和CreateLoadBalancerHTTPSListener 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-cookie string 服务器上配置的Cookie名称。 长度为1-200个字符,只能包含ASCII英文字母和数字字符,不能包含逗号、分号或空格,也不能以$开头。 说明 当service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session为on且service.beta.kubernetes.io/alibaba-cloud-loadbalancer-sticky-session-type为server时,该参数必选。 可参见:CreateLoadBalancerHTTPListener和CreateLoadBalancerHTTPSListener 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-master-zoneid string 主后端服务器的可用区ID。 无 v1.9.3.10-gfb99107-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-slave-zoneid string 备后端服务器的可用区ID。 无 v1.9.3.10-gfb99107-aliyun及以上版本 externalTrafficPolicy string 哪些节点可以作为后端服务器,取值: Cluster:使用所有后端节点作为后端服务器。 Local:使用Pod所在节点作为后端服务器。 Cluster v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners string 绑定已有负载均衡时,是否强制覆盖该SLB的监听。 false:不覆盖 v1.9.3.81-gca19cd4-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-bandwidth string 负载均衡的带宽,仅适用于公网类型的负载均衡。 50 v1.9.3.10-gfb99107-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-cert-id string 阿里云上的证书ID。您需要先上传证书 无 v1.9.3.164-g2105d2e-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-flag string 取值是on | off TCP监听默认为on且不可更改。 HTTP监听默认为off。 默认为off。TCP 不需要改参数。因为 TCP 默认打开健康检查,用户不可设置。 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-type string 健康检查类型,取值:tcp | http。 可参见:CreateLoadBalancerTCPListener tcp v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-uri string 用于健康检查的URI。 说明 当健康检查类型为TCP模式时,无需配置该参数。 可参见:CreateLoadBalancerTCPListener 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-connect-port string 健康检查使用的端口。取值: -520:默认使用监听配置的后端端口。 1-65535:健康检查的后端服务器的端口。 可参见:CreateLoadBalancerTCPListener 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-healthy-threshold string 健康检查连续成功多少次后,将后端服务器的健康检查状态由fail判定为success。 取值:2-10 可参见:CreateLoadBalancerTCPListener 3 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-unhealthy-threshold string 健康检查连续失败多少次后,将后端服务器的健康检查状态由success判定为fail。取值: 2-10 可参见:CreateLoadBalancerTCPListener 3 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-interval string 健康检查的时间间隔。 取值:1-50(秒) 可参见:CreateLoadBalancerTCPListener 2 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-connect-timeout string 接收来自运行状况检查的响应需要等待的时间,适用于TCP模式。如果后端ECS在指定的时间内没有正确响应,则判定为健康检查失败。 取值:1-300(秒) 说明 如果service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-connect-timeout的值小于service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-interval的值,则service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-connect-timeout无效,超时时间为service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-interval的值。 可参见:CreateLoadBalancerTCPListener 5 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-timeout string 接收来自运行状况检查的响应需要等待的时间,适用于HTTP模式。如果后端ECS在指定的时间内没有正确响应,则判定为健康检查失败。 取值:1-300(秒) 说明 如果 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-timeout的值小于service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-interval的值,则 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-timeout无效,超时时间为 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-interval的值。 可参见:CreateLoadBalancerTCPListener 5 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-domain string 用于健康检查的域名。 $_ip:后端服务器的私网IP。当指定了IP或该参数未指定时,负载均衡会使用各后端服务器的私网IP当做健康检查使用的域名。 domain:域名长度为1-80,只能包含字母、数字、点号(.)和连字符(-)。 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-health-check-httpcode string 健康检查正常的HTTP状态码,多个状态码用逗号(,)分割。取值: http_2xx http_3xx http_4xx http_5xx 默认值为http_2xx。 http_2xx v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-scheduler string 调度算法。取值wrr | wlc| rr。 wrr:权重值越高的后端服务器,被轮询到的次数(概率)也越高。 wlc:除了根据每台后端服务器设定的权重值来进行轮询,同时还考虑后端服务器的实际负载(即连接数)。当权重值相同时,当前连接数越小的后端服务器被轮询到的次数(概率)也越高。 rr:默认取值,按照访问顺序依次将外部请求依序分发到后端服务器。 rr v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-acl-status string 是否开启访问控制功能。取值: on | off off v1.9.3.164-g2105d2e-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-acl-id string 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 无 v1.9.3.164-g2105d2e-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-acl-type string 访问控制类型。 取值:white | black。 white:仅转发来自所选访问控制策略组中设置的IP地址或地址段的请求,白名单适用于应用只允许特定IP访问的场景。设置白名单存在一定业务风险。一旦设名单,就只有白名单中的IP可以访问负载均衡监听。如果开启了白名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。 black: 来自所选访问控制策略组中设置的IP地址或地址段的所有请求都不会转发,黑名单适用于应用只限制某些特定IP访问的场景。如果开启了黑名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。当AclStatus参数的值为on时,该参数必选。 无 v1.9.3.164-g2105d2e-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-vswitch-id string 负载均衡实例所属的VSwitch ID。设置该参数时需同时设置addresstype为intranet。 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-forward-port string 将HTTP请求转发至HTTPS指定端口。取值如80:443 无 v1.9.3.164-g2105d2e-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-additional-resource-tags string 需要添加的Tag列表,多个标签用逗号分隔。例如:"k1=v1,k2=v2" 无 v1.9.3及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-remove-unscheduled-backend string 从slb后端移除SchedulingDisabled Node。取值on | off off v1.9.3.164-g2105d2e-aliyun及以上版本 service.beta.kubernetes.io/backend-type string 支持在Terway eni网络模式下,通过设定改参数为"eni",可将Pod直接挂载到SLB后端,提升网络转发性能。取值:eni。 无 v1.9.3.164-g2105d2e-aliyun及以上版本 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-ip-version string 负载均衡实例的IP版本,取值:ipv4或ipv6 ipv4 v1.9.3.220-g24b1885-aliyun及以上版本

1934890530796658 2020-03-31 15:26:42 0 浏览量 回答数 0

问题

某政务网站性能优化

猫饭先生 2019-12-01 21:25:38 1412 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 阿里云双十一主会场 阿里云双十一新人会场 1024程序员加油包 阿里云双十一拼团会场 场景化解决方案 阿里云双十一直播大厅