SlideShare ist ein Scribd-Unternehmen logo
1 von 41
Downloaden Sie, um offline zu lesen
Redis Analytics

         @JeffSeibert
        CEO, Crashlytics


2      CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
3   CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
4   CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Crashlytics for Mac
Strings
    Lists
    Hashes
    Sets
    Sorted Sets

8                 CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Strings                              Activity Tracking

    Lists
    Hashes                               Event Tracking

    Sets
    Sorted Sets                          Leader boards


9                 CRASHLYTICS CONFIDENTIAL         © 2012. All rights reserved
Active User Tracking




10         CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Active User Tracking




      CREATE TABLE accounts (
        id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
        name varchar(255),
        email varchar(255),
        ...

           last_active_at datetime
      );




11                         CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Active User Tracking




      CREATE TABLE events (
         id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
         type varchar(32),
         account_id int(11),
         happened_at datetime
      );




12                      CRASHLYTICS CONFIDENTIAL    © 2012. All rights reserved
Active User Tracking




     accounts::active

       0       0        0        0               1        0       0                    1


        SETBIT key                offset value                (>= 2.2)           O(1)
      > SETBIT “accounts::active” 4      1
      > SETBIT “accounts::active” 7      1


14                             CRASHLYTICS CONFIDENTIAL           © 2012. All rights reserved
Active User Tracking
     accounts::active::2012-10

       1      1    1      0               1        0   1                    1

     accounts::active::2012-10-22

       0      0    1      0               1        0   0                    1

     accounts::active::2012-10-22-00

       0      0    0      0               1        0   0                    1

15                      CRASHLYTICS CONFIDENTIAL       © 2012. All rights reserved
Active User Tracking

     def record_active(obj, t=Time.now.utc)
       key = "#{obj.class.name.downcase.pluralize}::active::"

       key << t.year.to_s
       key << "-" << '%02d' % t.month
       REDIS.setbit key, obj.id, 1                     # accounts::active::2012-10

       key << "-" << '%02d' % t.day
       REDIS.setbit key, obj.id, 1                     # accounts::active::2012-10-22

       key << "-" << '%02d' % t.hour
       REDIS.setbit key, obj.id, 1                     # accounts::active::2012-10-22-00
     end




16                                    CRASHLYTICS CONFIDENTIAL             © 2012. All rights reserved
Active User Tracking
     ‣   We want to know…
         • How many users were active today? This month?

            BITCOUNT key                                      (>= 2.6)           O(N)
          > BITCOUNT “accounts::active::2012-10-22”
          (integer) 3
          > BITCOUNT “accounts::active::2012-10”
          (integer) 5


         • Was user X active today? This month?
            GETBIT key                            index       (>= 2.2)           O(1)
          > GETBIT “accounts::active::2012-10-22” 6
          (integer) 0
          > GETBIT “accounts::active::2012-10”    6
          (integer) 1


17                                 CRASHLYTICS CONFIDENTIAL       © 2012. All rights reserved
Active User Tracking
     ‣   Graphs and Heatmaps
         • Monthly actives over time?

          > BITCOUNT   “accounts::active::2012-07”
          > BITCOUNT   “accounts::active::2012-08”
          > BITCOUNT   “accounts::active::2012-09”
          > BITCOUNT   “accounts::active::2012-10”
          ...


         • Over time, when was user X active?
          > GETBIT   “accounts::active::2012-10-22”             6
          > GETBIT   “accounts::active::2012-10-21”             6
          > GETBIT   “accounts::active::2012-10-20”             6
          > GETBIT   “accounts::active::2012-10-19”             6
          ...


18                                   CRASHLYTICS CONFIDENTIAL       © 2012. All rights reserved
Active User Tracking
     ‣   Advanced Data-Mining: WAU
         • Computing weekly active users:

               BITOP op destkey srckey [srckeys...]              (>= 2.6)           O(N)
         •   > BITOP OR “accounts::active::2012-W42” 
                 “accounts::active::2012-10-21” 
                 “accounts::active::2012-10-20” 
                 “accounts::active::2012-10-19” 
                 “accounts::active::2012-10-18” 
                 “accounts::active::2012-10-17” 
                 “accounts::active::2012-10-16” 
                 “accounts::active::2012-10-15”
             > BITCOUNT “accounts::active::2012-W42”




