范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

云贝教育技术文章内存闩锁分析

  作者:刘晓峰
  原文链接:http://www.tdpub.cn/Blog/detail/id/1304.htmlLatch通用数据结构
  讲解闩锁前我们先讲一个数据结构,也就是散列表(hash table ),下图为拉链法表示的散列表
  这里不用关注散列表如何实现。我们关注其特性 给定key,传入到hash函数,返回value代表其内存地址,所以查询非常快 如果不同的key值,返回相同的内存地址,表示发生了hash碰撞,碰撞的key值存储在上图的链表中 链表的首段挂在一个数组后面,数组里存放的hash函数的value,链表里存放的是key Key的多少决定了数组的大小,如果固定数组大小,新写入一个key,如果发生碰撞,则需要维护链表,插入到链表的尾端。
  讲完这个散列表,跟我们的闩锁有什么关系呢。
  简单回顾一下oracle解析步骤
  1.  加载到共享池 - SQL 源代码被加载到 RAM 中进行解析。("硬"解析步骤)
  2.  语法分析 - Oracle 分析语法以检查拼写错误的 SQL 关键字。
  3.  语义解析 - Oracle 验证字典中的所有表和列名称,并检查您是否有权查看数据。
  4.  查询转换 ——Oracle 将把复杂的 SQL 转换为更简单、等效的形式,并酌情用物化视图替换聚合。在 Oracle 的早期版本中,必须为实体化视图重写设置 query_rewrite=true 参数。
  5.  优化 - Oracle 然后根据您的模式统计信息(或者可能来自 10g 中的动态采样的统计信息)创建一个执行计划。Oracle 在此期间构建成本决策树,选择感知成本最低的路径。
  6.  创建可执行文件 - Oracle 使用本机文件调用构建可执行文件以服务 SQL 查询。
  7.  获取行 - Oracle 然后执行对数据文件的本地调用以检索行并将它们传递回调用程序。
  当载入一条SQL文本的时候,如果库缓存中存在此SQL文本,表示是软解析,跳过上面的步骤1,如果库缓存中不存在,则表示是硬解析。
  上面的步骤涉及到"存在"和"不存在",所以是一个find 问题。此时hash表这个数据结构就有了用武之地。
  上图演化为:
  Library cache:库缓存
  Library cache latch,库缓存闩锁。
  为什么需要这个闩锁呢。其实就是问共享池内存数据为什么需要被保护。也就是为什么内存数据会涉及到DML,如果是只读的,且不修改任何属性,也就不存在问题。
  我们知道共享池用于缓存执行计划,数据字典缓存,SQL结果集和函数缓存,而缓存是有大小的,那些使用次数最少的缓存会从内存中老化退出。也就是针对上图的hash table,链表中的数据会被清除掉,而新的缓存又不断加入进来,所以这个链表会动态变化,修改链表的next值等于next的next的时候(其实是双向链表,所以还有last),如果这时还有会话去访问此链表,那么就会有问题。相当于读的时候,不能写,写的时候不能读。这不就是共享锁和排它锁吗?
  但是Oracle的锁(lock),是用于保护磁盘数据,如果要处理高速内存数据,机制太慢,我们需要一个轻量级的内存锁-闩(lacth),要求获取和释放时间都极短,去保护内存的数据。Lock最主要是需要排队,而latch谁在一个时间片内抢到了就算谁的。
  锁和闩分别对应视图v$lock和v$latch。除此之外我们还有互斥锁,pin锁,DDL锁,自定义锁。我们的hash table的数组上,每一个桶都有一个互斥锁(如果是保护lock的latch,则每个桶上还会有latch锁,比如enqueue hash chains),而pin锁会锁链表上的每一个节点。比如链表节点存储了执行计划,为了防止你正在使用执行计划EXECUTE SQL的时候,系统把此节点从链表删除.
  我们主要关注桶前面的library cache latch锁
  Latch分类
  1. 愿意等待:如果获取不到闩,会话休眠,然后再次尝试。休眠时间称之为latch free wait time。library cache latches主要是愿意等待模式
  2. 立即:如果当前进程获取不到闩,转而获取另一个闩,直到所有闩的都获取失败。 Latch视图分析
  查询v$latch有如下字段
  Addr 地址
  latch# 等于v$latch_children.LATCH#
  level# 级别
  name 闩锁名称
  hash 等于v$latch_children.HASH
  gets 当前进程以愿意等待模式成功获取到闩锁的次数,如果闩自旋了1千次,才最终获取到闩锁,gets+1而不是+1001,
  misses 当前进程以愿意等待模式尝试获取闩锁,当第一次尝试获取就失败了,则missed+1,并开始自旋
  sleeps进程以愿意等待模式尝试获取闩锁,第一次获取失败,然后自旋,几千次循环都没成获取,则开始睡眠,sleeps+1。
  immediate_gets 进程以立即模式获取闩锁,第一次尝试获取就获取成功,则immediate_gets+1
  immediate_misses 立即模式获取失败
  waiters_woken
  waits_holding_latch
  spin_gets 进程以愿意等待模式尝试获取闩锁,首次获取失败,然后开始自旋。如果在自旋里成功获取闩锁,spin_gets+1
  wait_time 进程总等待时间,单位一般为微秒
  参数增加顺序:
  misses-> spin_gets自旋也没获取到-> sleeps
  正常情况misses= spin_gets+sleeps
  获取闩锁的顺序
  1. 成功获取,然后释放
  2. 获取失败->自旋->自旋超过spin_count,开始从CPU调度出去,开始休眠->休眠完毕唤醒,继续获取->(1获取又失败misses+1,->自旋->……睡眠时间上升)->(2成功获取gets+1,然后释放)
  为什么要"自旋"?
  任务调度出CPU又调度回来涉及到上下文切换,而正常情况下闩锁获取释放速度很快,所以我在循环里一直获取,正常情况下循环几次就获取到了,如果循环个几千次,还是获取不到,才开始睡眠。这样平均等待时间比前者(指获取不到就开始睡眠)要快很多。
  进程调度出CPU需要切换上下文,耗时较长,所以循环获取 监测latch: library cache
  因为这个库缓存闩锁比较少见,因此不去分析latch视图了,我们后面详细分析快块缓冲区闩锁现象,下面给出监测方法:这些SQL和会话都是有问题的
  查询等待事件 SELECT sid, serial#, osuser, program   FROM v$session  WHERE sid IN (SELECT blocking_session                  FROM v$session                 WHERE event = "latch: library cache");
  查询高子游标计数和高版本sql SELECT DISTINCT sql_id FROM v$sql_plan WHERE child_number >= 300 SELECT sql_id, version_count, sql_text   FROM v$sqlarea  WHERE version_count > 300;
  查询高绑定变量sql SELECT AVG(bind_count) avg_num_binds   FROM (SELECT sql_id, COUNT(*) bind_count           FROM v$sql_bind_capture          WHERE child_number = 0          GROUP BY sql_id); SELECT *   FROM (SELECT sql_id, COUNT(*) bind_count           FROM v$sql_bind_capture          WHERE child_number = 0          GROUP BY sql_id) HAVING bind_count >=300
  再次讨论latch: cache buffers chains
  分析这个词
  Latch:闩锁
  Cache:缓存,比如从磁盘读入数据,放入缓存,下一次直接读缓存而不是磁盘
  buffers:缓冲区,比如有写缓冲区,写满了之后,再统一将缓冲区写磁盘,
  chains:链
  当我们遇到cache buffers就知道是块缓冲区缓存,而不是库缓存 粒度
  下图是块缓冲区的各个缓冲池示意图
  来源:https://codeantenna.com/a/dBDXzPb3zQ
  我们先接触一个词,granule(粒度),BLOCK是数据库最小I/O单元,那么granule就是共享池最小分配进程的连续虚拟内存单元,也是访问数据的最小工作单元。比如我们的自动内存管理,共享池和块缓冲区的大小会动态调整,那么增减的单元就是granule。查询v$sga_resize_ops可以看到最近的调整结果
  上图可以看到:
  一个缓冲池有多个granule,granule内部分为《缓冲区头部数组》和《缓冲区链》,一个工作集可以跨多个granule。这里《缓冲区头部数组》其实就是我们之前看到的X$BH
  查询粒度大小,我本地是4M select * from v$sgainfo where name="Granule Size";
  查询共享池和块缓冲区大小   SELECT s.component         ,s.current_size / 1024 / 1024 current_size         ,s.granule_size / 1024 / 1024 granule_size     FROM v$sga_dynamic_components s    WHERE s.component in ("DEFAULT buffer cache","shared pool")         COMPONENT CURRENT_SIZE GRANULE_SIZE 1 shared pool 240 4 2 DEFAULT buffer cache 28 4
  可以看到共享池240M,60个粒度,块缓冲区默认池28M,也就是7个粒度
  查询块缓冲区粒度的链表 SELECT ge.grantype       ,ct.component       ,ge.granprev       ,ge.grannum       ,grannext   FROM x$ksmge  ge       ,x$kmgsct ct  WHERE ge.grantype != 6    AND ct.grantype = ge.grantype    and ct.component="DEFAULT buffer cache"     GRANTYPE COMPONENT GRANPREV GRANNUM GRANNEXT 1 9 DEFAULT buffer cache 0 63 64 2 9 DEFAULT buffer cache 63 64 65 3 9 DEFAULT buffer cache 64 65 66 4 9 DEFAULT buffer cache 65 66 67 5 9 DEFAULT buffer cache 66 67 68 6 9 DEFAULT buffer cache 67 68 69 7 9 DEFAULT buffer cache 68 69 0
  GRANNEXT指向下一个粒度的指针,GRANNUM是当前指针,从上图可以看到按顺序排列,所以可以得出结论,我的块缓冲区没有动态调整过,当然因为我启用的是手动SGA内存管理。缓冲池内的所有的GRANULE双向链表串联起来组成大的缓冲池。
  --查询所有内存组件的粒度 SELECT ct.component       ,COUNT(1) * 4   FROM x$ksmge  ge       ,x$kmgsct ct  WHERE 1 = 1    AND ct.grantype = ge.grantype  GROUP BY ct.component
  --查询当前大小 SELECT s.component       ,s.current_size / 1024 / 1024 current_size       ,s.granule_size / 1024 / 1024 granule_size   FROM v$sga_dynamic_components s  WHERE s.component in ("DEFAULT buffer cache","shared pool")
  --查询当前块缓冲区详细信息 select * from v$buffer_pool;
  LRU
  我们的缓冲池里面的缓冲区个数是固定的,缓冲区链由工作集管理,当新的数据进入内存的时候,如何决定哪些缓冲区需要clear,LRU(Least recently used)算法就是最近最少被使用缓冲区应该被老化退出。
  回到我们的工作集   SELECT k.cnum_set --工作集中缓存区数量         ,k.set_latch --cache buffer latch地址         ,k.cnum_repl --缓冲区数量总和         ,k.nxt_repl--最多使用的缓冲区,缓冲区链的热端(链表头部)         ,k.prv_repl--最少使用的缓冲区,缓冲区链的冷端(链表尾部)         ,k.cold_hd --缓冲区头部链表冷热分界点         ,K.NXT_REPLAX--备用链头部,备用链比主链少了刷新脏块,获取和释放pin,所以从备用链获取可老化的缓冲区比主链更快         --一般而言,备用链头部链接在k.prv_repl对应的主链的尾部         ,K.PRV_REPLAX--备用链尾部         ,k.addr--等于x$bh.set_ds 表示此工作集有多少缓冲区     FROM x$kcbwds k;
  我们只关注主链,这个表的每一行就是一个工作集,由链表头部nxt_repl和链表尾部prv_repl决定的链表就是缓冲区头部链表,那么此链表的每一个节点就是代表一个个缓冲区。
  缓冲区头部可以简单理解成缓冲区的指针,所以后面遇到缓冲区还是缓冲区头部,可以理解他们都是指代同一个东西,就是缓冲区。每个缓冲区内部里面有很多block。
  上面的链表就是cache buffer lru chain 链表,每一个缓冲区上有一个TCH接触计数,这个TCH的修改机制比较复杂,这里不详细描述,所以我们简化一下,可以简单看成,链表左边的TCH较高,越往右越低,温度较低的缓冲区是从内存老化的优先选择对象。
  (TCH计算逻辑并不是访问一次就+1,这里不详细讨论,只是大概表达意思)
  而我们下面要讲到的cache buffer chain ,虽然节点还是一样的,都是缓冲区,不过他们能链接到一个链表上完全是因为hash 散列的结果,所以这个cache buffer chain链上的温度排列并不是左边的最高,右边的越低
  Latch锁
  现在我们有了一个LRU链表,决定哪些缓冲区需要老化,但是我们还需要前面讲到的hash table 结构去快速判断是物理读还是逻辑读。回想我们通过索引访问数据的过程,通过where条件对应的索引树,找到叶子节点对应的ROWID,ROWID是文件号,块号,块内行号组成的伪列,所以拿到ROWID就确定了是哪一个块,此次我们需要使用hash table,还是以上图举例
  这里的key值简单等价为块号,传入的桶对应的链表就是缓冲区,也就是上图链表中的矩形节点。我们顺序读,读入一个BLOCK,然后通过散列函数,计算出它应该放入那个桶中,然后按某种规则加入到缓冲区链表中。
  举例:
  现在我们传入磁盘block号,通过hash table得到了桶1,那么接下来应该选择放入桶1的三个缓冲区中的一个,具体选择哪一个就是上一节讲到的LRU链, 现在我们把LRU链也画一下,假设我们有2个工作集
  颜色越淡,表示越冷,因此备选缓冲区是2,我们需要修改缓冲区2的数据,回顾我们的库缓存latch,修改前必须要对其加锁,所以改造一下我们的缓冲区hash链
  我们必须首先获取桶1和桶2对应的latch1,然后再去修改桶1的缓冲区链表,这个latch就是标题的latch:cache buffers chains 既然是我们熟悉的latch锁,回想一下
  Misses,spin_gets,sleeps这些关键词,一旦我们有两个SQL访问的块位于同一个latch管辖的桶内,这两个SQL又都在大量进行buffer gets,他们都会争抢latch锁,最后造成此等待事件。
  此时我们假如获取到了latch1,同时通过LRU链我们选择把数据放在缓冲区2中,先pin住缓冲区2,如果不能pin住,则需要等待,此时触发等待事件 buffer busy wats 成功获取pin之后释放闩锁,再缓存我们的数据(这里都不考虑一致性读情况),然后获取闩锁,解除pin,再解除latch锁,完成访问。(LRU链也发生了更新,所以LRU上也会有LATCH锁去控制,这里不详细讨论)
  重现latch: cache buffers chains
  很多文章讲到这个等待事件,给出的解决方案是解决热点块现象,比如多个会话访问同一个块,不过热点块并不是决定因素,同一个buffer chain上的块+多会话+频繁访问才会出现。而buffer busy wait,才与热点块关系比较紧密。热点块以及块上TCH过高,只是说有可能有关系,我们现在来重现一下。
  首先随便在latch链中找到一行数据(如果oracle能提供函数,传入块信息,返回latch信息,那么我就能自己造测试数据了)   SELECT addr     FROM v$latch_children    WHERE NAME = "cache buffers chains"      AND rownum = 1;
  然后查一下这个buffer header 链上都有哪些块的数据 SELECT e.owner || "." || e.segment_name segment_name       ,e.file_id       ,e.extent_id extent#       ,x.dbablk       ,x.dbablk - e.block_id + 1 block#       ,x.tch       ,l.child#       ,l.gets       ,l.misses       ,l.sleeps       ,l.wait_time / 1000000 / 3600       ,l.latch#       ,l.hash   FROM v$latch_children l       ,x$bh             x       ,dba_extents      e  WHERE 1 = 1    AND l.addr = "000000006BDE6660"    AND e.file_id = x.file#    AND x.hladdr = l.addr    AND x.dbablk BETWEEN e.block_id AND e.block_id + e.blocks - 1  ORDER BY x.tch DESC;
  第一行块号是1,因此简单查询第一行就行(反复执行此SQL你会发现TCH会持续增长) select * from SYS.AQ$_SUBSCRIBER_LWM where rownum=1;
  第二行是一个聚簇,与索引聚簇表有关,第4行是一个索引,这里我们没有函数去查询索引块对应的数据是哪一行,第三行是一个表,因此用第三行对应的表测试。 select * from dba_extents d where d.file_id=1 and d.extent_id=20;
  查询此表分配了128个块
  尝试从block_id 118528开始,找3个块,一直访问此数据,但是并没有增加接触计数 SELECT ROWID       ,dbms_rowid.rowid_block_number(ROWID)   FROM sys.optstat_snapshot$ s  WHERE dbms_rowid.rowid_block_number(ROWID) - 118528 <= 3  AND dbms_rowid.rowid_block_number(ROWID) - 118528 >= 0;
  因此直接按ROWID排序,取前1000行数据 select * from (select  * from sys.optstat_snapshot$ order by rowid ) where rownum<=1000;
  因此改造这两个SQL,期望重现latch锁等待事件
  窗口1: --SELECT userenv("sid") FROM dual;--470   declare  cursor a_cur is  select * from SYS.AQ$_SUBSCRIBER_LWM where rownum=1; begin   for i in 1..1000000 loop      for a_rec in a_cur loop        null;      end loop;   end loop; end;
  窗口2: --SELECT userenv("sid") FROM dual; --467 declare  cursor a_cur is  select * from (select  * from sys.optstat_snapshot$ order by rowid ) where rownum<=1000; begin for i in 1..10000 loop for a_rec in a_cur loop null; end loop; end loop; end;
  执行后查看等待事件表 SELECT * FROM v$session_wait s WHERE s.sid IN (467, 470)
  成功重现latch: cache buffers chains
  查看此p1的值,并不是我们上图取出来的"000000006BDE6660"
  如果我们代入000000006BDA63D0会发现出现的段是其它两个系统段,
  而且按我们期望,取消467的查询,却并不能缓解470上的latch锁现象
  当我反复执行上面的查询时候,我发现接触计数高的是这两个段
  SYS.AQ$_SUBSCRIBER_LWM 和 SYS.C_OBJ# ,只能说这两个对象不能独立访问,因此我们去实际环境中重现此等待事件。
  1.找到一个latch锁,其中包含表数据SELECT l.addr, e.owner || "." || e.segment_name   FROM v$latch_children l, x$bh x, dba_extents e  WHERE 1 = 1    AND e.file_id = x.file#    AND x.hladdr = l.addr    AND x.dbablk BETWEEN e.block_id AND e.block_id + e.blocks - 1    AND e.segment_type = "TABLE"    AND e.tablespace_name <> "SYSTEM"
  2.随便取一个latch,将此latch地址传入 SELECT e.owner || "." || e.segment_name       ,segment_name       ,l.addr       ,e.extent_id extent#       ,x.dbablk       ,x.dbablk - e.block_id + 1 block#       ,x.tch       ,l.child#       ,l.gets       ,l.misses       ,l.sleeps       ,l.wait_time / 1000000 / 3600       ,l.latch#       ,l.hash   FROM v$latch_children l       ,x$bh             x       ,dba_extents      e  WHERE l.addr in ("0000001934656D68")    AND e.file_id = x.file#    AND x.hladdr = l.addr    AND x.dbablk BETWEEN e.block_id AND e.block_id + e.blocks - 1
  SEGMENT_NAM
  DBABLK
  MTL_SYSTEM_ITEMS_B
  3219221
  PO_REQUISITION_LINES_AL   1738115
  3通过块号找到缓存的ROWIDSELECT ROWID ,dbms_rowid.rowid_block_number(ROWID) FROM MTL_SYSTEM_ITEMS_B s WHERE dbms_rowid.rowid_block_number(ROWID) = 3219221; SELECT ROWID ,dbms_rowid.rowid_block_number(ROWID) FROM PO_REQUISITION_LINES_ALL s WHERE dbms_rowid.rowid_block_number(ROWID) =1738115   4.开两个窗口循环取数--2266 DECLARE CURSOR a_cur IS SELECT * FROM po_requisition_lines_all msi WHERE ROWID IN ("AAAdlDAIbAAGoWDAAA", "AAAdlDAIbAAGoWDAAB", "AAAdlDAIbAAGoWDAAD", "AAAdlDAIbAAGoWDAAC", "AAAdlDAIbAAGoWDAAG", "AAAdlDAIbAAGoWDAAF", "AAAdlDAIbAAGoWDAAE", "AAAdlDAIbAAGoWDAAI", "AAAdlDAIbAAGoWDAAH", "AAAdlDAIbAAGoWDAAK", "AAAdlDAIbAAGoWDAAJ", "AAAdlDAIbAAGoWDAAM", "AAAdlDAIbAAGoWDAAL"); BEGIN for i in 1..100000 loop FOR a_rec IN a_cur LOOP NULL; END LOOP; end loop; END; --4045 DECLARE CURSOR a_cur IS SELECT * FROM mtl_system_items_b msi WHERE ROWID IN ("AAQ54NAKNAAMR8VAAA", "AAQ54NAKNAAMR8VAAC", "AAQ54NAKNAAMR8VAAE", "AAQ54NAKNAAMR8VAAG", "AAQ54NAKNAAMR8VAAI", "AAQ54NAKNAAMR8VAAK", "AAQ54NAKNAAMR8VAAM", "AAQ54NAKNAAMR8VAAO"); BEGIN FOR i IN 1 .. 100000 LOOP FOR a_rec IN a_cur LOOP NULL; END LOOP; END LOOP; END;   5.查询等待事件select * from v$session_wait s where s.sid in (4045,2266);   SID   EVENT   P1RAW   2266
  latch: shared pool   60292678
  4045
  latch: shared pool   602922B8   没测试出来块缓冲区上的latch锁,却测试出来 latch: shared pool   共享池闩锁的争用是由于共享池容量不足、未共享 SQL 或数据字典的大量使用,   查询硬解析 select * from V$SESS_TIME_MODEL s where s.SID in (4045,2266) order by value desc;   硬解析花费时间并不严重,所以这个等待事件可能是我第一次装载此SQL,同时绑定变量过多导致,再次重复执行   SID   EVENT   P1   2266
  SQL*Net message from client   1952673792
  4045
  latch free   107898301512
  出现了latch free,这个包括了所有的闩锁现象,如果我们对此会话开启了跟踪,并打开原始trace文件,搜索latch free   搜索此number号 select * from v$latchname l where l.latch#=228 LATCH# NAME DISPLAY_NAME HASH CON_ID 1 228 cache buffers chains cache buffers chains 3563305585 0   就显示为实际的latch锁。   根据我们前面的判断,如果停掉2266会话的查询,而是单独查询4045,则不会出现跟buffer cache有关的闩锁,此时我们重新按12345的步骤测试一下,唯一的区别是不执行2266的查询,等待事件结果如下:   SID   EVENT   P1   2266
  SQL*Net message from client   1952673792
  4045
  SQL*Net message from client   1952673792
  符合我们的预测   如何解决latch锁导致的等待问题   回顾一下它的原理,我们有多个进程正在访问同一个buffer cache chain 上的缓冲区,一个获取到了,另一个就不得不等待。所以核心就是减少额外的buffer gets.   如何减少:   1. 避免循环中重复读取相同的块,而且循环本身速度较快的话,闩锁现象越严重   2. 检查索引效率,避免出现索引全扫描或者大段的索引范围扫描,本不需要扫描额外的buffer,由于糟糕的索引或者执行计划,额外扫描了这些block   3. 避免全表扫描,不过oracle有机制控制,读大表的时候会避免更新TCH,我们期望这些大表不会污染我们的块缓冲区(可以放入回收池),一趟全表扫描并不可怕,因为我们的等待来源于逻辑读,全表扫描第一次全是物理读   如果你不能减小buffer gets,也就是说就是要这么频繁访问,那么第二步就是直接路径读,直接路径读不在赘述   如果你也不能采用直接路径读,那么我们只能从降低争用入手   1. 如果争用发生在同一个块的不同行,尝试使用反向键,防止同时访问同一个块   2. 因为latch散列只与块属性有关,所以你要么分时间段执行这两个SQL,要么增大块缓冲区,并期望能散列到别的latch上。   3. 由2可知,对争用比较严重的段采用create as select ,期望生成新的BLOCK_ID并散列到不同的LATCH上(未测试)

