Application Object Replacement

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Google Mike

    Application Object Replacement

    I need an Application object replacement. I was creating my own using
    shared memory -- shm* API in PHP. I was doing fine for 6 months until
    it just got too fat, I guess, and the RH9 Linux server just started
    "losing its memory". I don't know -- perhaps I'm doing something
    wrong, perhaps it's my code, or perhaps there's a limitation on what
    I'm trying to do here. It's too many lines of code to debug right now.
    I'm searching for alternatives.

    The reason I was using this was because it sped up things so that
    instead of a database hit, my pages hit server memory for small things
    like caching reference tables that translate usernames to email
    addresses, group codes to group descriptions, and so on.

    Of course it's a dangerous thing to use an Application object in a
    server farm, so what I do is I refresh it on every server upon user
    login to the website. It hits the database and pulls the latest data
    to populate that server's Application object. If I update a reference
    table, I also have a script that refreshes this on every server. So,
    there's like a 99.9999% chance that everyone's going to have the
    latest Application object data.

    ....that is, until it got too fat, I guess.

    Anyway, does anyone have any ideas on how to use a different technique
    like environment variables; a socket service that caches the array to
    RAM after reading it from a database every 15 minutes; or other
    technique?

    I could store the entries in a file, but the point is that I don't
    want disk access here -- I want it in RAM.

    My Linux server has 1GB of RAM. I calculated the shared memory stuff
    I'm storing there and it's no more than 20MB.
  • Colin McKinnon

    #2
    Re: Application Object Replacement

    Google Mike wrote:[color=blue]
    >
    > Anyway, does anyone have any ideas on how to use a different technique
    > like environment variables; a socket service that caches the array to
    > RAM after reading it from a database every 15 minutes; or other
    > technique?
    >
    > I could store the entries in a file, but the point is that I don't
    > want disk access here -- I want it in RAM.
    >
    > My Linux server has 1GB of RAM. I calculated the shared memory stuff
    > I'm storing there and it's no more than 20MB.
    >[/color]

    Linux, indeed most forms of *nix are phenomonally good at cacheing file i/o
    therefore if you store the stuff in files it will most likely be available
    from 'RAM'. Indeed this is likely to be even faster than running a DBMS off
    a ramdisk. The only time I would even consider using shm is when I need
    manage near concurrent access to data which is rapidly changing - and I
    guess that is not the situation here.

    Try it.

    You can virtually eliminate file i/o by switching off atime on the relevant
    filesystem.

    Or of course you could put the files in a ramdisk, but there's not a lot of
    a performance gain there.

    HTH

    C.

    Comment

    • Drazen Gemic

      #3
      Re: Application Object Replacement

      > Linux, indeed most forms of *nix are phenomonally good at cacheing file i/o[color=blue]
      > therefore if you store the stuff in files it will most likely be available
      > from 'RAM'. Indeed this is likely to be even faster than running a DBMS off
      > a ramdisk. The only time I would even consider using shm is when I need[/color]

      It is not true when disk activity is high. Cache content might get
      replaced very often in such situation.

      Anyway, it is not wise to rely on application object in a server farm.

      DG

      Comment

      • Google Mike

        #4
        Re: Application Object Replacement

        Colin McKinnon <colin.deleteth is@andthis.mms3 .com> wrote in message[color=blue]
        > Google Mike wrote:[color=green]
        > >
        > > Anyway, does anyone have any ideas on how to use a different technique
        > > like environment variables; a socket service that caches the array to
        > > RAM after reading it from a database every 15 minutes; or other
        > > technique?
        > >
        > > I could store the entries in a file, but the point is that I don't
        > > want disk access here -- I want it in RAM.
        > >
        > > My Linux server has 1GB of RAM. I calculated the shared memory stuff
        > > I'm storing there and it's no more than 20MB.
        > >[/color]
        >
        > Linux, indeed most forms of *nix are phenomonally good at cacheing file i/o
        > therefore if you store the stuff in files it will most likely be available
        > from 'RAM'. Indeed this is likely to be even faster than running a DBMS off
        > a ramdisk. The only time I would even consider using shm is when I need
        > manage near concurrent access to data which is rapidly changing - and I
        > guess that is not the situation here.
        >
        > Try it.
        >
        > You can virtually eliminate file i/o by switching off atime on the relevant
        > filesystem.
        >
        > Or of course you could put the files in a ramdisk, but there's not a lot of
        > a performance gain there.
        >
        > HTH
        >
        > C.[/color]

        Hmm. Didn't think of that. Sounds like you're on to something.

        What about creating another filesystem with a portion of my Linux's
        existing (ext3) file system? Is that possible? If so, could I then
        apply the switch on that second file system to turn off anything that
        might slow it down? Can I make it a faster file system instead of
        ext3? If so, then I could do reads from this second, super-fast
        filesystem and perhaps get the kind of speed I need? What do you
        think?

        Comment

        • Google Mike

          #5
          Re: Application Object Replacement

          Because I was having upper limit memory limitations in Shared Memory
          API on RH9 Linux, I found a better option for Linux than Shared Memory
          API in PHP:

          mkdir /mnt/tmpfs
          mount -t tmpfs -o,mode=770 tmpfs /mnt/tmpfs
          touch /mnt/tmpfs/application_obj ect.db

          ....and now, if I create the application_obj ect.db as a key=value pair
          file (like an INI file), I can read and write to it in PHP extremely
          fast because this uses Linux virtual memory. Linux virtual memory is
          pretty much like virtual memory on most operating systems -- you use
          RAM to a certain extent and then you start swapping out storage to
          blocks in a swapfile on the hard drive. In the command above, it has
          the capacity to store almost up to all your RAM space and almost all
          your swap disk space if you want it to. And, when you reboot, this
          goes away.

          The tmpfs filesystem is sort of like a ramdisk, but instead of being
          limited by RAM, you go beyond that into available disk space on the
          swapfile filesystem where you mount this. And, it's not like reading
          and writing to the disk -- you're reading and writing to a cache
          that's swapped out in RAM, giving you a lot more speed than normal
          disk I/O.

          The other advantage of using this technique besides the Shared Memory
          API is that I can actually use command line to "cat" files out and see
          what's in them, checking for problems I might have created in code. If
          my file is corrupt, I'll be able to see it. If you have a corrupt
          Shared Memory section, you can't "cat" it (that I know of) to see
          what's going on. Here's another advantage over Microsoft's IIS Server
          Application Object -- you can't physically inspect that object, but
          here, with tmpfs on Linux, you can.

          If you use this technique, then you need to probably do the following.
          On computer bootup, say in a Bash script like at the bottom of
          rc.sysinit, you have to recreate your tmpfs space, read those
          reference tables from your database that you want to cache to optimize
          your web application, and write these entries into
          /mnt/tmpfs/application_obj ect.db as key=value pairs. Then, when you
          want to read these values from your PHP pages, you just do normal file
          API against application_obj ect.db. And, you can probably abstract that
          code into your very own Application object class file in PHP.

          However, be careful about implementing this in a web farm because each
          server has its own exclusive memory. To get around that limitation,
          you might want to consider first whether it's better to just read from
          the database and optimize some settings on it instead of using an
          Application object there. However, if you do wish to go ahead and try
          it, here's some extra steps that might work in some cases for you:

          1. Upon every user's login to your website, such as in a file like
          login2.php, refresh the /mnt/tmpfs/application_obj ect.db file from the
          database upon the next moment your web server sees that this is not
          being read from or written against. (I would recommend this, anyway,
          even in a standalone web server environment.)

          2. If you administer the reference files in your database that you
          were trying to cache, then you need to create a Bash script that you
          can call to tell all your web farm servers to refresh their
          application_obj ect.db objects from the central database the next
          moment the web server is idle.

          Comment

          • Google Mike

            #6
            Re: Application Object Replacement

            An even better step on the road to replacing a custom Application
            Object class in Linux-based PHP, getting away from Shared Memory API
            (shm*), is to use tmpfs and read/write to that as I mentioned
            yesterday in this group. I found a neat way to autoload this and have
            a way to restart the service when you need to do so. The technique is
            this:

            # stick me in /etc/init.d as file named "webcache"
            #! /bin/bash
            #
            # webcache Start/Stop the Web Cache
            #
            # chkconfig: 2345 90 60
            # description: webcache is a tool designed to give web developers \
            # a hot settings file /mnt/webcache/settings.db where \
            # they can store application settings, caching stuff so \
            # that they do not need to hit the database.
            # processname: webcache
            # pidfile: /var/run/webcache.pid

            # Source function library.
            .. /etc/init.d/functions

            RETVAL=0

            prog="webcache"
            start() {
            echo -n $"Starting Web Cache: "
            mkdir /mnt/webcache 2>/dev/null
            mount -t tmpfs -o mode=770 tmpfs /mnt/webcache 2>/dev/null
            touch /mnt/webcache/settings.db 2>/dev/null
            echo "key=value" >> /mnt/webcache/settings.db 2>/dev/null
            touch /var/lock/subsys/webcache
            success
            echo
            }

            stop() {
            echo -n $"Stopping Web Cache: "
            umount /mnt/webcache 2>/dev/null
            rm -f /var/lock/subsys/webcache
            success
            echo
            }

            rhstatus() {
            if [ -f /var/lock/subsys/webcache ]; then
            echo "webcache started"
            else
            echo "webcache stopped"
            fi
            }

            restart() {
            stop
            start
            }

            reload() {
            echo -n $"Reloading Web Cache: "
            success
            echo
            }

            case "$1" in
            start)
            start
            ;;
            stop)
            stop
            ;;
            restart)
            restart
            ;;
            reload)
            reload
            ;;
            status)
            rhstatus
            ;;
            condrestart)
            [ -f /var/lock/subsys/webcache ] && restart || :
            ;;
            *)
            echo $"Usage: $0 {start|stop|sta tus|reload|rest art|condrestart }"
            exit 1
            esac

            exit $?
            # EOF

            ....Then, do this at command line (once you are root):

            /sbin/chkconfig --add webcache

            Now you can see "webcache" in Services Control Panel on RH8 or better
            Linux, and you can start and stop it, or set it to automatically start
            when the computer starts up. It also provides a default text file
            called /mnt/webcache/settings.db that you can read/write to from your
            PHP code.

            To improve this script even more, you can use Bash and have it read a
            settings from a file you can create called
            /etc/webcache/webcache.conf. This file can then have SQL statements in
            it that you can read, run, and then store the results in
            /mnt/webcache/settings.db as key=value pairs. And you can create a PHP
            class called Application that reads these pairs from any web page.

            Comment

            • Google Mike

              #7
              Re: Application Object Replacement

              I'd like to criticize my earlier submission about building a RAM cache
              using tmpfs on Linux, or even using a ramdisk file system. It's all
              interesting and everything, but I saw no significant speed improvement
              compared to just reading from a settings file. Linux simply does an
              outstanding job already with normal file I/O after multiple hits to
              the file. I now use a technique where my Application object class just
              reads from a settings file. To update that settings file of key=value
              pairs, I wrote a regen.php page that reads cache.conf (something I
              came up with) that tells it what SQL to read and cache in a file
              called cache. Every time someone administers these reference tables
              that are used in the cache, I make a call to regen.php to rebuild the
              cache. Okay, so what about the problem where someone reads from the
              cache the moment I'm rebuilding it? No problem. I drop a busyfile
              there to let me know, and the Application object class automatically
              knows to use the last backup of this cache file instead of the latest
              one, until the busyfile is no longer there.

              So, key points I learned:

              * In cases where this is suitable, do you want to cache stuff from the
              database so that your PHP web pages run faster? Fine, use a settings
              file and read from it with normal file I/O. It will run just as fast
              as a ramdisk or tmpfs filespace. If you use Linux, it will load very
              fast and multiple people can read the same file at the same time. You
              can then abstract the file I/O with your own Application object class.

              * Do you want to update this settings file? Fine, I use a technique
              where I copy the settings file into a backup settings file and drop a
              busy file. I then wait 5 seconds. This gives my Application object
              class plenty of time to recognize the existence of the busy file and
              start directing users to the backup settings file instead of the real
              one. I then regen the settings file based on reference tables from SQL
              that I want to cache. When finished, I delete the busy file so that
              the Application object class recognizes that it can start using the
              new settings file.

              * Do you want to webfarm your Application object? This is possible
              since it's file-based. You just mount NFS on each server and use a
              process to distribute it (while also using the backup/busy file
              process) so that the Application Object class can read the alternate
              settings file while your process updates the real one.

              Hope this speeds up your PHP apps!

              Comment

              • Google Mike

                #8
                Re: Application Object Replacement

                Turns out I was wrong even still. There is a faster way to implement
                application object like caching in PHP without the shm* API and
                without file i/o.

                Normal file i/o is fairly fast on Linux on a good system, but on a
                weaker system like an 800Mhz with IDE, it's not great at all when it
                gets hammered for looking up strings from a cache file. And for some
                reason, using a ramdisk is only slightly faster. I guess it comes down
                to the fact that PHP has slow file i/o API? I'm on 4.2.2, so perhaps
                that condition is only on that version of PHP.

                What does seem to work extremely fast, however, is to draw from a
                class object with hard-coded properties, and include this page with
                require() on the page that needs to draw from cache.

                Okay, so you might wonder, how the heck do the values get in the class
                object in the first place? The answer is that you regenerate this PHP
                class file from a script.

                So then this begs the questions:

                1. When do I regenerate this PHP class file?
                2. When it's being regenerated, how do users read from it without
                getting an error?

                Answers:

                1. A good time to regenerate this PHP class file is every time you
                update the items that you are trying to cache. Since caching is really
                only recommended for small reference tables that you draw from
                frequently but which do not change frequently, then every time you
                update the reference table, you can regenerate the PHP class file. I
                do this from my admin pages that I designed for these reference
                tables. If I leave the admin pages to return to the end user mode in
                the application, I trigger regeneration automatically.

                2. When the PHP class file is being regenerated, then of course this
                will be a problem. You'll need to come up with a way that a file named
                "busy" is detected and callers of this class file are automatically
                switched over to the last backup of the PHP class file.

                Comment

                • Google Mike

                  #9
                  Re: Application Object Replacement

                  "What does seem to work extremely fast, however, is to draw from a
                  class object with hard-coded properties, and include this page with
                  require() on the page that needs to draw from cache."

                  I'd like to comment that the class file technique works because I've
                  put it into a production environment with several concurrent users.

                  Here's the details:

                  * I have this set of admin pages. You can edit reference tables in the
                  database, but they do not update the cache files that the website
                  uses. However, when you exit the admin pages, the exit link tells the
                  website to regenerate cache. (Oh, I can hear you say, "What's a
                  reference table?" A reference table is one you store no more than say,
                  100 rows (although you may store more) which has primary keys that end
                  up being foreign keys in other, much larger tables in your database.
                  Typically a reference table is not one you change very often -- say,
                  once a week.)

                  * When I regenerate cache, I first make a backup of the existing cache
                  file. Then, I drop a busy file. I let that busy file sit out there a
                  few seconds before continuing. Users, upon hitting the website, will
                  hit code that sees that busy file and automatically direct users to
                  use the backup cache.

                  * Next, I begin to regenerate the cache by reading a cache.conf file
                  to identify the SQL queries I want to cache in a format of class
                  properties, generating a list like:

                  $this->Names_username _1="hpatel"
                  $this->Names_firstnam e_1="Hadresh"
                  $this->Names_lastname _1="Patel"
                  $this->Names_username _2="jsprite"
                  $this->Names_firstnam e_2="Jack"
                  $this->Names_lastname _2="Sprite"
                  $this->Names_rowcount ="2"

                  ....and then I tack on a class file header and footer (two fragments of
                  a complete class file) to combine everything into a real class file.
                  For even more coolness, this class file has methods in it (Translate
                  and Pull) that allow one to pull a value from the cache or translate
                  one row value with another (such as username with full name).

                  * Then, I remove the busy file and users (via my code) now start to
                  use the new cache. The first time they hit it, PHP compiles it.

                  * This makes for a superfast cache that seems to operate much faster
                  than me hitting the website constantly for these values. It also
                  allows me, for instance, to build a work order ticket that has foreign
                  keys, but I don't need SQL joins to translate the foreign keys -- I
                  can just pull them from cache.

                  * You see, SQL has to be parsed and translated, but a PHP class page,
                  once it gets compiled into bytecode the first time you hit the page,
                  provides an object that is much more responsive in a shorter amount of
                  time.

                  Comment

                  Working...