19                                    CRASHLYTICS CONFIDENTIAL       © 2012. All rights reserved
Active User Tracking
     ‣   Advanced Data-Mining: Retention
         • What % of users active last week are active this week?

               BITOP op destkey srckey [srckeys...]              (>= 2.6)           O(N)
         •   > BITOP AND “accounts::active::2012-W41+W42” 
                 “accounts::active::2012-W41” 
                 “accounts::active::2012-W42”
             > BITCOUNT “accounts::active::2012-W41”
             > BITCOUNT “accounts::active::2012-W41+W42”




20                                    CRASHLYTICS CONFIDENTIAL       © 2012. All rights reserved
Active User Tracking
     ‣   Advanced Data-Mining: Churn
         • Locate accounts that have been inactive for 3 months

               BITOP op destkey srckey [srckeys...]              (>= 2.6)           O(N)
         •   > BITOP OR “accounts::active::2012-Q3” 
                 “accounts::active::2012-09” 
                 “accounts::active::2012-08” 
                 “accounts::active::2012-07”
             > BITOP NOT “accounts::churned::2012-Q3” 
                 “accounts::active::2012-Q3”
             > BITCOUNT “accounts::churned::2012-Q3”




21                                    CRASHLYTICS CONFIDENTIAL       © 2012. All rights reserved
Active User Tracking

     def record_boolean(obj, topic=:active, t=Time.now.utc)
       key = "#{obj.class.name.downcase.pluralize}::#{topic}::"

       key << t.year.to_s
       key << "-" << '%02d' % t.month
       REDIS.setbit key, obj.id, 1                     # accounts::active::2012-10

       key << "-" << '%02d' % t.day
       REDIS.setbit key, obj.id, 1                     # accounts::active::2012-10-22

       key << "-" << '%02d' % t.hour
       REDIS.setbit key, obj.id, 1                     # accounts::active::2012-10-22-00
     end




22                                    CRASHLYTICS CONFIDENTIAL             © 2012. All rights reserved
Event Tracking




23      CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Event Tracking




     apps::crashes

       0      0      0     0               ?        0   0                    0




24                       CRASHLYTICS CONFIDENTIAL       © 2012. All rights reserved
Event Tracking

     apps::crashes {
       0 => 34,
       1 => 546457,
       2 => 1
     }



       HINCRBY key             field increment           (>= 2.0)           O(1)
     > HINCRBY “apps::crashes” “0”   1
     > HINCRBY “apps::crashes” “2”   1




25                            CRASHLYTICS CONFIDENTIAL       © 2012. All rights reserved
Event Tracking

     app::0::crash::by_day {
       2012-10-22 => 34,
       2012-10-21 => 46,
       2012-10-20 => 29,
       ...
     }



     > HINCRBY “app::0::crash::by_day” “2012-10-22” 1




26                            CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Event Tracking

     def record_event(obj, topic=:crash, specificity=:day, t=Time.now.utc)
       key = "#{obj.class.name.downcase}::#{obj.id}::#{topic}::by_#{specificity}"
       # e.g. app::0::crash::by_day

       field = t.year.to_s
       field << "-" << '%02d' % t.month    # 2012-10
       REDIS.hincrby key, field, 1 if specificity == :month

       field << "-" << '%02d' % t.day      # 2012-10-22
       REDIS.hincrby key, field, 1 if specificity == :day

       field << "-" << '%02d' % t.hour     # 2012-10-22-00
       REDIS.hincrby key, field, 1 if specificity == :hour
     end