中超最新积分榜三镇继续领跑,海港跌出前三,广州脱离降级区北京时间11月26日,中超第27轮继续开打大连人VS梅州客家。上半场第26分钟,特洛索夫点球命中。下半场第78分钟,廖均健破门第90分钟,商隐绝杀。最终,大连人21击败梅州客家。山小组第二晋级?遭韩国逼平,乌拉圭能否抗衡有C罗压阵的葡萄牙?1950年以前两度获得世界杯冠军的乌拉圭国家队,自二十世纪1950年代迄今一直在世界杯小组赛浮沉,早已不复八九十年前世界足坛霸主的荣光。近年在苏亚雷斯领衔之下,乌拉圭于2018年俄30小伙儿鼻整形,术后82天惊艳所有人!整形经历大公开去年10月,差不多也是这个时候,一位小伙子从海南飞过来,专程找老路给他做鼻整形手术。小伙子很年轻,差不多30岁左右,自述一直很想做鼻子,但也一直在犹豫。鼻整形手术中小伙儿自述鼻整形塌鼻子变美方法这个特征太显老了,怎么救?Hi,姐妹们想问一下,你们觉得五官中哪个对颜值影响最大呢?迷儿耶我去问遍了整个同事,她们大部分选择鼻子!的确,鼻子位于面部中央,存在感最强,鼻子好不好看别人第一眼就瞧得出。偷吃脆脆钻戒市场大变天,开始宠物定制?钻戒被当成是衡量爱情最高尚的信物!见过下面这段文字吗?为了守护真爱,钻戒不卖这十种人犹豫不决的人,不卖权衡利弊的人,不卖心里还有另一个名字的人,不卖未成年的人,不卖一时冲动的人,不机芯万国自产69000系机芯指南!导柱轮版7750机芯万国的新的葡计飞计都换装了最新的69000系列机芯,这一枚机芯其实就是导柱轮版的7750机芯,今天就为大家讲讲这枚万国形状大规模用在入门产品上的自产机芯。2014年万国发布6900故乡的沟(散文)我的家乡没有大江大河,更没有雄伟的高山。它却是中国四大平原人口最多的华北大平原。我家的精准定位是永定河冲积平原的南岸,距离永定河也就二十里地。从我记事起,永定河就是干枯的,号称全国嘴,是别人的路,是自己的谁人背后不说人,谁人背后无人说。人生在世,谁也躲不过受人议论的命运。你做的再好,也有人觉得不好,你做的在对,也有人说你不对。正所谓,一心难称众人意,一味难调众人口。总有些人喜欢评头散文世事薄凉,懂得善待自己作者子墨十一月,站在冬天的风中,感受萧瑟与寒意。冬天的味道,除了冷就是肃穆。苍茫之间,山寒水瘦,枝头叶稀,疏离的时光里,也有点点温柔。那是透过枝条细碎的阳光,斑驳了一地陆离光影,仿杨紫,一手烂牌也得打出王炸没有特别喜欢吃的零食,没有特别喜欢听的歌,却有个特别喜欢的你喜欢她的理由很简单,在她身上可以看到普通的我们如何凭借自己的努力一步一步变得更好,摆脱一些标签,目标明确,知道自己想要什去做这6件事,让自己拉开与同龄人的距离大家好,我是木木雪。不知道大家有没有这样的经历每当心情低落的时候,夜里就会做一些很压抑的梦?我经常会在梦里,梦见自己老是融不进别人的圈子,心里很失落,醒来后这种感觉迟迟未散去。大概
加密货币机构频频申请破产,加密货币将失去意义?2022年对加密行业来说可谓风雨飘摇的一年加密货币价值节节败退,比特币近期一度跌至约1。6万美元,加密货币Luna更是全面崩溃。同时,加密货币机构相继破产,继全球第二大加密货币投资新十条重磅发布,复苏牛行情可期每经记者曾子建每经编辑赵云投基Z世代,Z哥最实在。前期几天,Z哥对市场的态度很明确,就是可以乐观一些,再乐观一些。因为我国走出疫情阴影的预期已经非常明朗,走出疫情之后,最重要的就是机构20城物业费均价2。5元平方米月,呈稳中略升态势新京报讯(记者袁秀丽)12月7日,中指研究院发布的2022年中国物业服务价格指数研究报告报告显示,20城物业服务均价为2。52元平方米月,呈现稳中略升的趋势。2022年12月二十城今年的买房目标完成了吗?2022年最后一个月,今年定下的买房目标完成了吗?对比之前各种暴跌腰斩降价的字眼,明显感觉到,寒冷的12月,楼市却久违刮起了暖风。01政策端利好已经释放11月中旬,金融16条等利好劳动者的星辰凝视高光照不到的黯淡之处范雨素和劳动者的星辰北京皮村文学小组作品集(范雨素郭福来等著,上海人民出版社,2022)。(南方人物周刊图)打工的日子就像坐在老牛拉的车上,漫长而无聊,总是把今天走成昨天。在外出打鼎际得研究报告深耕聚烯烃催化剂,进军新材料展翅腾飞(报告出品方作者国盛证券,杨义韬,孙琦祥,王席鑫)1。鼎际得深耕聚烯烃催化剂,进军新材料展翅腾飞1。1。立足优质客户资源,打造催化剂助剂一站式供应公司是国内稀缺的同时具备聚烯烃催化90岁,陈金英奶奶还完了债把债还掉,是她口中的高频词,放在更长的时间线上,人生无法掌控的东西太多,但羽绒服卖一件少一件,欠条撕一张少一张,这成了她唯一能握在手里的东西。文王双兴编辑金匝图王双兴(除特殊标注外这篇作文全是感情,没有技巧爸爸我要玩亲爱的爸爸你好!爸爸你是个好人,非常疼爱我,可是你一整天把我关在家里,不让我出去玩,还让我不停的写字。因此我非常苦恼。有一次一个暑假的时候,你六点钟的时候就叫我起,让我读拒逆转!浓眉5517,库兹马277,詹姆斯甘当绿叶,两大奇兵崛起北京时间12月5日,NBA常规赛湖人客场挑战奇才,赛前,湖人9胜12负排名西部第13,而奇才11胜12负位居东部第10,此役的最大看点肯定是湖人三巨头能打出怎样的表现,另外再次面对江主席有多强,俄罗斯总统普京公开表示,造诣方面自叹不如江主席是一位学富五车,多才多艺的领导人,他精通英文俄文罗马尼亚文还初通德语和日语。在江主席的国际交往中,与各国领导人交谈是必不可少的环节,他可以与俄罗斯总统普京交谈用俄语,与美国总中国历史名镇歙县徽城镇渔梁村安徽省歙县徽城镇渔梁村渔梁(俗称梁下)古村落位于歙县城南1公里练江北岸,濒临练江,北至徽州路,南至练江北岸,西至白云禅院,东至新安关或紫阳桥。渔梁文化底蕴深厚,文物古迹众多,山水风