27                                 CRASHLYTICS CONFIDENTIAL        © 2012. All rights reserved
Event Tracking
     ‣   We want to…
         • Power a graph of crashes over the last week

            HMGET key                     field1 [...]    (>= 2.0)           O(N)
          > HMGET “app::0::crash::by_day” “2012-10-22” 
                    “2012-10-21” “2012-10-20” “2012-10-19” 
                    “2012-10-18” “2012-10-17” “2012-10-16”
          1) ...


         • “Zoom” the graph to see more detail

         > HMGET “app::0::crash::by_hour” “2012-10-22-00” 
                   “2012-10-22-01” “2012-10-22-02” “2012-10-22-03” 
                   “2012-10-22-04” “2012-10-22-05” “2012-10-22-06” ...
         1) ...



28                                 CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Grouped Event Tracking

      “How often has app X crashed
         on each type of iPad?”




29            CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Grouped Event Tracking

     app::0::crash::iPad1,1 {                      device_models [
       2012-10-22 => 34,                             “iPad1,1”,
       2012-10-21 => 46,                             “iPad2,1”,
       2012-10-20 => 29,                             ...
       ...                                         ]
     }

     app::0::crash::iPad2,1 {
       2012-10-22 => 12,
       2012-10-21 => 17,
       2012-10-20 => 11,
       ...
     }


30                      CRASHLYTICS CONFIDENTIAL           © 2012. All rights reserved
Grouped Event Tracking

     app::0::crash::2012-10-22 {
       ALL => 46,
       iPad1,1 => 34,
       iPad2,1 => 12,
       ...
     }


       HGETALL key                                        (>= 2.0)          O(N)
     > HGETALL “app::0::crash::2012-10-22”
     (multi-bulk)




31                             CRASHLYTICS CONFIDENTIAL        © 2012. All rights reserved
Grouped Event Tracking

     def record_grouped_event(obj, group, topic=:crash, t=Time.now.utc)
       key = "#{obj.class.name.downcase}::#{obj.id}::#{topic}::"

       key = t.year.to_s
       key << "-" << '%02d' % t.month      # app::0::crash::2012-10
       REDIS.hincrby key, group, 1
       REDIS.hincrby key, 'ALL', 1

       field << "-" << '%02d' % t.day      # app::0::crash::2012-10-22
       REDIS.hincrby key, group, 1
       REDIS.hincrby key, 'ALL', 1

       field << "-" << '%02d' % t.hour     # app::0::crash::2012-10-22-00
       REDIS.hincrby key, group, 1
       REDIS.hincrby key, 'ALL', 1
     end




32                                 CRASHLYTICS CONFIDENTIAL           © 2012. All rights reserved
MongoDB
     > Account.first.id
     => BSON::ObjectId('507db04798a3340ada000002')




33                      CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Sequential ID Generation

     sequential_ids::accounts {
       10 5084bfbb98a33406f0000002,
       9 5084bfa798a33406f0000001,
       8 507db04798a3340ada000002,
       ...
     }


       ZADD key                        score member (>= 1.2) O(log(N))
     > ZADD “sequential_ids::accounts” 10    507db04798a3340ada000002
     (integer) 1




34                             CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Sequential ID Generation

     sequential_ids::accounts {
       10 5084bfbb98a33406f0000002,
       9 5084bfa798a33406f0000001,
       8 507db04798a3340ada000002,
       ...
     }


       ZCARD key                                          (>= 1.2) O(1)
     > ZCARD “sequential_ids::accounts”
     (integer) 9

       ZADD key                        score member (>= 1.2) O(log(N))
     > ZADD “sequential_ids::accounts” 10    5084bfbb98a33406f0000002
     (integer) 1



35                             CRASHLYTICS CONFIDENTIAL    © 2012. All rights reserved
Sequential ID Generation

     sequential_ids::accounts {
       10 5084bfbb98a33406f0000002,
       9 5084bfa798a33406f0000001,
       8 507db04798a3340ada000002,
       ...
     }


       ZSCORE key                        member          (>= 1.2) O(1)
     > ZSCORE “sequential_ids::accounts” 5084bfbb98a33406f0000002
     (integer) 10




36                             CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Sequential ID Generation

     def sequential_id(obj)
       key = "sequential_keys::#{obj.class.name.downcase.pluralize}"
       id = obj.id.to_s

       # Lua script to atomically determine the score of an id.
       # If needed, adds it to the set with the next available score.
       # In the general case, O(1). On add, O(log(N)). Requires Redis >= 2.6
       monotonic_zadd = <<LUA
         local sequential_id = redis.call('zscore', KEYS[1], ARGV[1])
         if not sequential_id then
           sequential_id = redis.call('zcard', KEYS[1])
           redis.call('zadd', KEYS[1], sequential_id, ARGV[1])
         end

           return sequential_id
     LUA

       REDIS.eval(monotonic_zadd, [key], [id]).to_i
     end



37                                   CRASHLYTICS CONFIDENTIAL          © 2012. All rights reserved
Redis Analytics Wish List




38           CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Redis Analytics Wish List
     ‣   MSETBIT, MGETBIT, MBITCOUNT, HMINCRBY
         • Can already be addressed with scripting
     ‣ Native support for (insertion-)ordered sets
     ‣ Per-hash-key expiration policies




39                              CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Q&A
       @JeffSeibert
      CEO, Crashlytics



40   CRASHLYTICS CONFIDENTIAL   © 2012. All rights reserved
Scaling Crashlytics: Building Analytics on Redis 2.6

Weitere ähnliche Inhalte

Was ist angesagt?

Simplified Security Code Review Process
Simplified Security Code Review ProcessSimplified Security Code Review Process
Simplified Security Code Review Process
Sherif Koussa
 

Was ist angesagt? (20)

OSGi, Scripting and REST, Building Webapps With Apache Sling
OSGi, Scripting and REST, Building Webapps With Apache SlingOSGi, Scripting and REST, Building Webapps With Apache Sling
OSGi, Scripting and REST, Building Webapps With Apache Sling
 
Redis overview for Software Architecture Forum
Redis overview for Software Architecture ForumRedis overview for Software Architecture Forum
Redis overview for Software Architecture Forum
 
Simplified Security Code Review Process
Simplified Security Code Review ProcessSimplified Security Code Review Process
Simplified Security Code Review Process
 
react redux.pdf
react redux.pdfreact redux.pdf
react redux.pdf
 
Getting Git
Getting GitGetting Git
Getting Git
 
MongoDB Performance Tuning
MongoDB Performance TuningMongoDB Performance Tuning
MongoDB Performance Tuning
 
Improving the performance of Odoo deployments
Improving the performance of Odoo deploymentsImproving the performance of Odoo deployments
Improving the performance of Odoo deployments
 
Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing Strategies
 
React js
React jsReact js
React js
 
Design Pattern Cheatsheet
Design Pattern CheatsheetDesign Pattern Cheatsheet
Design Pattern Cheatsheet
 
Introduction à React
Introduction à ReactIntroduction à React
Introduction à React
 
Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIO
 
React js
React jsReact js
React js
 
Version Control with Git for Beginners
Version Control with Git for BeginnersVersion Control with Git for Beginners
Version Control with Git for Beginners
 
Redux Toolkit & RTK Query in TypeScript: tips&tricks
Redux Toolkit & RTK Query in TypeScript: tips&tricksRedux Toolkit & RTK Query in TypeScript: tips&tricks
Redux Toolkit & RTK Query in TypeScript: tips&tricks
 
Redis Streams for Event-Driven Microservices
Redis Streams for Event-Driven MicroservicesRedis Streams for Event-Driven Microservices
Redis Streams for Event-Driven Microservices
 
An Introduction to REDIS NoSQL database
An Introduction to REDIS NoSQL databaseAn Introduction to REDIS NoSQL database
An Introduction to REDIS NoSQL database
 
Process Automation: an Update from the Trenches
Process Automation: an Update from the TrenchesProcess Automation: an Update from the Trenches
Process Automation: an Update from the Trenches
 
Windows Operating System Archaeology
Windows Operating System ArchaeologyWindows Operating System Archaeology
Windows Operating System Archaeology
 
Nodejs Explained with Examples
Nodejs Explained with ExamplesNodejs Explained with Examples
Nodejs Explained with Examples
 

Andere mochten auch

Kicking ass with redis
Kicking ass with redisKicking ass with redis
Kicking ass with redis
Dvir Volk
 

Andere mochten auch (6)

Kicking ass with redis
Kicking ass with redisKicking ass with redis
Kicking ass with redis
 
Redis in Practice
Redis in PracticeRedis in Practice
Redis in Practice
 
Redis data design by usecase
Redis data design by usecaseRedis data design by usecase
Redis data design by usecase
 
High-Volume Data Collection and Real Time Analytics Using Redis
High-Volume Data Collection and Real Time Analytics Using RedisHigh-Volume Data Collection and Real Time Analytics Using Redis
High-Volume Data Collection and Real Time Analytics Using Redis
 
Redis Use Patterns (DevconTLV June 2014)
Redis Use Patterns (DevconTLV June 2014)Redis Use Patterns (DevconTLV June 2014)
Redis Use Patterns (DevconTLV June 2014)
 
Everything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to askEverything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to ask
 

Ähnlich wie Scaling Crashlytics: Building Analytics on Redis 2.6

Desenvolvimento web com Ruby on Rails (parte 5)
Desenvolvimento web com Ruby on Rails (parte 5)Desenvolvimento web com Ruby on Rails (parte 5)
Desenvolvimento web com Ruby on Rails (parte 5)
Joao Lucas Santana
 
1 24 - user data management
1 24 - user data management1 24 - user data management
1 24 - user data management
MongoDB
 

Ähnlich wie Scaling Crashlytics: Building Analytics on Redis 2.6 (20)

ATT&CK Updates- Defensive ATT&CK
ATT&CK Updates- Defensive ATT&CKATT&CK Updates- Defensive ATT&CK
ATT&CK Updates- Defensive ATT&CK
 
Desenvolvimento web com Ruby on Rails (parte 5)
Desenvolvimento web com Ruby on Rails (parte 5)Desenvolvimento web com Ruby on Rails (parte 5)
Desenvolvimento web com Ruby on Rails (parte 5)
 
1 24 - user data management
1 24 - user data management1 24 - user data management
1 24 - user data management
 
Webinar: User Data Management with MongoDB
Webinar: User Data Management with MongoDBWebinar: User Data Management with MongoDB
Webinar: User Data Management with MongoDB
 
Introducing Stitch
Introducing Stitch Introducing Stitch
Introducing Stitch
 
DevTalks 2021 Cloud Engineering @Crowdstrike
DevTalks 2021 Cloud Engineering @CrowdstrikeDevTalks 2021 Cloud Engineering @Crowdstrike
DevTalks 2021 Cloud Engineering @Crowdstrike
 
Audience Intel presentation 2014
Audience Intel presentation 2014Audience Intel presentation 2014
Audience Intel presentation 2014
 
5 Key Audit Procedures for Rock-Solid Trial Balances
5 Key Audit Procedures for Rock-Solid Trial Balances5 Key Audit Procedures for Rock-Solid Trial Balances
5 Key Audit Procedures for Rock-Solid Trial Balances
 
MongoDB Days UK: No Compromises SQL Connectivity for MongoDB
MongoDB Days UK: No Compromises SQL Connectivity for MongoDBMongoDB Days UK: No Compromises SQL Connectivity for MongoDB
MongoDB Days UK: No Compromises SQL Connectivity for MongoDB
 
Andy lib解説
Andy lib解説Andy lib解説
Andy lib解説
 
PayPal Real Time Analytics
PayPal  Real Time AnalyticsPayPal  Real Time Analytics
PayPal Real Time Analytics
 
IOOF IT System Modernisation
IOOF IT System ModernisationIOOF IT System Modernisation
IOOF IT System Modernisation
 
Google Analytics blog support
Google Analytics blog supportGoogle Analytics blog support
Google Analytics blog support
 
Build 2017 - P4152 - Microsoft Graph - Delta Query and Webhooks
Build 2017 - P4152 - Microsoft Graph - Delta Query and WebhooksBuild 2017 - P4152 - Microsoft Graph - Delta Query and Webhooks
Build 2017 - P4152 - Microsoft Graph - Delta Query and Webhooks
 
Building Applications with DynamoDB
Building Applications with DynamoDBBuilding Applications with DynamoDB
Building Applications with DynamoDB
 
Nyss Open legislation
Nyss Open legislationNyss Open legislation
Nyss Open legislation
 
Webinar: User Data Management with MongoDB
Webinar: User Data Management with MongoDBWebinar: User Data Management with MongoDB
Webinar: User Data Management with MongoDB
 
The database is half done
The database is half doneThe database is half done
The database is half done
 
Ivanti for msp
Ivanti for mspIvanti for msp
Ivanti for msp
 
Uncover the Root Cause of Kafka Performance Anomalies, Daniel Kim & Antón Rod...
Uncover the Root Cause of Kafka Performance Anomalies, Daniel Kim & Antón Rod...Uncover the Root Cause of Kafka Performance Anomalies, Daniel Kim & Antón Rod...
Uncover the Root Cause of Kafka Performance Anomalies, Daniel Kim & Antón Rod...
 

Kürzlich hochgeladen

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Kürzlich hochgeladen (20)

Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 

Scaling Crashlytics: Building Analytics on Redis 2.6

  • 1.
  • 2. Redis Analytics @JeffSeibert CEO, Crashlytics 2 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 3. 3 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 4. 4 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 5.
  • 7.
  • 8. Strings Lists Hashes Sets Sorted Sets 8 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 9. Strings Activity Tracking Lists Hashes Event Tracking Sets Sorted Sets Leader boards 9 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 10. Active User Tracking 10 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 11. Active User Tracking CREATE TABLE accounts ( id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, name varchar(255), email varchar(255), ... last_active_at datetime ); 11 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 12. Active User Tracking CREATE TABLE events ( id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, type varchar(32), account_id int(11), happened_at datetime ); 12 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 13.
  • 14. Active User Tracking accounts::active 0 0 0 0 1 0 0 1 SETBIT key offset value (>= 2.2) O(1) > SETBIT “accounts::active” 4 1 > SETBIT “accounts::active” 7 1 14 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 15. Active User Tracking accounts::active::2012-10 1 1 1 0 1 0 1 1 accounts::active::2012-10-22 0 0 1 0 1 0 0 1 accounts::active::2012-10-22-00 0 0 0 0 1 0 0 1 15 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 16. Active User Tracking def record_active(obj, t=Time.now.utc) key = "#{obj.class.name.downcase.pluralize}::active::" key << t.year.to_s key << "-" << '%02d' % t.month REDIS.setbit key, obj.id, 1 # accounts::active::2012-10 key << "-" << '%02d' % t.day REDIS.setbit key, obj.id, 1 # accounts::active::2012-10-22 key << "-" << '%02d' % t.hour REDIS.setbit key, obj.id, 1 # accounts::active::2012-10-22-00 end 16 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 17. Active User Tracking ‣ We want to know… • How many users were active today? This month? BITCOUNT key (>= 2.6) O(N) > BITCOUNT “accounts::active::2012-10-22” (integer) 3 > BITCOUNT “accounts::active::2012-10” (integer) 5 • Was user X active today? This month? GETBIT key index (>= 2.2) O(1) > GETBIT “accounts::active::2012-10-22” 6 (integer) 0 > GETBIT “accounts::active::2012-10” 6 (integer) 1 17 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 18. Active User Tracking ‣ Graphs and Heatmaps • Monthly actives over time? > BITCOUNT “accounts::active::2012-07” > BITCOUNT “accounts::active::2012-08” > BITCOUNT “accounts::active::2012-09” > BITCOUNT “accounts::active::2012-10” ... • Over time, when was user X active? > GETBIT “accounts::active::2012-10-22” 6 > GETBIT “accounts::active::2012-10-21” 6 > GETBIT “accounts::active::2012-10-20” 6 > GETBIT “accounts::active::2012-10-19” 6 ... 18 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 19. Active User Tracking ‣ Advanced Data-Mining: WAU • Computing weekly active users: BITOP op destkey srckey [srckeys...] (>= 2.6) O(N) • > BITOP OR “accounts::active::2012-W42” “accounts::active::2012-10-21” “accounts::active::2012-10-20” “accounts::active::2012-10-19” “accounts::active::2012-10-18” “accounts::active::2012-10-17” “accounts::active::2012-10-16” “accounts::active::2012-10-15” > BITCOUNT “accounts::active::2012-W42” 19 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 20. Active User Tracking ‣ Advanced Data-Mining: Retention • What % of users active last week are active this week? BITOP op destkey srckey [srckeys...] (>= 2.6) O(N) • > BITOP AND “accounts::active::2012-W41+W42” “accounts::active::2012-W41” “accounts::active::2012-W42” > BITCOUNT “accounts::active::2012-W41” > BITCOUNT “accounts::active::2012-W41+W42” 20 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 21. Active User Tracking ‣ Advanced Data-Mining: Churn • Locate accounts that have been inactive for 3 months BITOP op destkey srckey [srckeys...] (>= 2.6) O(N) • > BITOP OR “accounts::active::2012-Q3” “accounts::active::2012-09” “accounts::active::2012-08” “accounts::active::2012-07” > BITOP NOT “accounts::churned::2012-Q3” “accounts::active::2012-Q3” > BITCOUNT “accounts::churned::2012-Q3” 21 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 22. Active User Tracking def record_boolean(obj, topic=:active, t=Time.now.utc) key = "#{obj.class.name.downcase.pluralize}::#{topic}::" key << t.year.to_s key << "-" << '%02d' % t.month REDIS.setbit key, obj.id, 1 # accounts::active::2012-10 key << "-" << '%02d' % t.day REDIS.setbit key, obj.id, 1 # accounts::active::2012-10-22 key << "-" << '%02d' % t.hour REDIS.setbit key, obj.id, 1 # accounts::active::2012-10-22-00 end 22 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 23. Event Tracking 23 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 24. Event Tracking apps::crashes 0 0 0 0 ? 0 0 0 24 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 25. Event Tracking apps::crashes { 0 => 34, 1 => 546457, 2 => 1 } HINCRBY key field increment (>= 2.0) O(1) > HINCRBY “apps::crashes” “0” 1 > HINCRBY “apps::crashes” “2” 1 25 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 26. Event Tracking app::0::crash::by_day { 2012-10-22 => 34, 2012-10-21 => 46, 2012-10-20 => 29, ... } > HINCRBY “app::0::crash::by_day” “2012-10-22” 1 26 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 27. Event Tracking def record_event(obj, topic=:crash, specificity=:day, t=Time.now.utc) key = "#{obj.class.name.downcase}::#{obj.id}::#{topic}::by_#{specificity}" # e.g. app::0::crash::by_day field = t.year.to_s field << "-" << '%02d' % t.month # 2012-10 REDIS.hincrby key, field, 1 if specificity == :month field << "-" << '%02d' % t.day # 2012-10-22 REDIS.hincrby key, field, 1 if specificity == :day field << "-" << '%02d' % t.hour # 2012-10-22-00 REDIS.hincrby key, field, 1 if specificity == :hour end 27 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 28. Event Tracking ‣ We want to… • Power a graph of crashes over the last week HMGET key field1 [...] (>= 2.0) O(N) > HMGET “app::0::crash::by_day” “2012-10-22” “2012-10-21” “2012-10-20” “2012-10-19” “2012-10-18” “2012-10-17” “2012-10-16” 1) ... • “Zoom” the graph to see more detail > HMGET “app::0::crash::by_hour” “2012-10-22-00” “2012-10-22-01” “2012-10-22-02” “2012-10-22-03” “2012-10-22-04” “2012-10-22-05” “2012-10-22-06” ... 1) ... 28 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 29. Grouped Event Tracking “How often has app X crashed on each type of iPad?” 29 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 30. Grouped Event Tracking app::0::crash::iPad1,1 { device_models [ 2012-10-22 => 34, “iPad1,1”, 2012-10-21 => 46, “iPad2,1”, 2012-10-20 => 29, ... ... ] } app::0::crash::iPad2,1 { 2012-10-22 => 12, 2012-10-21 => 17, 2012-10-20 => 11, ... } 30 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 31. Grouped Event Tracking app::0::crash::2012-10-22 { ALL => 46, iPad1,1 => 34, iPad2,1 => 12, ... } HGETALL key (>= 2.0) O(N) > HGETALL “app::0::crash::2012-10-22” (multi-bulk) 31 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 32. Grouped Event Tracking def record_grouped_event(obj, group, topic=:crash, t=Time.now.utc) key = "#{obj.class.name.downcase}::#{obj.id}::#{topic}::" key = t.year.to_s key << "-" << '%02d' % t.month # app::0::crash::2012-10 REDIS.hincrby key, group, 1 REDIS.hincrby key, 'ALL', 1 field << "-" << '%02d' % t.day # app::0::crash::2012-10-22 REDIS.hincrby key, group, 1 REDIS.hincrby key, 'ALL', 1 field << "-" << '%02d' % t.hour # app::0::crash::2012-10-22-00 REDIS.hincrby key, group, 1 REDIS.hincrby key, 'ALL', 1 end 32 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 33. MongoDB > Account.first.id => BSON::ObjectId('507db04798a3340ada000002') 33 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 34. Sequential ID Generation sequential_ids::accounts { 10 5084bfbb98a33406f0000002, 9 5084bfa798a33406f0000001, 8 507db04798a3340ada000002, ... } ZADD key score member (>= 1.2) O(log(N)) > ZADD “sequential_ids::accounts” 10 507db04798a3340ada000002 (integer) 1 34 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 35. Sequential ID Generation sequential_ids::accounts { 10 5084bfbb98a33406f0000002, 9 5084bfa798a33406f0000001, 8 507db04798a3340ada000002, ... } ZCARD key (>= 1.2) O(1) > ZCARD “sequential_ids::accounts” (integer) 9 ZADD key score member (>= 1.2) O(log(N)) > ZADD “sequential_ids::accounts” 10 5084bfbb98a33406f0000002 (integer) 1 35 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 36. Sequential ID Generation sequential_ids::accounts { 10 5084bfbb98a33406f0000002, 9 5084bfa798a33406f0000001, 8 507db04798a3340ada000002, ... } ZSCORE key member (>= 1.2) O(1) > ZSCORE “sequential_ids::accounts” 5084bfbb98a33406f0000002 (integer) 10 36 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 37. Sequential ID Generation def sequential_id(obj) key = "sequential_keys::#{obj.class.name.downcase.pluralize}" id = obj.id.to_s # Lua script to atomically determine the score of an id. # If needed, adds it to the set with the next available score. # In the general case, O(1). On add, O(log(N)). Requires Redis >= 2.6 monotonic_zadd = <<LUA local sequential_id = redis.call('zscore', KEYS[1], ARGV[1]) if not sequential_id then sequential_id = redis.call('zcard', KEYS[1]) redis.call('zadd', KEYS[1], sequential_id, ARGV[1]) end return sequential_id LUA REDIS.eval(monotonic_zadd, [key], [id]).to_i end 37 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 38. Redis Analytics Wish List 38 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 39. Redis Analytics Wish List ‣ MSETBIT, MGETBIT, MBITCOUNT, HMINCRBY • Can already be addressed with scripting ‣ Native support for (insertion-)ordered sets ‣ Per-hash-key expiration policies 39 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved
  • 40. Q&A @JeffSeibert CEO, Crashlytics 40 CRASHLYTICS CONFIDENTIAL © 2012. All rights reserved